mirror of https://github.com/FreeCol/freecol.git
1183 lines
48 KiB
Java
1183 lines
48 KiB
Java
/**
|
|
* Copyright (C) 2002-2022 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.report;
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.event.ActionEvent;
|
|
import java.util.ArrayList;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Set;
|
|
import java.util.function.BinaryOperator;
|
|
import java.util.function.Function;
|
|
import java.util.function.Predicate;
|
|
import java.util.stream.Collectors;
|
|
|
|
import javax.swing.ImageIcon;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JComponent;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JSeparator;
|
|
import javax.swing.SwingConstants;
|
|
|
|
import net.miginfocom.swing.MigLayout;
|
|
import net.sf.freecol.client.FreeColClient;
|
|
import net.sf.freecol.client.gui.ImageLibrary;
|
|
import net.sf.freecol.client.gui.panel.Utility;
|
|
import net.sf.freecol.common.i18n.Messages;
|
|
import net.sf.freecol.common.model.Ability;
|
|
import net.sf.freecol.common.model.AbstractGoods;
|
|
import net.sf.freecol.common.model.BuildableType;
|
|
import net.sf.freecol.common.model.Building;
|
|
import net.sf.freecol.common.model.Colony;
|
|
import net.sf.freecol.common.model.Colony.TileImprovementSuggestion;
|
|
import static net.sf.freecol.common.model.Constants.*;
|
|
import net.sf.freecol.common.model.ExportData;
|
|
import net.sf.freecol.common.model.Game;
|
|
import net.sf.freecol.common.model.GoodsContainer;
|
|
import net.sf.freecol.common.model.GoodsType;
|
|
import net.sf.freecol.common.model.Market;
|
|
import net.sf.freecol.common.model.Player;
|
|
import net.sf.freecol.common.model.ProductionInfo;
|
|
import net.sf.freecol.common.model.Region;
|
|
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.TileImprovementType;
|
|
import net.sf.freecol.common.model.Unit;
|
|
import net.sf.freecol.common.model.UnitType;
|
|
import net.sf.freecol.common.model.WorkLocation;
|
|
import net.sf.freecol.common.model.WorkLocation.Suggestion;
|
|
import net.sf.freecol.common.resources.ResourceManager;
|
|
import static net.sf.freecol.common.util.CollectionUtils.*;
|
|
|
|
|
|
/**
|
|
* This panel displays the compact colony report.
|
|
*/
|
|
public final class ReportCompactColonyPanel extends ReportPanel {
|
|
|
|
/** Predicate to select units that are not working. */
|
|
private static final Predicate<Unit> notWorkingPred = u ->
|
|
u.getState() != Unit.UnitState.FORTIFIED && u.getState() != Unit.UnitState.SENTRY;
|
|
|
|
/** Container class for all the information about a colony. */
|
|
private static class ColonySummary {
|
|
|
|
/** Types of production for a given goods type. */
|
|
public enum ProductionStatus {
|
|
FAIL, // Negative production and below low alarm level
|
|
BAD, // Negative production
|
|
NONE, // No production at all
|
|
ZERO, // Production == consumption
|
|
GOOD, // Positive production
|
|
EXPORT, // Positive production and exporting
|
|
EXCESS, // Positive production and above high alarm level
|
|
OVERFLOW, // Positive production and above capacity
|
|
PRODUCTION, // Positive production but could produce more
|
|
CONSUMPTION, // Positive production but could consume more
|
|
};
|
|
|
|
|
|
/** Container class for goods production. */
|
|
public static class GoodsProduction {
|
|
|
|
/** Binary accumulation operator for goods production. */
|
|
public static final BinaryOperator<GoodsProduction>
|
|
goodsProductionAccumulator = (g1, g2) -> g1.accumulate(g2);
|
|
|
|
public int amount;
|
|
public ProductionStatus status;
|
|
public int extra;
|
|
|
|
/**
|
|
* Build a new goods production container.
|
|
*
|
|
* @param amount The amount of goods.
|
|
* @param status The production status.
|
|
* @param extra Extra production.
|
|
*/
|
|
public GoodsProduction(int amount, ProductionStatus status,
|
|
int extra) {
|
|
this.amount = amount;
|
|
this.status = status;
|
|
this.extra = extra;
|
|
}
|
|
|
|
/**
|
|
* Accumulate other production into this one.
|
|
*
|
|
* @param other The other {@code GoodsProduction}.
|
|
* @return This {@code GoodsProduction}.
|
|
*/
|
|
public GoodsProduction accumulate(GoodsProduction other) {
|
|
this.amount += other.amount;
|
|
this.status = (this.status == ProductionStatus.NONE
|
|
&& other.status == ProductionStatus.NONE)
|
|
? ProductionStatus.NONE
|
|
: (this.amount < 0) ? ProductionStatus.BAD
|
|
: (this.amount > 0) ? ProductionStatus.GOOD
|
|
: ProductionStatus.ZERO;
|
|
this.extra = 0;
|
|
return this;
|
|
}
|
|
};
|
|
|
|
|
|
/** The colony being summarized. */
|
|
public final Colony colony;
|
|
|
|
/** Possible tile improvements. */
|
|
public final List<TileImprovementSuggestion> tileSuggestions
|
|
= new ArrayList<>();
|
|
|
|
/** Famine warning required? */
|
|
public final boolean famine;
|
|
|
|
/**
|
|
* Turns to new colonist if positive, no colonist if zero,
|
|
* -turns-1 to starvation if negative.
|
|
*/
|
|
public final int newColonist;
|
|
|
|
/** Current production bonus. */
|
|
public final int bonus;
|
|
|
|
public final int unitCount;
|
|
|
|
public final int unitsToAdd;
|
|
|
|
public final int unitsToRemove;
|
|
|
|
/** Goods production. */
|
|
public final Map<GoodsType, GoodsProduction> production
|
|
= new HashMap<>();
|
|
|
|
/** Teacher units mapped to turns to complete. */
|
|
public final Map<Unit, Integer> teachers = new HashMap<>();
|
|
/** Units present that are not working. */
|
|
public final List<Unit> notWorking = new ArrayList<>();
|
|
/** Units present that might be working. */
|
|
public final List<UnitType> couldWork = new ArrayList<>();
|
|
/** Suggested better unit use. */
|
|
public final Map<UnitType, Suggestion> improve = new HashMap<>();
|
|
/** Suggested new unit use. */
|
|
public final Map<UnitType, Suggestion> want = new HashMap<>();
|
|
|
|
/** Currently building. */
|
|
public final BuildableType build;
|
|
public final int completeTurns;
|
|
public final AbstractGoods needed;
|
|
|
|
|
|
/**
|
|
* Create the colony summary.
|
|
*
|
|
* @param colony The {@code Colony} to summarize.
|
|
* @param goodsTypes A list of {@code GoodsType}s to include
|
|
* in the summary.
|
|
*/
|
|
public ColonySummary(Colony colony, List<GoodsType> goodsTypes) {
|
|
this.colony = colony;
|
|
|
|
final Specification spec = colony.getSpecification();
|
|
|
|
this.tileSuggestions.clear();
|
|
this.tileSuggestions.addAll(colony.getTileImprovementSuggestions());
|
|
|
|
int starve = colony.getStarvationTurns();
|
|
if (starve < 0) {
|
|
this.famine = false;
|
|
this.newColonist = colony.getNewColonistTurns();
|
|
} else {
|
|
this.famine = starve <= Colony.FAMINE_TURNS;
|
|
this.newColonist = -starve - 1;
|
|
}
|
|
|
|
this.bonus = colony.getProductionBonus();
|
|
|
|
this.unitCount = colony.getUnitCount();
|
|
this.unitsToAdd = colony.getUnitsToAdd();
|
|
this.unitsToRemove = colony.getUnitsToRemove();
|
|
|
|
for (GoodsType gt : goodsTypes) produce(gt);
|
|
|
|
this.notWorking.addAll(transform(colony.getTile().getUnits(),
|
|
notWorkingPred));
|
|
|
|
// Collect the types of the units at work in the colony
|
|
// (colony tiles and buildings) that are suboptimal (and
|
|
// are not just temporarily there because they are being
|
|
// taught), the types for sites that really need a new
|
|
// unit, the teachers, and the units that are not working.
|
|
//
|
|
// FIXME: this needs to be merged with the requirements
|
|
// checking code, but that in turn should be opened up
|
|
// so the AI can use it...
|
|
for (WorkLocation wl :transform(colony.getAvailableWorkLocations(),
|
|
WorkLocation::canBeWorked)) {
|
|
if (wl.canTeach()) {
|
|
for (Unit u : wl.getUnitList()) {
|
|
teachers.put(u, u.getNeededTurnsOfTraining()
|
|
- u.getTurnsOfTraining());
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Check if the units are working.
|
|
this.notWorking.addAll(transform(wl.getUnits(),
|
|
u -> (u.getTeacher() == null
|
|
&& u.getWorkType() == null)));
|
|
|
|
// Add work location suggestions.
|
|
forEachMapEntry(wl.getSuggestions(),
|
|
e -> addSuggestion(((e.getKey() == null) ? this.want
|
|
: this.improve),
|
|
spec.getExpertForProducing(e.getValue().goodsType),
|
|
e.getValue()));
|
|
}
|
|
|
|
// Make a list of unit types that are not working at their
|
|
// speciality, including the units just standing around.
|
|
final Predicate<Unit> couldWorkPred = u -> {
|
|
WorkLocation wl = u.getWorkLocation();
|
|
return wl != null && (wl.getWorkFor(u) == null
|
|
|| wl.getWorkFor(u) != u.getWorkType());
|
|
};
|
|
this.couldWork.addAll(transform(this.notWorking, couldWorkPred,
|
|
Unit::getType));
|
|
|
|
this.build = colony.getCurrentlyBuilding();
|
|
if (this.build == null) {
|
|
this.completeTurns = -1;
|
|
this.needed = null;
|
|
} else {
|
|
AbstractGoods needed = new AbstractGoods();
|
|
this.completeTurns = colony.getTurnsToComplete(build, needed);
|
|
this.needed = (this.completeTurns < 0) ? needed : null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the production map values for the given goods type.
|
|
*
|
|
* @param goodsType The {@code GoodsType} to use.
|
|
*/
|
|
private void produce(GoodsType goodsType) {
|
|
final ExportData exportData = colony.getExportData(goodsType);
|
|
final int adjustment = colony.getWarehouseCapacity()
|
|
/ GoodsContainer.CARGO_SIZE;
|
|
final int low = exportData.getLowLevel() * adjustment;
|
|
final int high = exportData.getHighLevel() * adjustment;
|
|
final int amount = colony.getGoodsCount(goodsType);
|
|
int p = colony.getAdjustedNetProductionOf(goodsType);
|
|
|
|
ProductionStatus status;
|
|
AbstractGoods deficit;
|
|
int extra = 0;
|
|
if (p < 0) {
|
|
status = (amount < low) ? ProductionStatus.FAIL
|
|
: ProductionStatus.BAD;
|
|
extra = -amount / p + 1;
|
|
} else if (p == 0 && !colony.isProducing(goodsType)) {
|
|
status = (colony.isConsuming(goodsType)) ? ProductionStatus.FAIL
|
|
: ProductionStatus.NONE;
|
|
} else if (p == 0) {
|
|
status = ProductionStatus.ZERO;
|
|
extra = 0;
|
|
deficit = null;
|
|
for (WorkLocation wl : colony.getWorkLocationsForProducing(goodsType)) {
|
|
ProductionInfo pi = colony.getProductionInfo(wl);
|
|
if (pi == null) continue;
|
|
deficit = find(pi.getConsumptionDeficit(),
|
|
AbstractGoods.matches(goodsType));
|
|
if (deficit != null) {
|
|
status = ProductionStatus.CONSUMPTION;
|
|
extra = deficit.getAmount();
|
|
break;
|
|
}
|
|
}
|
|
} else if (exportData.getExported()) {
|
|
status = ProductionStatus.EXPORT;
|
|
extra = exportData.getExportLevel();
|
|
} else if (goodsType.limitIgnored()) {
|
|
status = ProductionStatus.GOOD;
|
|
} else if (amount + p > colony.getWarehouseCapacity()) {
|
|
status = ProductionStatus.OVERFLOW;
|
|
extra = amount + p - colony.getWarehouseCapacity();
|
|
} else if (amount >= high) {
|
|
status = ProductionStatus.EXCESS;
|
|
extra = (colony.getWarehouseCapacity() - amount) / p;
|
|
} else {
|
|
status = ProductionStatus.GOOD;
|
|
extra = 0;
|
|
deficit = null;
|
|
for (WorkLocation wl : colony.getWorkLocationsForProducing(goodsType)) {
|
|
ProductionInfo pi = colony.getProductionInfo(wl);
|
|
if (pi == null) continue;
|
|
deficit = find(pi.getProductionDeficit(),
|
|
AbstractGoods.matches(goodsType));
|
|
if (deficit != null) {
|
|
status = ProductionStatus.PRODUCTION;
|
|
extra = deficit.getAmount();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.production.put(goodsType,
|
|
new GoodsProduction(p, status, extra));
|
|
}
|
|
|
|
private void addSuggestion(Map<UnitType, Suggestion> suggestions,
|
|
UnitType expert, Suggestion suggestion) {
|
|
if (suggestion == null || expert == null) return;
|
|
Suggestion now = suggestions.get(expert);
|
|
if (now == null || now.amount < suggestion.amount) {
|
|
suggestions.put(expert, suggestion);
|
|
}
|
|
}
|
|
};
|
|
|
|
/** Predicate to select the goods to report on. */
|
|
private static final Predicate<GoodsType> reportGoodsPred = gt ->
|
|
(gt.isStorable() && !gt.isTradeGoods()) || gt.isLibertyType();
|
|
private static final String BUILDQUEUE = "buildQueue.";
|
|
private static final String cAlarmKey = "color.report.colony.alarm";
|
|
private static final String cWarnKey = "color.report.colony.warning";
|
|
private static final String cPlainKey = "color.report.colony.plain";
|
|
private static final String cExportKey = "color.report.colony.export";
|
|
private static final String cGoodKey = "color.report.colony.good";
|
|
private static Color cAlarm = null;
|
|
private static Color cWarn;
|
|
private static Color cPlain;
|
|
private static Color cExport;
|
|
private static Color cGood;
|
|
|
|
private final Specification spec;
|
|
private final ImageLibrary lib;
|
|
private final List<List<Colony>> colonies = new ArrayList<>();
|
|
private final Market market;
|
|
private final List<GoodsType> goodsTypes = new ArrayList<>();
|
|
|
|
|
|
/**
|
|
* Creates a compact colony report.
|
|
*
|
|
* @param freeColClient The {@code FreeColClient} for the game.
|
|
*/
|
|
public ReportCompactColonyPanel(FreeColClient freeColClient) {
|
|
super(freeColClient, "reportColonyAction");
|
|
|
|
this.spec = getSpecification();
|
|
this.lib = getImageLibrary();
|
|
final Player player = getMyPlayer();
|
|
this.market = player.getMarket();
|
|
|
|
// Sort the colonies by continent.
|
|
final Map<Integer, List<Colony>> continents = new HashMap<>();
|
|
for (Colony c : player.getColonyList()) {
|
|
if (c.getUnitCount() > 0) {
|
|
// Do not include colonies that have been abandoned
|
|
// but are still on the colonies list.
|
|
appendToMapList(continents, c.getTile().getContiguity(), c);
|
|
}
|
|
}
|
|
final Comparator<Colony> colonyComparator
|
|
= freeColClient.getClientOptions().getColonyComparator();
|
|
final Comparator<List<Colony>> firstColonyComparator
|
|
= Comparator.comparing(l -> first(l), colonyComparator);
|
|
this.colonies.addAll(sort(continents.values(), firstColonyComparator));
|
|
|
|
this.goodsTypes.addAll(transform(spec.getGoodsTypeList(),
|
|
reportGoodsPred,
|
|
Function.<GoodsType>identity(),
|
|
GoodsType.goodsTypeComparator));
|
|
|
|
loadResources();
|
|
update();
|
|
}
|
|
|
|
|
|
private synchronized void loadResources() {
|
|
if (cAlarm != null) return;
|
|
|
|
cAlarm = ImageLibrary.getColor(cAlarmKey, Color.RED);
|
|
cWarn = ImageLibrary.getColor(cWarnKey, Color.MAGENTA);
|
|
cPlain = ImageLibrary.getColor(cPlainKey, Color.DARK_GRAY);
|
|
cExport = ImageLibrary.getColor(cExportKey, Color.GREEN);
|
|
cGood = ImageLibrary.getColor(cGoodKey, Color.BLUE);
|
|
}
|
|
|
|
private static StringTemplate stpl(String messageId) {
|
|
return (Messages.containsKey(messageId))
|
|
? StringTemplate.template(messageId)
|
|
: null;
|
|
}
|
|
|
|
private static StringTemplate stpld(String messageId) {
|
|
messageId = Messages.descriptionKey(messageId);
|
|
return stpl(messageId);
|
|
}
|
|
|
|
private JLabel newLabel(String h, ImageIcon i, Color c) {
|
|
JLabel l = new JLabel(h, i, SwingConstants.CENTER);
|
|
l.setForeground((c == null) ? Color.BLACK : c);
|
|
return l;
|
|
}
|
|
|
|
private JLabel newLabel(String h, ImageIcon i, Color c, StringTemplate t) {
|
|
if (h != null && Messages.containsKey(h)) h = Messages.message(h);
|
|
JLabel l = newLabel(h, i, c);
|
|
if (t != null) Utility.localizeToolTip(l, t);
|
|
return l;
|
|
}
|
|
|
|
private JButton newButton(String action, String h, ImageIcon i,
|
|
Color c, StringTemplate t) {
|
|
if (h != null && Messages.containsKey(h)) h = Messages.message(h);
|
|
JButton b = Utility.getLinkButton(h, i, action);
|
|
b.setForeground((c == null) ? Color.BLACK : c);
|
|
if (t != null) Utility.localizeToolTip(b, t);
|
|
b.addActionListener(this);
|
|
return b;
|
|
}
|
|
|
|
private void addTogether(List<? extends JComponent> components) {
|
|
if (components.isEmpty()) {
|
|
reportPanel.add(new JLabel());
|
|
return;
|
|
}
|
|
String layout = (components.size() > 1) ? "split " + components.size()
|
|
: null;
|
|
for (JComponent jc : components) {
|
|
reportPanel.add(jc, layout);
|
|
layout = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update a single colony.
|
|
*
|
|
* @param s The {@code ColonySummary} to update from.
|
|
*/
|
|
private void updateColony(ColonySummary s) {
|
|
final String cac = s.colony.getId();
|
|
final UnitType defaultUnitType
|
|
= spec.getDefaultUnitType(s.colony.getOwner());
|
|
List<JComponent> buttons = new ArrayList<>(16);
|
|
JButton b;
|
|
Color c;
|
|
StringTemplate t;
|
|
Building building;
|
|
|
|
// Field: A button for the colony.
|
|
// Colour: bonus in {-2,2} => {alarm, warn, plain, export, good}
|
|
// Font: Bold if famine is threatening.
|
|
c = (s.bonus <= -2) ? cAlarm
|
|
: (s.bonus == -1) ? cWarn
|
|
: (s.bonus == 0) ? cPlain
|
|
: (s.bonus == 1) ? cExport
|
|
: cGood;
|
|
String annotations = "", key;
|
|
t = StringTemplate.label(",");
|
|
if ((building = s.colony.getStockade()) == null) {
|
|
key = "annotation.unfortified";
|
|
t.add(Messages.message("report.colony.annotation.unfortified"));
|
|
} else {
|
|
key = "annotation." + building.getType().getSuffix();
|
|
t.add(Messages.message(building.getLabel()));
|
|
}
|
|
if (ResourceManager.getStringResource(key, false) != null) {
|
|
annotations += ResourceManager.getString(key);
|
|
}
|
|
if (!s.colony.getTile().isCoastland()) {
|
|
key = "annotation.inland";
|
|
t.add(Messages.message("report.colony.annotation.inland"));
|
|
} else if ((building = s.colony.getWorkLocationWithAbility(Ability.PRODUCE_IN_WATER, Building.class)) == null) {
|
|
key = "annotation.coastal";
|
|
t.add(Messages.message("report.colony.annotation.coastal"));
|
|
} else {
|
|
key = "annotation." + building.getType().getSuffix();
|
|
t.add(Messages.message(building.getLabel()));
|
|
}
|
|
if (ResourceManager.getStringResource(key, false) != null) {
|
|
annotations += ResourceManager.getString(key);
|
|
}
|
|
/* Omit for now, too much detail.
|
|
for (GoodsType gt : spec.getLibertyGoodsTypeList()) {
|
|
if ((building = s.colony.getWorkLocationWithModifier(gt.getId(), Building.class)) != null) {
|
|
key = "annotation." + building.getType().getSuffix();
|
|
t.add(Messages.message(building.getLabel()));
|
|
if (ResourceManager.hasResource(key))
|
|
annotations += ResourceManager.getString(key);
|
|
}
|
|
}*/
|
|
/* Omit for now, too much detail.
|
|
for (GoodsType gt : spec.getImmigrationGoodsTypeList()) {
|
|
if ((building = s.colony.getWorkLocationWithModifier(gt.getId(), Building.class)) != null) {
|
|
key = "annotation." + building.getType().getSuffix();
|
|
t.add(Messages.message(building.getLabel()));
|
|
if (ResourceManager.hasResource(key))
|
|
annotations += ResourceManager.getString(key);
|
|
}
|
|
}*/
|
|
/* Font update needed
|
|
if ((building = s.colony.getWorkLocationWithAbility(Ability.TEACH, Building.class)) != null) {
|
|
key = "annotation." + building.getType().getSuffix();
|
|
t.add(Messages.message(building.getLabel()));
|
|
if (ResourceManager.hasResource(key)) annotations += ResourceManager.getString(key);
|
|
}*/
|
|
if ((building = s.colony.getWorkLocationWithAbility(Ability.EXPORT, Building.class)) != null) {
|
|
annotations += "*";
|
|
t.add(Messages.message(building.getLabel()));
|
|
}
|
|
b = newButton(cac, s.colony.getName() + annotations, null, c,
|
|
StringTemplate.label(": ").add(s.colony.getName())
|
|
.add(Messages.message(t)));
|
|
if (s.famine) b.setFont(b.getFont().deriveFont(Font.BOLD));
|
|
reportPanel.add(b, "newline");
|
|
|
|
// Field: Size
|
|
c = cGood;
|
|
t = stpld("report.colony.size");
|
|
reportPanel.add(newButton(cac, Integer.toString(s.unitCount), null, c, t));
|
|
|
|
// Field: The number of colonists that can be added to a
|
|
// colony without damaging the production bonus
|
|
if (s.unitsToAdd > 0) {
|
|
c = cGood;
|
|
t = stpld("report.colony.growing")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%amount%", s.unitsToAdd);
|
|
b = newButton(cac, Integer.toString(s.unitsToAdd), null, c, t);
|
|
} else {
|
|
b = null;
|
|
}
|
|
reportPanel.add((b == null) ? new JLabel() : b);
|
|
|
|
// Field: the number of colonists to remove to fix the inefficiency.
|
|
// Colour: Blue if efficient/Red if inefficient.
|
|
if (s.unitsToRemove > 0) {
|
|
c = s.bonus < 0 ? cAlarm : cGood;
|
|
t = stpld("report.colony.shrinking")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%amount%", s.unitsToRemove);
|
|
b = newButton(cac, Integer.toString(s.unitsToRemove), null, c, t);
|
|
} else {
|
|
b = null;
|
|
}
|
|
reportPanel.add((b == null) ? new JLabel() : b);
|
|
|
|
// Field: The number of potential colony tiles that need
|
|
// exploring.
|
|
// Colour: Always cAlarm
|
|
int n = count(s.tileSuggestions,
|
|
TileImprovementSuggestion::isExploration);
|
|
if (n > 0) {
|
|
t = stpld("report.colony.exploring")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%amount%", n);
|
|
b = newButton(cac, Integer.toString(n), null, cAlarm, t);
|
|
} else {
|
|
b = null;
|
|
}
|
|
reportPanel.add((b == null) ? new JLabel() : b);
|
|
|
|
// Fields: The number of existing colony tiles that would
|
|
// benefit from improvements.
|
|
// Colour: Always cAlarm
|
|
// Font: Bold if one of the tiles is the colony center.
|
|
for (TileImprovementType ti : spec.getTileImprovementTypeList()) {
|
|
if (ti.isNatural()) continue;
|
|
n = 0;
|
|
boolean center = false;
|
|
for (TileImprovementSuggestion tis : s.tileSuggestions) {
|
|
if (tis.tileImprovementType == ti) {
|
|
n++;
|
|
if (tis.tile == s.colony.getTile()) center = true;
|
|
}
|
|
}
|
|
if (n > 0) {
|
|
c = cAlarm;
|
|
if (n == 1) {
|
|
TileImprovementSuggestion tis = first(s.tileSuggestions);
|
|
if (any(tis.tile.getUnits(),
|
|
u -> (u.getState() == Unit.UnitState.IMPROVING
|
|
&& u.getWorkImprovement() != null
|
|
&& u.getWorkImprovement().getType()
|
|
== tis.tileImprovementType))) {
|
|
c = cWarn; // Work is underway
|
|
}
|
|
t = stpld("report.colony.tile." + ti.getSuffix()
|
|
+ ".specific")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addStringTemplate("%location%",
|
|
tis.tile.getColonyTileLocationLabel(s.colony));
|
|
} else {
|
|
t = stpld("report.colony.tile." + ti.getSuffix())
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%amount%", n);
|
|
}
|
|
b = newButton(cac, Integer.toString(n), null, c, t);
|
|
if (center) b.setFont(b.getFont().deriveFont(Font.BOLD));
|
|
} else {
|
|
b = null;
|
|
}
|
|
reportPanel.add((b == null) ? new JLabel() : b);
|
|
}
|
|
|
|
// Fields: The net production of each storable+non-trade-goods
|
|
// goods type.
|
|
// Colour: cAlarm if too low, cWarn if negative, empty if no
|
|
// production, cPlain if production balanced at zero,
|
|
// otherwise must be positive, wherein cExport
|
|
// if exported, cAlarm if too high, else cGood.
|
|
for (GoodsType gt : this.goodsTypes) {
|
|
final ColonySummary.GoodsProduction gp = s.production.get(gt);
|
|
switch (gp.status) {
|
|
case FAIL:
|
|
c = cAlarm;
|
|
t = stpld("report.colony.production.low")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", -gp.amount)
|
|
.addAmount("%turns%", gp.extra);
|
|
break;
|
|
case BAD:
|
|
c = cWarn;
|
|
t = stpld("report.colony.production")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount);
|
|
break;
|
|
case NONE:
|
|
c = null;
|
|
t = null;
|
|
break;
|
|
case ZERO:
|
|
c = cPlain;
|
|
t = stpld("report.colony.production")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount);
|
|
break;
|
|
case GOOD:
|
|
c = cGood;
|
|
t = stpld("report.colony.production")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount);
|
|
break;
|
|
case EXPORT:
|
|
c = cExport;
|
|
t = stpld("report.colony.production.export")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount)
|
|
.addAmount("%export%", gp.extra);
|
|
break;
|
|
case EXCESS:
|
|
c = cWarn;
|
|
t = stpld("report.colony.production.high")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount)
|
|
.addAmount("%turns%", gp.extra);
|
|
break;
|
|
case OVERFLOW:
|
|
c = cAlarm;
|
|
t = stpld("report.colony.production.waste")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount)
|
|
.addAmount("%waste%", gp.extra);
|
|
break;
|
|
case PRODUCTION:
|
|
c = cWarn;
|
|
t = stpld("report.colony.production.maxProduction")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount)
|
|
.addAmount("%more%", gp.extra);
|
|
break;
|
|
case CONSUMPTION:
|
|
c = cWarn;
|
|
t = stpld("report.colony.production.maxConsumption")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%goods%", gt)
|
|
.addAmount("%amount%", gp.amount)
|
|
.addAmount("%more%", gp.extra);
|
|
break;
|
|
default:
|
|
throw new IllegalStateException("Bogus status: " + gp.status);
|
|
}
|
|
reportPanel.add((c == null) ? new JLabel()
|
|
: newButton(cac, Integer.toString(gp.amount), null, c, t));
|
|
}
|
|
|
|
// Field: New colonist arrival or famine warning.
|
|
// Colour: cGood if arriving eventually, blank if not enough food
|
|
// to grow, cWarn if negative, cAlarm if famine soon.
|
|
if (s.newColonist > 0) {
|
|
t = stpld("report.colony.arriving")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%unit%", defaultUnitType)
|
|
.addAmount("%turns%", s.newColonist);
|
|
b = newButton(cac, Integer.toString(s.newColonist), null,
|
|
cGood, t);
|
|
} else if (s.newColonist < 0) {
|
|
c = (s.famine) ? cAlarm : cWarn;
|
|
t = stpld("report.colony.starving")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%turns%", -s.newColonist);
|
|
b = newButton(cac, Integer.toString(-s.newColonist), null,
|
|
c, t);
|
|
if (s.famine) b.setFont(b.getFont().deriveFont(Font.BOLD));
|
|
} else {
|
|
b = null;
|
|
}
|
|
reportPanel.add((b == null) ? new JLabel() : b);
|
|
|
|
// Field: What is currently being built (clickable if on the
|
|
// buildqueue) and the turns until it completes, including
|
|
// units being taught, or blank if nothing queued.
|
|
// Colour: cWarn if no construction is occurring, cGood with
|
|
// turns if completing, cAlarm with turns if will block, turns
|
|
// indicates when blocking occurs.
|
|
// Font: Bold if blocked right now.
|
|
final String qac = BUILDQUEUE + cac;
|
|
if (s.build != null) {
|
|
int turns = s.completeTurns;
|
|
String bname = Messages.getName(s.build);
|
|
if (turns == UNDEFINED) {
|
|
t = stpld("report.colony.making.noconstruction")
|
|
.addName("%colony%", s.colony.getName());
|
|
b = newButton(qac, bname, null, cWarn, t);
|
|
} else if (turns >= 0) {
|
|
t = stpld("report.colony.making.constructing")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addNamed("%buildable%", s.build)
|
|
.addAmount("%turns%", turns);
|
|
b = newButton(qac, bname + " " + Integer.toString(turns), null,
|
|
cGood, t);
|
|
} else { // turns < 0
|
|
turns = -(turns + 1);
|
|
t = stpld("report.colony.making.blocking")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%amount%", s.needed.getAmount())
|
|
.addNamed("%goods%", s.needed.getType())
|
|
.addNamed("%buildable%", s.build)
|
|
.addAmount("%turns%", turns);
|
|
b = newButton(qac, bname + " " + Integer.toString(turns),
|
|
null, cAlarm, t);
|
|
if (turns == 0) b.setFont(b.getFont().deriveFont(Font.BOLD));
|
|
}
|
|
buttons.add(b);
|
|
}
|
|
|
|
// Field: What is being trained, including shadow units for vacant
|
|
// places.
|
|
// Colour: cAlarm if completion is blocked, otherwise cPlain.
|
|
int empty = 0;
|
|
Building school = s.colony.getWorkLocationWithAbility(Ability.TEACH,
|
|
Building.class);
|
|
if (school != null) empty = school.getType().getWorkPlaces();
|
|
for (Entry<Unit, Integer> e
|
|
: mapEntriesByValue(s.teachers, descendingIntegerComparator)) {
|
|
Unit u = e.getKey();
|
|
ImageIcon ii = new ImageIcon(this.lib.getTinyUnitImage(u));
|
|
if (e.getValue() <= 0) {
|
|
t = stpld("report.colony.making.noteach")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addStringTemplate("%teacher%",
|
|
u.getLabel(Unit.UnitLabelType.NATIONAL));
|
|
b = newButton(cac, Integer.toString(0), ii, cAlarm, t);
|
|
} else {
|
|
t = stpld("report.colony.making.educating")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addStringTemplate("%teacher%",
|
|
u.getLabel(Unit.UnitLabelType.NATIONAL))
|
|
.addAmount("%turns%", e.getValue());
|
|
b = newButton(cac, Integer.toString(e.getValue()), ii,
|
|
cPlain, t);
|
|
}
|
|
buttons.add(b);
|
|
empty--;
|
|
}
|
|
|
|
if (empty > 0) {
|
|
final ImageIcon emptyIcon
|
|
= new ImageIcon(this.lib.getTinyUnitTypeImage(defaultUnitType, true));
|
|
t = stpld("report.colony.making.educationVacancy")
|
|
.addName("%colony%", s.colony.getName())
|
|
.addAmount("%number%", empty);
|
|
for (; empty > 0; empty--) {
|
|
buttons.add(newButton(cac, "", emptyIcon, cPlain, t));
|
|
}
|
|
}
|
|
addTogether(buttons);
|
|
|
|
// Field: The units that could be upgraded, followed by the units
|
|
// that could be added.
|
|
if (s.improve.isEmpty() && s.want.isEmpty()) {
|
|
reportPanel.add(new JLabel());
|
|
} else {
|
|
buttons.clear();
|
|
buttons.addAll(unitButtons(s.improve, s.couldWork, s.colony));
|
|
buttons.add(new JLabel("/"));
|
|
// Prefer to suggest an improvement over and addition.
|
|
for (UnitType ut : s.improve.keySet()) s.want.remove(ut);
|
|
buttons.addAll(unitButtons(s.want, s.couldWork, s.colony));
|
|
addTogether(buttons);
|
|
}
|
|
|
|
// TODO: notWorking?
|
|
}
|
|
|
|
private List<JButton> unitButtons(final Map<UnitType, Suggestion> suggestions,
|
|
List<UnitType> have, Colony colony) {
|
|
final String cac = colony.getId();
|
|
List<JButton> result = new ArrayList<>(suggestions.size());
|
|
final Comparator<UnitType> buttonComparator
|
|
= Comparator.comparing(ut -> suggestions.get(ut),
|
|
Suggestion.descendingAmountComparator);
|
|
for (UnitType type : sort(suggestions.keySet(), buttonComparator)) {
|
|
boolean present = have.contains(type);
|
|
Suggestion suggestion = suggestions.get(type);
|
|
String label = Integer.toString(suggestion.amount);
|
|
ImageIcon icon
|
|
= new ImageIcon(this.lib.getTinyUnitTypeImage(type, false));
|
|
StringTemplate tip = (suggestion.oldType == null)
|
|
? stpld("report.colony.wanting")
|
|
.addName("%colony%", colony.getName())
|
|
.addNamed("%unit%", type)
|
|
.addStringTemplate("%location%",
|
|
suggestion.workLocation.getLabel())
|
|
.addNamed("%goods%", suggestion.goodsType)
|
|
.addAmount("%amount%", suggestion.amount)
|
|
: stpld("report.colony.improving")
|
|
.addName("%colony%", colony.getName())
|
|
.addNamed("%oldUnit%", suggestion.oldType)
|
|
.addNamed("%unit%", type)
|
|
.addStringTemplate("%location%",
|
|
suggestion.workLocation.getLabel())
|
|
.addNamed("%goods%", suggestion.goodsType)
|
|
.addAmount("%amount%", suggestion.amount);
|
|
JButton b = newButton(cac, label, icon,
|
|
(present) ? cGood : cPlain, tip);
|
|
if (present) b.setFont(b.getFont().deriveFont(Font.BOLD));
|
|
result.add(b);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Update several colonies.
|
|
*
|
|
* @param summaries A list of {@code ColonySummary}s to update from.
|
|
*/
|
|
private void updateCombinedColonies(List<ColonySummary> summaries) {
|
|
JLabel l;
|
|
Color c;
|
|
StringTemplate t;
|
|
|
|
reportPanel.add(new JSeparator(JSeparator.HORIZONTAL),
|
|
"newline, span, growx");
|
|
|
|
// Accumulate all the summaries
|
|
Map<Region, Integer> rRegionMap = new HashMap<>();
|
|
List<TileImprovementSuggestion> rTileSuggestions = new ArrayList<>();
|
|
int rUnitCount = 0, rUnitsToAdd = 0, rUnitsToRemove = 0,
|
|
teacherLen = 0, improveLen = 0;
|
|
double rNewColonist = 0.0;
|
|
Map<GoodsType, ColonySummary.GoodsProduction> rProduction
|
|
= new HashMap<>();
|
|
Map<UnitType, Integer> rTeachers = new HashMap<>();
|
|
//List<Unit> rNotWorking = new ArrayList<>();
|
|
//List<UnitType> rCouldWork = new ArrayList<>();
|
|
Map<UnitType, Integer> rImprove = new HashMap<>();
|
|
Map<GoodsType, Double> rNeeded = new HashMap<>();
|
|
for (ColonySummary s : summaries) {
|
|
accumulateToMap(rRegionMap, s.colony.getTile().getRegion(), 1,
|
|
integerAccumulator);
|
|
rTileSuggestions.addAll(s.tileSuggestions);
|
|
if (s.newColonist > 0) rNewColonist += s.newColonist;
|
|
rUnitCount += s.unitCount;
|
|
rUnitsToAdd += s.unitsToAdd;
|
|
if (s.bonus < 0) {
|
|
rUnitsToRemove += s.unitsToRemove;
|
|
}
|
|
accumulateMap(rProduction, s.production,
|
|
ColonySummary.GoodsProduction.goodsProductionAccumulator);
|
|
teacherLen = Math.max(teacherLen, s.teachers.size());
|
|
for (Unit u : s.teachers.keySet()) {
|
|
accumulateToMap(rTeachers, u.getType(), 1, integerAccumulator);
|
|
}
|
|
//rNotWorking.addAll(s.notWorking);
|
|
//rCouldWork.addAll(s.couldWork);
|
|
improveLen = Math.max(improveLen, s.improve.size() + s.want.size());
|
|
for (UnitType ut : s.improve.keySet()) {
|
|
accumulateToMap(rImprove, ut, 1, integerAccumulator);
|
|
}
|
|
for (UnitType ut : s.want.keySet()) {
|
|
accumulateToMap(rImprove, ut, 1, integerAccumulator);
|
|
}
|
|
if (s.needed != null && s.needed.getType().isStorable()) {
|
|
accumulateToMap(rNeeded, s.needed.getType(),
|
|
(double)s.needed.getAmount() / s.completeTurns,
|
|
doubleAccumulator);
|
|
}
|
|
}
|
|
rNewColonist = Math.round(rNewColonist / summaries.size());
|
|
|
|
// Field: A label for the most settled region in the list.
|
|
// Colour: Plain
|
|
t = mapEntriesByValue(rRegionMap, descendingIntegerComparator)
|
|
.get(0).getKey().getLabel();
|
|
reportPanel.add(newLabel(Messages.message(t), null, cPlain,
|
|
stpld("report.colony.name.summary")),
|
|
"newline");
|
|
|
|
// Field: The total units.
|
|
reportPanel.add(newLabel(Integer.toString(rUnitCount), null, cGood, stpld("report.colony.size.summary")));
|
|
|
|
// Field: The total units to add.
|
|
reportPanel.add(newLabel(Integer.toString(rUnitsToAdd), null, cGood, stpld("report.colony.growing.summary")));
|
|
|
|
// Field: The total units to remove.
|
|
// Colour: cGood if efficient/cAlarm if inefficient.
|
|
reportPanel.add(newLabel(Integer.toString(rUnitsToRemove), null,
|
|
(rUnitsToRemove > 0) ? cAlarm : cGood,
|
|
stpld("report.colony.shrinking.summary")));
|
|
|
|
// Field: The number of potential colony tiles that need
|
|
// exploring.
|
|
// Colour: cAlarm
|
|
Set<Tile> tiles = transform(rTileSuggestions,
|
|
TileImprovementSuggestion::isExploration,
|
|
ts -> ts.tile, Collectors.toSet());
|
|
reportPanel.add((tiles.isEmpty()) ? new JLabel()
|
|
: newLabel(Integer.toString(tiles.size()), null, cAlarm,
|
|
stpld("report.colony.exploring.summary")));
|
|
|
|
// Fields: The number of existing colony tiles that would
|
|
// benefit from improvements.
|
|
// Colour: cAlarm
|
|
for (TileImprovementType ti : spec.getTileImprovementTypeList()) {
|
|
if (ti.isNatural()) continue;
|
|
tiles.clear();
|
|
tiles.addAll(transform(rTileSuggestions,
|
|
matchKey(ti, ts -> ts.tileImprovementType),
|
|
ts -> ts.tile, Collectors.toSet()));
|
|
reportPanel.add((tiles.isEmpty()) ? new JLabel()
|
|
: newLabel(Integer.toString(tiles.size()), null, cAlarm,
|
|
stpld("report.colony.tile." + ti.getSuffix()
|
|
+ ".summary")));
|
|
}
|
|
|
|
// Fields: The net production of each storable+non-trade-goods
|
|
// goods type.
|
|
// Colour: cWarn if negative, empty if no production,
|
|
// cPlain if production balanced at zero, otherwise cGood.
|
|
for (GoodsType gt : this.goodsTypes) {
|
|
final ColonySummary.GoodsProduction gp = rProduction.get(gt);
|
|
switch (gp.status) {
|
|
case BAD:
|
|
c = cWarn;
|
|
break;
|
|
case NONE:
|
|
c = null;
|
|
break;
|
|
case ZERO:
|
|
c = cPlain;
|
|
break;
|
|
case GOOD:
|
|
c = cGood;
|
|
break;
|
|
default:
|
|
throw new IllegalStateException("Bogus status: " + gp.status);
|
|
}
|
|
reportPanel.add((c == null) ? new JLabel()
|
|
: newLabel(Integer.toString(gp.amount), null, c,
|
|
stpld("report.colony.production.summary")
|
|
.addNamed("%goods%", gt)));
|
|
}
|
|
|
|
// Field: New colonist arrival or famine warning.
|
|
// Colour: cWarn if negative, else cGood
|
|
reportPanel.add(newLabel(Integer.toString((int)rNewColonist), null,
|
|
(rNewColonist < 0) ? cWarn : cGood,
|
|
stpld("report.colony.arriving.summary")));
|
|
|
|
// Field: The required goods rates.
|
|
// Colour: cPlain
|
|
List<JLabel> labels = transform(mapEntriesByValue(rNeeded, descendingDoubleComparator),
|
|
alwaysTrue(),
|
|
e -> newLabel(String.format("%4.1f %s", e.getValue(),
|
|
Messages.getName(e.getKey())),
|
|
null, cPlain,
|
|
stpld("report.colony.making.summary")
|
|
.addNamed("%goods%", e.getKey())));
|
|
|
|
// Field: What is being trained (attached to previous)
|
|
// Colour: cPlain.
|
|
teacherLen = Math.max(3, teacherLen); // Always some room here
|
|
labels.addAll(unitTypeLabels(rTeachers, teacherLen,
|
|
stpld("report.colony.making.educating.summary")));
|
|
addTogether(labels);
|
|
|
|
// Field: The units that could be upgraded, followed by the units
|
|
// that could be added.
|
|
addTogether(unitTypeLabels(rImprove, improveLen,
|
|
stpld("report.colony.improving.summary")));
|
|
}
|
|
|
|
private List<JLabel> unitTypeLabels(Map<UnitType, Integer> unitTypeMap,
|
|
int maxSize, StringTemplate t) {
|
|
List<JLabel> result = new ArrayList<>(maxSize);
|
|
int n = 0;
|
|
for (Entry<UnitType, Integer> e
|
|
: mapEntriesByValue(unitTypeMap, descendingIntegerComparator)) {
|
|
ImageIcon icon
|
|
= new ImageIcon(this.lib.getTinyUnitTypeImage(e.getKey(), false));
|
|
result.add(newLabel(Integer.toString(e.getValue()), icon,
|
|
cPlain, t));
|
|
if (++n >= maxSize) break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Display the header area for the concise panel.
|
|
*
|
|
* @param market A {@code Market} to check goods arrears
|
|
* status with.
|
|
*/
|
|
private void conciseHeaders(Market market) {
|
|
reportPanel.add(new JSeparator(JSeparator.HORIZONTAL),
|
|
"newline, span, growx");
|
|
|
|
reportPanel.add(newLabel("report.colony.name.header", null, null,
|
|
stpld("report.colony.name")),
|
|
"newline");
|
|
|
|
reportPanel.add(newLabel("report.colony.size.header", null, null,
|
|
stpld("report.colony.size")));
|
|
|
|
reportPanel.add(newLabel("report.colony.grow.header", null, null,
|
|
stpld("report.colony.grow")));
|
|
reportPanel.add(newLabel("report.colony.shrink.header", null, null,
|
|
stpld("report.colony.shrink")));
|
|
|
|
reportPanel.add(newLabel("report.colony.explore.header", null, null,
|
|
stpld("report.colony.explore")));
|
|
for (TileImprovementType ti : this.spec.getTileImprovementTypeList()) {
|
|
if (ti.isNatural()) continue;
|
|
String key = "report.colony.tile." + ti.getSuffix() + ".header";
|
|
reportPanel.add(newLabel(key, null, null, stpld(key)));
|
|
}
|
|
for (GoodsType gt : this.goodsTypes) {
|
|
ImageIcon icon = new ImageIcon(this.lib.getSmallGoodsTypeImage(gt));
|
|
JLabel l = newLabel(null, icon, null,
|
|
stpl("report.colony.production.header")
|
|
.addNamed("%goods%", gt));
|
|
l.setEnabled(market == null || market.getArrears(gt) <= 0);
|
|
reportPanel.add(l);
|
|
}
|
|
|
|
final UnitType type = spec.getDefaultUnitType(getMyPlayer());
|
|
ImageIcon colonistIcon
|
|
= new ImageIcon(this.lib.getTinyUnitTypeImage(type));
|
|
reportPanel.add(newLabel(null, colonistIcon, null,
|
|
stpld("report.colony.birth")));
|
|
reportPanel.add(newLabel("report.colony.making.header", null, null,
|
|
stpld("report.colony.making")));
|
|
reportPanel.add(newLabel("report.colony.improve.header", null, null,
|
|
stpld("report.colony.improve")));
|
|
|
|
reportPanel.add(new JSeparator(JSeparator.HORIZONTAL),
|
|
"newline, span, growx");
|
|
}
|
|
|
|
/**
|
|
* Update the panel.
|
|
*/
|
|
private void update() {
|
|
reportPanel.removeAll();
|
|
|
|
// Define the layout, with a column for each goods type.
|
|
StringBuilder sb = new StringBuilder(64);
|
|
sb.append("[l][c][c][c]");
|
|
for (int i = 0; i < this.goodsTypes.size(); i++) sb.append("[c]");
|
|
sb.append("[c][c][l][l][l]");
|
|
reportPanel.setLayout(new MigLayout("fillx, insets 0, gap 0 0",
|
|
sb.toString(), ""));
|
|
|
|
conciseHeaders(this.market);
|
|
List<ColonySummary> summaries = new ArrayList<>();
|
|
for (List<Colony> cs : this.colonies) {
|
|
summaries.clear();
|
|
for (Colony c : cs) {
|
|
ColonySummary s = new ColonySummary(c, this.goodsTypes);
|
|
summaries.add(s);
|
|
updateColony(s);
|
|
}
|
|
if (cs.size() > 1) {
|
|
updateCombinedColonies(summaries);
|
|
}
|
|
conciseHeaders(this.market);
|
|
}
|
|
}
|
|
|
|
|
|
// Interface ActionListener
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void actionPerformed(ActionEvent ae) {
|
|
final Game game = getGame();
|
|
String command = ae.getActionCommand();
|
|
if (command.startsWith(BUILDQUEUE)) {
|
|
command = command.substring(BUILDQUEUE.length());
|
|
Colony colony = game.getFreeColGameObject(command, Colony.class);
|
|
if (colony != null) {
|
|
getGUI().showBuildQueuePanel(colony)
|
|
.addClosingCallback(() -> { update(); });
|
|
return;
|
|
}
|
|
} else {
|
|
Colony colony = game.getFreeColGameObject(command, Colony.class);
|
|
if (colony != null) {
|
|
getGUI().showColonyPanel(colony, null)
|
|
.addClosingCallback(() -> { update(); });
|
|
return;
|
|
}
|
|
}
|
|
super.actionPerformed(ae);
|
|
}
|
|
}
|