/**
* 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.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import net.miginfocom.swing.MigLayout;
import net.sf.freecol.FreeCol;
import net.sf.freecol.client.ClientOptions;
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.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.ColonyChangeEvent;
import net.sf.freecol.common.model.ColonyTile;
import net.sf.freecol.common.model.FreeColGameObject;
import net.sf.freecol.common.model.Goods;
import net.sf.freecol.common.model.GoodsContainer;
import net.sf.freecol.common.model.GoodsType;
import net.sf.freecol.common.model.Map.Direction;
import net.sf.freecol.common.model.ModelMessage;
import net.sf.freecol.common.model.Player;
import net.sf.freecol.common.model.Player.NoClaimReason;
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.TileType;
import net.sf.freecol.common.model.TradeRoute;
import net.sf.freecol.common.model.Unit;
import net.sf.freecol.common.model.UnitLocation.NoAddReason;
import net.sf.freecol.common.model.UnitType;
import org.freecolandroid.repackaged.java.awt.Color;
import org.freecolandroid.repackaged.java.awt.Component;
import org.freecolandroid.repackaged.java.awt.Container;
import org.freecolandroid.repackaged.java.awt.FlowLayout;
import org.freecolandroid.repackaged.java.awt.Graphics;
import org.freecolandroid.repackaged.java.awt.Graphics2D;
import org.freecolandroid.repackaged.java.awt.GridLayout;
import org.freecolandroid.repackaged.java.awt.Insets;
import org.freecolandroid.repackaged.java.awt.Point;
import org.freecolandroid.repackaged.java.awt.Rectangle;
import org.freecolandroid.repackaged.java.awt.dnd.Autoscroll;
import org.freecolandroid.repackaged.java.awt.event.ActionEvent;
import org.freecolandroid.repackaged.java.awt.event.ActionListener;
import org.freecolandroid.repackaged.java.awt.event.KeyEvent;
import org.freecolandroid.repackaged.java.awt.event.MouseAdapter;
import org.freecolandroid.repackaged.java.awt.event.MouseEvent;
import org.freecolandroid.repackaged.java.awt.event.MouseListener;
import org.freecolandroid.repackaged.javax.swing.BorderFactory;
import org.freecolandroid.repackaged.javax.swing.ComponentInputMap;
import org.freecolandroid.repackaged.javax.swing.ImageIcon;
import org.freecolandroid.repackaged.javax.swing.InputMap;
import org.freecolandroid.repackaged.javax.swing.JButton;
import org.freecolandroid.repackaged.javax.swing.JComboBox;
import org.freecolandroid.repackaged.javax.swing.JComponent;
import org.freecolandroid.repackaged.javax.swing.JLabel;
import org.freecolandroid.repackaged.javax.swing.JPanel;
import org.freecolandroid.repackaged.javax.swing.JScrollPane;
import org.freecolandroid.repackaged.javax.swing.JToolTip;
import org.freecolandroid.repackaged.javax.swing.JViewport;
import org.freecolandroid.repackaged.javax.swing.KeyStroke;
import org.freecolandroid.repackaged.javax.swing.ScrollPaneConstants;
import org.freecolandroid.repackaged.javax.swing.SwingUtilities;
import org.freecolandroid.repackaged.javax.swing.border.BevelBorder;
/**
* This is a panel for the Colony display. It shows the units that are working
* in the colony, the buildings and much more.
*
* Beware that in debug mode, this might be a server-side version of the colony
* which is why we need to call getColony().getSpecification() to get the
* spec that corresponds to the good types in this colony.
*/
public final class ColonyPanel extends FreeColPanel
implements ActionListener, PropertyChangeListener {
private static Logger logger = Logger.getLogger(ColonyPanel.class.getName());
/**
* The height of the area in which autoscrolling should happen.
*/
public static final int SCROLL_AREA_HEIGHT = 40;
/**
* The speed of the scrolling.
*/
public static final int SCROLL_SPEED = 40;
private static final int EXIT = 0,
BUILDQUEUE = 1,
UNLOAD = 2,
WAREHOUSE = 4,
FILL = 5,
SETGOODS = 6;
private final JPanel netProductionPanel = new JPanel();
private final PopulationPanel populationPanel = new PopulationPanel();
private final JComboBox nameBox;
private final OutsideColonyPanel outsideColonyPanel;
private final InPortPanel inPortPanel;
private final ColonyCargoPanel cargoPanel;
private final WarehousePanel warehousePanel;
private final TilePanel tilePanel;
private final BuildingsPanel buildingsPanel;
private final ConstructionPanel constructionPanel;
private final DefaultTransferHandler defaultTransferHandler;
private final MouseListener pressListener;
private final MouseListener releaseListener;
private Colony colony;
private UnitLabel selectedUnitLabel;
private JButton unloadButton = new JButton(Messages.message("unload"));
private JButton fillButton = new JButton(Messages.message("fill"));
private JButton warehouseButton = new JButton(Messages.message("warehouseDialog.name"));
private JButton buildQueueButton = new JButton(Messages.message("colonyPanel.buildQueue"));
private JButton setGoodsButton = (FreeCol.isInDebugMode())
? new JButton("Set Goods") : null;
/**
* The constructor for the panel.
* @param freeColClient
*
* @param parent The parent of this panel
*/
public ColonyPanel(FreeColClient freeColClient, GUI gui, Colony colony) {
super(freeColClient, gui);
setFocusCycleRoot(true);
// Use ESCAPE for closing the ColonyPanel:
InputMap closeInputMap = new ComponentInputMap(okButton);
closeInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "pressed");
closeInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), "released");
SwingUtilities.replaceUIInputMap(okButton, JComponent.WHEN_IN_FOCUSED_WINDOW, closeInputMap);
InputMap unloadInputMap = new ComponentInputMap(unloadButton);
unloadInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_U, 0, false), "pressed");
unloadInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_U, 0, true), "released");
SwingUtilities.replaceUIInputMap(unloadButton, JComponent.WHEN_IN_FOCUSED_WINDOW, unloadInputMap);
InputMap fillInputMap = new ComponentInputMap(fillButton);
fillInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0, false), "pressed");
fillInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0, true), "released");
SwingUtilities.replaceUIInputMap(fillButton, JComponent.WHEN_IN_FOCUSED_WINDOW, fillInputMap);
netProductionPanel.setOpaque(false);
constructionPanel = new ConstructionPanel(freeColClient, gui, colony, true);
constructionPanel.setOpaque(true);
outsideColonyPanel = new OutsideColonyPanel();
inPortPanel = new InPortPanel();
warehousePanel = new WarehousePanel(this);
tilePanel = new TilePanel(freeColClient, gui, this);
buildingsPanel = new BuildingsPanel(this);
cargoPanel = new ColonyCargoPanel(freeColClient, gui);
cargoPanel.setParentPanel(this);
defaultTransferHandler = new DefaultTransferHandler(freeColClient, gui, this);
pressListener = new DragListener(getFreeColClient(), gui, this);
releaseListener = new DropListener();
JScrollPane outsideColonyScroll = new JScrollPane(outsideColonyPanel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
outsideColonyScroll.getVerticalScrollBar().setUnitIncrement( 16 );
JScrollPane inPortScroll = new JScrollPane(inPortPanel);
inPortScroll.getVerticalScrollBar().setUnitIncrement( 16 );
JScrollPane cargoScroll = new JScrollPane(cargoPanel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane warehouseScroll = new JScrollPane(warehousePanel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane tilesScroll = new JScrollPane(tilePanel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JScrollPane buildingsScroll = new JScrollPane(buildingsPanel,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
buildingsScroll.getVerticalScrollBar().setUnitIncrement( 16 );
// Make the colony label
nameBox = new JComboBox();
nameBox.setFont(smallHeaderFont);
for (Colony aColony : getSortedColonies()) {
nameBox.addItem(aColony);
}
nameBox.setSelectedItem(colony);
nameBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
initialize((Colony) nameBox.getSelectedItem());
}
});
// the following actions are pre-defined
nameBox.getInputMap().put(KeyStroke.getKeyStroke("LEFT"), "selectPrevious2");
nameBox.getInputMap().put(KeyStroke.getKeyStroke("RIGHT"), "selectNext2");
InputMap nameInputMap = new ComponentInputMap(nameBox);
nameInputMap.put(KeyStroke.getKeyStroke("LEFT"), "selectPrevious2");
nameInputMap.put(KeyStroke.getKeyStroke("RIGHT"), "selectNext2");
SwingUtilities.replaceUIInputMap(nameBox, JComponent.WHEN_IN_FOCUSED_WINDOW, nameInputMap);
buildingsScroll.setAutoscrolls(true);
buildingsScroll.getViewport().setOpaque(false);
buildingsPanel.setOpaque(false);
/** Borders */
tilesScroll.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
buildingsScroll.setBorder(BorderFactory.createEtchedBorder());
warehouseScroll.setBorder(BorderFactory.createEtchedBorder());
cargoScroll.setBorder(BorderFactory.createEtchedBorder());
inPortScroll.setBorder(BorderFactory.createEtchedBorder());
outsideColonyScroll.setBorder(BorderFactory.createEtchedBorder());
okButton.setText(Messages.message("close"));
unloadButton.setActionCommand(String.valueOf(UNLOAD));
enterPressesWhenFocused(unloadButton);
unloadButton.addActionListener(this);
fillButton.setActionCommand(String.valueOf(FILL));
enterPressesWhenFocused(fillButton);
fillButton.addActionListener(this);
warehouseButton.setActionCommand(String.valueOf(WAREHOUSE));
enterPressesWhenFocused(warehouseButton);
warehouseButton.addActionListener(this);
buildQueueButton.setActionCommand(String.valueOf(BUILDQUEUE));
enterPressesWhenFocused(buildQueueButton);
buildQueueButton.addActionListener(this);
if (setGoodsButton != null) {
setGoodsButton.setActionCommand(String.valueOf(SETGOODS));
enterPressesWhenFocused(setGoodsButton);
setGoodsButton.addActionListener(this);
}
selectedUnitLabel = null;
// See the message of Ulf Onnen for more information about the presence
// of this fake mouse listener.
addMouseListener(new MouseAdapter() {});
setLayout(new MigLayout("fill, wrap 2, insets 2", "[390!][fill]",
"[][]0[]0[][growprio 200,shrinkprio 10][growprio 150,shrinkprio 50]"));
add(nameBox, "height 48:, grow");
add(netProductionPanel, "growx");
add(tilesScroll, "width 390!, height 200!, top");
add(buildingsScroll, "span 1 3, grow");
add(populationPanel, "grow");
add(constructionPanel, "grow, top");
add(inPortScroll, "span, split 3, grow, sg, height 60:121:");
add(cargoScroll, "grow, sg, height 60:121:");
add(outsideColonyScroll, "grow, sg, height 60:121:");
add(warehouseScroll, "span, height 40:60:, growx");
add(unloadButton, "span, split "
+ Integer.toString((setGoodsButton == null) ? 5 : 6)
+ ", align center");
add(fillButton);
add(warehouseButton);
add(buildQueueButton);
if (setGoodsButton != null) add(setGoodsButton);
add(okButton, "tag ok");
initialize(colony);
restoreSavedSize(850, 600);
}
/**
* Returns a pointer to the <code>CargoPanel</code>-object in use.
*
* @return The <code>CargoPanel</code>.
*/
public final CargoPanel getCargoPanel() {
return cargoPanel;
}
/**
* Returns a pointer to the <code>WarehousePanel</code>-object in use.
*
* @return The <code>WarehousePanel</code>.
*/
public final WarehousePanel getWarehousePanel() {
return warehousePanel;
}
/**
* Returns a pointer to the <code>TilePanel</code>-object in use.
*
* @return The <code>TilePanel</code>.
*/
public final TilePanel getTilePanel() {
return tilePanel;
}
/**
* Returns a pointer to the <code>Colony</code>-pointer in use.
*
* @return The <code>Colony</code>.
*/
public synchronized final Colony getColony() {
return colony;
}
/**
* Set the current colony.
*
* @param colony The new colony value.
*/
private synchronized void setColony(Colony colony) {
removePropertyChangeListeners();
this.colony = colony;
addPropertyChangeListeners();
editable = colony.getOwner() == getMyPlayer();
}
public void updateConstructionPanel() {
constructionPanel.update();
}
public void updateInPortPanel() {
inPortPanel.initialize();
}
public void updateWarehousePanel() {
warehousePanel.update();
}
public void updateOutsideColonyPanel() {
outsideColonyPanel.initialize();
}
public void updateTilePanel() {
tilePanel.initialize();
}
public void updateProductionPanel() {
// TODO: find out why the cache needs to be explicitly invalidated
colony.invalidateCache();
netProductionPanel.removeAll();
for (GoodsType goodsType : getColony().getSpecification().getGoodsTypeList()) {
int amount = colony.getAdjustedNetProductionOf(goodsType);
if (amount != 0) {
netProductionPanel.add(new ProductionLabel(getFreeColClient(), getGUI(), goodsType, amount));
}
}
netProductionPanel.revalidate();
}
private void sortBuildings(List<Building> buildings) {
Collections.sort(buildings);
}
/**
* Analyzes an event and calls the right external methods to take
* care of the user's request.
*
* @param event The incoming action event
*/
public void actionPerformed(ActionEvent event) {
Colony colony = getColony();
String command = event.getActionCommand();
if (OK.equals(command)) {
closeColonyPanel();
} else {
try {
switch (Integer.valueOf(command).intValue()) {
case UNLOAD:
unload();
break;
case WAREHOUSE:
if (getGUI().showWarehouseDialog(colony)) {
updateWarehousePanel();
}
break;
case BUILDQUEUE:
getGUI().showBuildQueuePanel(colony);
updateConstructionPanel();
break;
case FILL:
fill();
break;
case SETGOODS:
debugSetGoods(colony);
break;
default:
logger.warning("Invalid action");
break;
}
} catch (NumberFormatException e) {
logger.warning("Invalid action number: " + command);
}
}
}
/**
* Interactive debug-mode change of goods amount in a colony.
*
* @param canvas The <code>Canvas</code> to use.
* @param colony The <code>Colony</code> to set goods amounts in.
*/
private void debugSetGoods(Colony colony) {
Specification spec = getSpecification();
List<ChoiceItem<GoodsType>> gtl
= new ArrayList<ChoiceItem<GoodsType>>();
for (GoodsType t : spec.getGoodsTypeList()) {
if (t.isFoodType() && t != spec.getPrimaryFoodType()) continue;
gtl.add(new ChoiceItem<GoodsType>(Messages.message(t.toString() + ".name"),
t));
}
GoodsType goodsType = getGUI().showChoiceDialog(null, "Select Goods Type",
"Cancel", gtl);
if (goodsType == null) return;
String amount = getGUI().showInputDialog(null,
StringTemplate.name("Select Goods Amount"),
Integer.toString(colony.getGoodsCount(goodsType)),
"ok", "cancel", true);
if (amount == null) return;
int a;
try {
a = Integer.parseInt(amount);
} catch (NumberFormatException nfe) {
return;
}
GoodsType sGoodsType = getFreeColClient().getFreeColServer()
.getSpecification().getGoodsType(goodsType.getId());
GoodsContainer cgc = colony.getGoodsContainer();
GoodsContainer sgc = (GoodsContainer) getFreeColClient()
.getFreeColServer().getGame().getFreeColGameObject(cgc.getId());
cgc.setAmount(goodsType, a);
sgc.setAmount(sGoodsType, a);
updateConstructionPanel();
updateProductionPanel();
updateWarehousePanel();
}
/**
* Unloads all goods and units from the carrier currently selected.
*/
private void unload() {
Unit unit = getSelectedUnit();
if (unit != null && unit.isCarrier()) {
for (Goods goods : unit.getGoodsContainer().getGoods()) {
getController().unloadCargo(goods, false);
}
for (Unit u : unit.getUnitList()) {
getController().leaveShip(u);
}
cargoPanel.initialize();
outsideColonyPanel.initialize();
}
unloadButton.setEnabled(false);
fillButton.setEnabled(false);
}
/**
* Fill goods from the carrier currently selected to capacity.
*/
private void fill() {
Unit unit = getSelectedUnit();
if (unit != null && unit.isCarrier()) {
for (Goods goods : unit.getGoodsContainer().getGoods()) {
int space = GoodsContainer.CARGO_SIZE - goods.getAmount();
int count = getColony().getGoodsCount(goods.getType());
if (space > 0 && count > 0) {
Goods newGoods = new Goods(goods.getGame(), getColony(),
goods.getType(),
Math.min(space, count));
getController().loadCargo(newGoods, unit);
}
}
}
}
/**
* Enables the unload and fill buttons if the currently selected unit is a
* carrier with some cargo.
*/
private void updateCarrierButtons() {
unloadButton.setEnabled(false);
fillButton.setEnabled(false);
if (isEditable() && selectedUnitLabel != null) {
Unit unit = selectedUnitLabel.getUnit();
if (unit != null && unit.isCarrier()
&& unit.getSpaceLeft() < unit.getType().getSpace()) {
unloadButton.setEnabled(true);
for (Goods goods : unit.getGoodsList()) {
if (getColony().getGoodsCount(goods.getType()) > 0) {
fillButton.setEnabled(true);
break;
}
}
}
}
}
/**
* Returns the currently select unit.
*
* @return The currently select unit.
*/
public Unit getSelectedUnit() {
return (selectedUnitLabel == null) ? null
: selectedUnitLabel.getUnit();
}
/**
* Selects a unit that is potentially located somewhere in port.
*
* @param unit The <code>Unit</code> to select.
*/
public void setSelectedUnit(Unit unit) {
UnitLabel unitLabel = null;
if (unit != null) {
Component[] components = inPortPanel.getComponents();
for (int i = 0; i < components.length; i++) {
if (components[i] instanceof UnitLabel
&& ((UnitLabel) components[i]).getUnit() == unit) {
unitLabel = (UnitLabel) components[i];
break;
}
}
}
setSelectedUnitLabel(unitLabel);
}
/**
* Returns the currently select unit label.
*
* @return The currently select unit label.
*/
public UnitLabel getSelectedUnitLabel() {
return selectedUnitLabel;
}
/**
* Selects a unit that is located somewhere on this panel.
*
* @param unitLabel The <code>UnitLabel</code> for the unit that
* is being selected.
*/
public void setSelectedUnitLabel(UnitLabel unitLabel) {
if (selectedUnitLabel != unitLabel) {
if (selectedUnitLabel != null) {
selectedUnitLabel.setSelected(false);
selectedUnitLabel.getUnit().removePropertyChangeListener(this);
}
selectedUnitLabel = unitLabel;
if (unitLabel == null) {
cargoPanel.setCarrier(null);
} else {
cargoPanel.setCarrier(unitLabel.getUnit());
unitLabel.setSelected(true);
unitLabel.getUnit().addPropertyChangeListener(this);
}
}
updateCarrierButtons();
inPortPanel.revalidate();
inPortPanel.repaint();
}
/**
* Initialize the data on the window. This is the same as calling:
* <code>initialize(colony, game, null)</code>.
*
* @param colony The <code>Colony</code> to be displayed.
*/
private void initialize(Colony colony) {
setColony(colony);
// Set listeners and transfer handlers
outsideColonyPanel.removeMouseListener(releaseListener);
inPortPanel.removeMouseListener(releaseListener);
cargoPanel.removeMouseListener(releaseListener);
warehousePanel.removeMouseListener(releaseListener);
if (isEditable()) {
outsideColonyPanel.setTransferHandler(defaultTransferHandler);
inPortPanel.setTransferHandler(defaultTransferHandler);
cargoPanel.setTransferHandler(defaultTransferHandler);
warehousePanel.setTransferHandler(defaultTransferHandler);
outsideColonyPanel.addMouseListener(releaseListener);
inPortPanel.addMouseListener(releaseListener);
cargoPanel.addMouseListener(releaseListener);
warehousePanel.addMouseListener(releaseListener);
} else {
outsideColonyPanel.setTransferHandler(null);
inPortPanel.setTransferHandler(null);
cargoPanel.setTransferHandler(null);
warehousePanel.setTransferHandler(null);
}
// Enable/disable widgets
unloadButton.setEnabled(isEditable());
fillButton.setEnabled(isEditable());
warehouseButton.setEnabled(isEditable());
nameBox.setEnabled(isEditable());
// update all the subpanels
cargoPanel.setCarrier(null);
inPortPanel.initialize();
warehousePanel.initialize();
buildingsPanel.initialize();
tilePanel.initialize();
updateProductionPanel();
populationPanel.update();
constructionPanel.setColony(colony);
outsideColonyPanel.setColony(colony);
}
/**
* Closes the <code>ColonyPanel</code>.
*/
public void closeColonyPanel() {
if (getColony().getUnitCount() == 0) {
if (getGUI().showConfirmDialog("abandonColony.text",
"abandonColony.yes",
"abandonColony.no")) {
getGUI().removeFromCanvas(this);
getController().abandonColony(getColony());
}
} else {
BuildableType buildable = getColony().getCurrentlyBuilding();
if (buildable != null
&& buildable.getPopulationRequired() > getColony().getUnitCount()
&& !getGUI().showConfirmDialog(null, StringTemplate.template("colonyPanel.reducePopulation")
.addName("%colony%", getColony().getName())
.addAmount("%number%", buildable.getPopulationRequired())
.add("%buildable%", buildable.getNameKey()),
"ok", "cancel")) {
return;
}
getGUI().removeFromCanvas(this);
// remove property listeners
removePropertyChangeListeners();
if (getSelectedUnit() != null) {
getSelectedUnit().removePropertyChangeListener(this);
}
buildingsPanel.cleanup();
warehousePanel.cleanup();
tilePanel.cleanup();
constructionPanel.removePropertyChangeListeners();
cargoPanel.setCarrier(null);
outsideColonyPanel.cleanup();
if (getFreeColClient().currentPlayerIsMyPlayer()) {
getController().nextModelMessage();
Unit activeUnit = getGUI().getActiveUnit();
if (activeUnit == null || activeUnit.getTile() == null || activeUnit.getMovesLeft() <= 0
|| (!(activeUnit.getLocation() instanceof Tile) && !(activeUnit.isOnCarrier()))) {
getGUI().setActiveUnit(null);
getController().nextActiveUnit();
}
}
getGUI().getMapViewer().restartBlinking();
}
}
/**
* Add property change listeners needed by this ColonyPanel.
*/
private void addPropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.addPropertyChangeListener(this);
colony.getGoodsContainer().addPropertyChangeListener(this);
colony.getTile().addPropertyChangeListener(this);
}
}
/**
* Remove the property change listeners of ColonyPanel.
*/
private void removePropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.removePropertyChangeListener(this);
colony.getGoodsContainer().removePropertyChangeListener(this);
colony.getTile().removePropertyChangeListener(this);
}
}
/**
* Handle a property change event sent to this ColonyPanel.
*
* @param event The <code>PropertyChangeEvent</code> to handle.
*/
public void propertyChange(PropertyChangeEvent event) {
if (!isShowing() || getColony() == null) {
return;
}
String property = event.getPropertyName();
logger.finest(getColony().getName() + " change " + property
+ ": " + event.getOldValue()
+ " -> " + event.getNewValue());
if (property == null) {
logger.warning("Null property change");
} else if (Unit.CARGO_CHANGE.equals(property)) {
updateInPortPanel();
} else if (ColonyChangeEvent.POPULATION_CHANGE.toString().equals(property)) {
populationPanel.update();
updateProductionPanel(); // food production changes
} else if (ColonyChangeEvent.BONUS_CHANGE.toString().equals(property)) {
ModelMessage msg = getColony().checkForGovMgtChangeMessage();
if (msg != null) {
getGUI().showInformationMessage(msg);
}
populationPanel.update();
} else if (ColonyChangeEvent.UNIT_TYPE_CHANGE.toString().equals(property)) {
FreeColGameObject object = (FreeColGameObject) event.getSource();
UnitType oldType = (UnitType) event.getOldValue();
UnitType newType = (UnitType) event.getNewValue();
getGUI().showInformationMessage(object,
StringTemplate.template("model.colony.unitChange")
.add("%oldType%", oldType.getNameKey())
.add("%newType%", newType.getNameKey()));
updateTilePanel();
} else if (ColonyTile.UNIT_CHANGE.toString().equals(property)) {
// Note: ColonyTile.UNIT_CHANGE.equals(Building.UNIT_CHANGE)
updateTilePanel();
updateProductionPanel();
} else if (property.startsWith("model.goods.")) {
// Changes to warehouse goods count may affect building production
// which requires a view update.
updateProductionPanel();
updateWarehousePanel();
buildingsPanel.update();
updateConstructionPanel();
} else if (Tile.UNIT_CHANGE.equals(property)) {
updateOutsideColonyPanel();
updateInPortPanel();
} else {
logger.warning("Unknown property change event: "
+ event.getPropertyName());
}
}
/**
* This panel shows the content of a carrier in the colony
*/
public final class ColonyCargoPanel extends CargoPanel {
public ColonyCargoPanel(FreeColClient freeColClient, GUI gui) {
super(freeColClient, gui, true);
setLayout(new MigLayout("wrap 6, fill, insets 0"));
}
@Override
public void update() {
super.update();
// May have un/loaded cargo, "Unload" could have changed validity
updateCarrierButtons();
}
@Override
public String getUIClassID() {
return "CargoPanelUI";
}
}
/**
* This panel is a list of the colony's buildings.
*/
public final class BuildingsPanel extends JPanel {
private final ColonyPanel colonyPanel;
/**
* Creates this BuildingsPanel.
*
* @param colonyPanel The panel that holds this BuildingsPanel.
*/
public BuildingsPanel(ColonyPanel colonyPanel) {
setLayout(new MigLayout("fill, wrap 4, insets 0, gap 0:10:10:push"));
this.colonyPanel = colonyPanel;
}
/**
* Initializes the <code>BuildingsPanel</code> by loading/displaying
* the buildings of the colony.
*/
public void initialize() {
update();
}
public void cleanup() {
removePropertyChangeListeners();
}
public void update() {
removePropertyChangeListeners();
removeAll();
MouseAdapter mouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
getGUI().showBuildQueuePanel(getColony());
}
};
ASingleBuildingPanel aSingleBuildingPanel;
List<Building> buildings = getColony().getBuildings();
sortBuildings(buildings);
for (Building building : buildings) {
aSingleBuildingPanel = new ASingleBuildingPanel(building);
if (colonyPanel.isEditable()) {
aSingleBuildingPanel.addMouseListener(releaseListener);
aSingleBuildingPanel.setTransferHandler(defaultTransferHandler);
}
aSingleBuildingPanel.setOpaque(false);
aSingleBuildingPanel.addMouseListener(mouseAdapter);
add(aSingleBuildingPanel);
}
}
private void removePropertyChangeListeners() {
for (Component component : getComponents()) {
if (component instanceof ASingleBuildingPanel) {
((ASingleBuildingPanel) component).removePropertyChangeListeners();
}
}
}
@Override
public String getUIClassID() {
return "BuildingsPanelUI";
}
/**
* This panel is a single line (one building) in the
* <code>BuildingsPanel</code>.
*/
public final class ASingleBuildingPanel extends BuildingPanel implements Autoscroll {
/**
* Creates this ASingleBuildingPanel.
*
* @param building The building to display information from.
*/
public ASingleBuildingPanel(Building building) {
super(getFreeColClient(), building, getGUI());
}
public void autoscroll(Point p) {
JViewport vp = (JViewport) colonyPanel.buildingsPanel.getParent();
if (getLocation().y + p.y - vp.getViewPosition().y < SCROLL_AREA_HEIGHT) {
vp.setViewPosition(new Point(vp.getViewPosition().x,
Math.max(vp.getViewPosition().y - SCROLL_SPEED, 0)));
} else if (getLocation().y + p.y - vp.getViewPosition().y >= vp.getHeight() - SCROLL_AREA_HEIGHT) {
vp.setViewPosition(new Point(vp.getViewPosition().x,
Math.min(vp.getViewPosition().y + SCROLL_SPEED,
colonyPanel.buildingsPanel.getHeight()
- vp.getHeight())));
}
}
public Insets getAutoscrollInsets() {
Rectangle r = getBounds();
return new Insets(r.x, r.y, r.width, r.height);
}
public void initialize() {
super.initialize();
if (colonyPanel.isEditable()) {
for (UnitLabel unitLabel : getUnitLabels()) {
unitLabel.setTransferHandler(defaultTransferHandler);
unitLabel.addMouseListener(pressListener);
}
}
}
/**
* Adds a component to this ASingleBuildingPanel and makes
* sure that the unit that the component represents gets
* modified so that it will be located in the colony.
*
* @param comp The component to add to this ColonistsPanel.
* @param editState Must be set to 'true' if the state of the
* component that is added (which should be a dropped
* component representing a Unit) should be changed so
* that the underlying unit will be located in the
* colony.
* @return The component argument.
*/
public Component add(Component comp, boolean editState) {
Container oldParent = comp.getParent();
if (editState) {
if (comp instanceof UnitLabel) {
if (tryWork(((UnitLabel) comp).getUnit())) {
oldParent.remove(comp);
} else {
return null;
}
} else {
logger.warning("An invalid component was dropped"
+ " on this ASingleBuildingPanel.");
return null;
}
}
initialize();
return null;
}
private boolean tryWork(Unit unit) {
Building building = getBuilding();
NoAddReason reason = building.getNoAddReason(unit);
if (reason != NoAddReason.NONE) {
getGUI().errorMessage("noAddReason."
+ reason.toString().toLowerCase(Locale.US));
return false;
}
getController().work(unit, building);
return true;
}
}
}
public final class PopulationPanel extends JPanel {
private final JLabel rebelShield = new JLabel();
private final JLabel rebelLabel = new JLabel();
private final JLabel bonusLabel = new JLabel();
private final JLabel royalistLabel = new JLabel();
private final JLabel royalistShield = new JLabel();
private final JLabel rebelMemberLabel = new JLabel();
private final JLabel popLabel = new JLabel();
private final JLabel royalistMemberLabel = new JLabel();
public PopulationPanel() {
setOpaque(false);
setToolTipText(" ");
setLayout(new MigLayout("wrap 5, fill, insets 0",
"[][]:push[center]:push[right][]"));
add(rebelShield, "bottom");
add(rebelLabel, "split 2, flowy");
add(rebelMemberLabel);
add(popLabel, "split 2, flowy");
add(bonusLabel);
add(royalistLabel, "split 2, flowy");
add(royalistMemberLabel);
add(royalistShield, "bottom");
}
public JToolTip createToolTip() {
return new RebelToolTip(getFreeColClient(), getGUI(), getColony());
}
public void update() {
int population = getColony().getUnitCount();
int members = getColony().getMembers();
int rebels = getColony().getSoL();
String rebelNumber = Messages.message(StringTemplate.template("colonyPanel.rebelLabel")
.addAmount("%number%", members));
String royalistNumber = Messages.message(StringTemplate.template("colonyPanel.royalistLabel")
.addAmount("%number%", population - members));
popLabel.setText(Messages.message(StringTemplate.template("colonyPanel.populationLabel")
.addAmount("%number%", population)));
rebelLabel.setText(rebelNumber);
rebelMemberLabel.setText(Integer.toString(rebels) + "%");
bonusLabel.setText(Messages.message(StringTemplate.template("colonyPanel.bonusLabel")
.addAmount("%number%", getColony().getProductionBonus())));
royalistLabel.setText(royalistNumber);
royalistMemberLabel.setText(Integer.toString(getColony().getTory()) + "%");
rebelShield.setIcon(new ImageIcon(getLibrary().getCoatOfArmsImage(getColony().getOwner().getNation(), 0.5)));
royalistShield.setIcon(new ImageIcon(getLibrary().getCoatOfArmsImage(getColony().getOwner().getNation()
.getRefNation(), 0.5)));
revalidate();
repaint();
}
@Override
public String getUIClassID() {
return "PopulationPanelUI";
}
};
/**
* A panel that holds UnitLabels that represent Units that are standing in
* front of a colony.
*/
public final class OutsideColonyPanel extends JPanel
implements PropertyChangeListener {
private Colony colony;
public OutsideColonyPanel() {
super(new MigLayout("wrap 4, fill, insets 0"));
setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(),
Messages.message("outsideColony")));
}
public Colony getColony() {
return colony;
}
public void setColony(Colony newColony) {
removePropertyChangeListeners();
this.colony = newColony;
addPropertyChangeListeners();
initialize();
}
public void initialize() {
removeAll();
if (getColony() == null) return;
Tile colonyTile = getColony().getTile();
for (Unit unit : colonyTile.getUnitList()) {
// we only deal with land, non-carrier units here
if (unit.isNaval() || unit.isCarrier()) {
continue;
}
UnitLabel unitLabel = new UnitLabel(getFreeColClient(), unit, getGUI());
if (isEditable()) {
unitLabel.setTransferHandler(defaultTransferHandler);
unitLabel.addMouseListener(pressListener);
}
add(unitLabel, false);
}
revalidate();
repaint();
}
public void cleanup() {
removePropertyChangeListeners();
}
/**
* Adds a component to this OutsideColonyPanel and makes sure
* that the unit that the component represents gets modified
* so that it will be located in the colony.
*
* @param comp The component to add to this ColonistsPanel.
* @param editState Must be set to 'true' if the state of the component
* that is added (which should be a dropped component
* representing a Unit) should be changed so that the
* underlying unit will be located in the colony.
* @return The component argument.
*/
public Component add(Component comp, boolean editState) {
Container oldParent = comp.getParent();
if (editState) {
if (comp instanceof UnitLabel) {
UnitLabel unitLabel = ((UnitLabel) comp);
Unit unit = unitLabel.getUnit();
if (!unit.isOnCarrier()) {
getController().putOutsideColony(unit);
}
if (unit.getColony() == null) {
closeColonyPanel();
return null;
} else if (!(unit.getLocation() instanceof Tile) && !unit.isOnCarrier()) {
return null;
}
oldParent.remove(comp);
initialize();
return comp;
} else {
logger.warning("An invalid component got dropped on this ColonistsPanel.");
return null;
}
} else {
((UnitLabel) comp).setSmall(false);
Component c = add(comp);
return c;
}
}
private void addPropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.getTile().addPropertyChangeListener(Tile.UNIT_CHANGE,
this);
}
}
private void removePropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.getTile().removePropertyChangeListener(Tile.UNIT_CHANGE,
this);
}
}
public void propertyChange(PropertyChangeEvent event) {
String property = event.getPropertyName();
logger.finest("Outside " + getColony().getId()
+ " change " + property
+ ": " + event.getOldValue()
+ " -> " + event.getNewValue());
initialize();
}
@Override
public String getUIClassID() {
return "OutsideColonyPanelUI";
}
}
/**
* A panel that holds UnitsLabels that represent naval Units that are
* waiting in the port of the colony.
*/
public final class InPortPanel extends JPanel {
public InPortPanel() {
super(new MigLayout("wrap 3, fill, insets 0"));
setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(),
Messages.message("inPort")));
}
public void initialize() {
removeAll();
if (getColony() == null) return;
UnitLabel lastCarrier = null;
UnitLabel prevCarrier = null;
for (Unit unit : getColony().getTile().getUnitList()) {
if (!unit.isCarrier()) continue;
UnitLabel unitLabel = new UnitLabel(getFreeColClient(), unit, getGUI());
TradeRoute tradeRoute = unit.getTradeRoute();
if (tradeRoute != null) {
unitLabel.setDescriptionLabel(Messages.message(Messages.getLabel(unit))
+ " (" + tradeRoute.getName() + ")");
}
if (isEditable()) {
unitLabel.setTransferHandler(defaultTransferHandler);
unitLabel.addMouseListener(pressListener);
}
add(unitLabel);
lastCarrier = unitLabel;
if (getSelectedUnit() == unit) prevCarrier = unitLabel;
}
// Keep the previous selected unit if possible, otherwise default
// on the last carrier.
setSelectedUnitLabel((prevCarrier != null) ? prevCarrier
: (lastCarrier != null) ? lastCarrier
: null);
// No revalidate+repaint as this is done in setSelectedUnitLabel
}
@Override
public String getUIClassID() {
return "InPortPanelUI";
}
}
/**
* A panel that holds goods that represent cargo that is inside
* the Colony.
*/
public final class WarehousePanel extends JPanel
implements PropertyChangeListener {
private final ColonyPanel colonyPanel;
/**
* Creates this WarehousePanel.
*
* @param colonyPanel The panel that holds this WarehousePanel.
*/
public WarehousePanel(ColonyPanel colonyPanel) {
this.colonyPanel = colonyPanel;
setLayout(new MigLayout("fill, gap push, insets 0"));
}
/**
* Initialize this WarehousePanel.
*/
public void initialize() {
addPropertyChangeListeners();
update();
revalidate();
repaint();
}
/**
* Clean up this WarehousePanel.
*/
public void cleanup() {
removePropertyChangeListeners();
}
/**
* Update this WarehousePanel.
*/
private void update() {
final int threshold = (FreeCol.isInDebugMode()) ? 1
: getClientOptions().getInteger(ClientOptions.MIN_NUMBER_FOR_DISPLAYING_GOODS);
removeAll();
GoodsContainer container = getColony().getGoodsContainer();
for (GoodsType goodsType : getColony().getSpecification().getGoodsTypeList()) {
if (goodsType.isStorable()) {
Goods goods = container.getGoods(goodsType);
if (goods.getAmount() >= threshold) {
GoodsLabel goodsLabel = new GoodsLabel(goods, getGUI());
if (colonyPanel.isEditable()) {
goodsLabel.setTransferHandler(defaultTransferHandler);
goodsLabel.addMouseListener(pressListener);
}
add(goodsLabel, false);
}
}
}
revalidate();
repaint();
}
/**
* Adds a component to this WarehousePanel and makes sure that
* the unit or good that the component represents gets
* modified so that it is on board the currently selected
* ship.
*
* @param comp The component to add to this WarehousePanel.
* @param editState Must be set to 'true' if the state of the
* component that is added (which should be a
* dropped component representing a Unit or good)
* should be changed so that the underlying unit or
* goods are on board the currently selected ship.
* @return The component argument.
*/
public Component add(Component comp, boolean editState) {
if (editState) {
if (!(comp instanceof GoodsLabel)) {
logger.warning("Invalid component dropped on this WarehousePanel.");
return null;
}
comp.getParent().remove(comp);
return comp;
}
Component c = add(comp);
return c;
}
private void addPropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.getGoodsContainer().addPropertyChangeListener(this);
}
}
private void removePropertyChangeListeners() {
Colony colony = getColony();
if (colony != null) {
colony.getGoodsContainer().removePropertyChangeListener(this);
}
}
public void propertyChange(PropertyChangeEvent event) {
logger.finest(getColony().getName() + "-warehouse change "
+ event.getPropertyName()
+ ": " + event.getOldValue()
+ " -> " + event.getNewValue());
update();
}
@Override
public String getUIClassID() {
return "WarehousePanelUI";
}
}
/**
* A panel that displays the tiles in the immediate area around the colony.
*/
public final class TilePanel extends FreeColPanel {
private final ColonyPanel colonyPanel;
private Tile[][] tiles = new Tile[3][3];
/**
* Creates this TilePanel.
* @param freeColClient
*
* @param colonyPanel The panel that holds this TilePanel.
*/
public TilePanel(FreeColClient freeColClient, GUI gui, ColonyPanel colonyPanel) {
super(freeColClient, gui);
this.colonyPanel = colonyPanel;
setBackground(Color.BLACK);
setBorder(null);
setLayout(null);
}
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
TileType tileType = getColony().getTile().getType();
int tileWidth = getLibrary().getTerrainImageWidth(tileType) / 2;
int tileHeight = getLibrary().getTerrainImageHeight(tileType) / 2;
if (getColony() != null) {
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if (tiles[x][y] != null) {
int xx = ((2 - x) + y) * tileWidth;
int yy = (x + y) * tileHeight;
g.translate(xx, yy);
getGUI().getColonyTileGUI().displayColonyTile((Graphics2D) g, tiles[x][y], getColony());
g.translate(-xx, -yy);
}
}
}
}
}
public void initialize() {
removePropertyChangeListeners();
removeAll();
Tile tile = getColony().getTile();
tiles[0][0] = tile.getNeighbourOrNull(Direction.N);
tiles[0][1] = tile.getNeighbourOrNull(Direction.NE);
tiles[0][2] = tile.getNeighbourOrNull(Direction.E);
tiles[1][0] = tile.getNeighbourOrNull(Direction.NW);
tiles[1][1] = tile;
tiles[1][2] = tile.getNeighbourOrNull(Direction.SE);
tiles[2][0] = tile.getNeighbourOrNull(Direction.W);
tiles[2][1] = tile.getNeighbourOrNull(Direction.SW);
tiles[2][2] = tile.getNeighbourOrNull(Direction.S);
int layer = 2;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if (tiles[x][y] != null) {
ColonyTile colonyTile = getColony().getColonyTile(tiles[x][y]);
ASingleTilePanel p = new ASingleTilePanel(colonyTile, x, y);
add(p, new Integer(layer));
layer++;
}
}
}
repaint();
}
public void cleanup() {
removePropertyChangeListeners();
}
private void removePropertyChangeListeners() {
for (Component component : getComponents()) {
if (component instanceof ASingleTilePanel) {
((ASingleTilePanel) component).removePropertyChangeListeners();
}
}
}
/**
* Panel for visualizing a <code>ColonyTile</code>. The component
* itself is not visible, however the content of the component is (i.e.
* the people working and the production)
*/
public final class ASingleTilePanel extends JPanel implements PropertyChangeListener {
private ColonyTile colonyTile;
public ASingleTilePanel(ColonyTile colonyTile, int x, int y) {
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
this.colonyTile = colonyTile;
addPropertyChangeListeners();
setOpaque(false);
TileType tileType = colonyTile.getTile().getType();
// Size and position:
setSize(getLibrary().getTerrainImageWidth(tileType), getLibrary().getTerrainImageHeight(tileType));
setLocation(((2 - x) + y) * getLibrary().getTerrainImageWidth(tileType) / 2,
(x + y) * getLibrary().getTerrainImage(tileType, 0, 0).getHeight(null) / 2);
initialize();
}
/**
* Initialized the center of the colony panel tile. The one
* containing the city.
*
*/
private void initializeAsCenterTile() {
setLayout(new GridLayout(2, 1));
ProductionInfo info = colony.getProductionInfo(colonyTile);
if (info == null) return;
for (AbstractGoods goods : info.getProduction()) {
add(new ProductionLabel(getFreeColClient(), getGUI(), goods));
}
}
/**
* Updates the description label The description label is a tooltip
* with the terrain type, road and plow indicator if any
*
* If a unit is on it update the tooltip of it instead
*/
private void updateDescriptionLabel(UnitLabel unit, boolean toAdd) {
String tileDescription = Messages.message(this.colonyTile.getLabel());
if (unit == null) {
setToolTipText(tileDescription);
} else {
String unitDescription = Messages.message(Messages.getLabel(unit.getUnit()));
if (toAdd) {
unitDescription = tileDescription + " [" + unitDescription + "]";
}
unit.setDescriptionLabel(unitDescription);
}
}
/**
* Checks if this <code>JComponent</code> contains the given
* coordinate.
*/
@Override
public boolean contains(int px, int py) {
int w = getWidth();
int h = getHeight();
int dx = Math.abs(w/2 - px);
int dy = Math.abs(h/2 - py);
return (dx + w * dy / h) <= w/2;
}
private void initialize() {
removeAll();
UnitLabel unitLabel = null;
for (Unit unit : colonyTile.getUnitList()) {
unitLabel = new UnitLabel(getFreeColClient(), unit, getGUI());
if (colonyPanel.isEditable()) {
unitLabel.setTransferHandler(defaultTransferHandler);
unitLabel.addMouseListener(pressListener);
}
super.add(unitLabel);
}
updateDescriptionLabel(unitLabel, true);
if (colonyTile.isColonyCenterTile()) {
initializeAsCenterTile();
}
if (colonyPanel.isEditable()) {
setTransferHandler(defaultTransferHandler);
addMouseListener(releaseListener);
}
}
/**
* Adds a component to this CargoPanel and makes sure that the unit
* or good that the component represents gets modified so that it is
* on board the currently selected ship.
*
* @param comp The component to add to this CargoPanel.
* @param editState Must be set to 'true' if the state of the
* component that is added (which should be a dropped
* component representing a Unit or good) should be
* changed so that the underlying unit or goods are on
* board the currently selected ship.
* @return The component argument.
*/
public Component add(Component comp, boolean editState) {
Container oldParent = comp.getParent();
if (editState) {
if (comp instanceof UnitLabel) {
if (tryWork(((UnitLabel) comp).getUnit())) {
oldParent.remove(comp);
((UnitLabel) comp).setSmall(false);
} else {
return null;
}
} else {
logger.warning("An invalid component was dropped"
+ " on this ASingleTilePanel.");
return null;
}
}
/*
* At this point, the panel has already been updated
* via the property change listener.
*
removeAll();
Component c = super.add(comp);
refresh();
*/
return comp;
}
/**
* Try to work this tile with a specified unit.
*
* @param unit The <code>Unit</code> to work the tile.
* @return True if the unit succeeds.
*/
private boolean tryWork(Unit unit) {
Tile tile = colonyTile.getWorkTile();
Colony colony = getColony();
Player player = unit.getOwner();
if (tile.getOwningSettlement() != colony) {
// Need to acquire the tile before working it.
NoClaimReason claim
= player.canClaimForSettlementReason(tile);
switch (claim) {
case NONE: case NATIVES:
if (getController().claimLand(tile, colony, 0)
&& tile.getOwningSettlement() == colony) {
logger.info("Colony " + colony.getName()
+ " claims tile " + tile.toString()
+ " with unit " + unit.getId());
} else {
logger.warning("Colony " + colony.getName()
+ " did not claim " + tile.toString()
+ " with unit " + unit.getId());
return false;
}
break;
default: // Otherwise, can not use land
getGUI().errorMessage("noClaimReason."
+ claim.toString().toLowerCase(Locale.US));
return false;
}
// Check reason again, claim should be satisfied.
if (tile.getOwningSettlement() != colony) {
throw new IllegalStateException("Claim failed");
}
}
// Claim sorted, but complain about other failure.
NoAddReason reason = colonyTile.getNoAddReason(unit);
if (reason != NoAddReason.NONE) {
getGUI().errorMessage("noAddReason."
+ reason.toString().toLowerCase(Locale.US));
return false;
}
// Choose the work to be done.
// FTM, do not change the work type unless explicitly
// told to as this destroys experience (TODO: allow
// multiple experience accumulation?).
GoodsType workType = unit.getWorkType();
if (workType == null) {
// Try to use expertise, then tile-specific
workType = unit.getType().getExpertProduction();
if (workType == null) {
workType = colonyTile.getWorkType(unit);
}
}
// Set the unit to work. Note this might upgrade the
// unit, and possibly even change its work type as the
// server has the right to maintain consistency.
getController().work(unit, colonyTile);
// Now recheck, and see if we want to change to the
// expected work type.
if (workType != null
&& workType != unit.getWorkType()) {
getController().changeWorkType(unit, workType);
}
if (getClientOptions()
.getBoolean(ClientOptions.SHOW_NOT_BEST_TILE)) {
ColonyTile best = colony.getVacantColonyTileFor(unit, false,
workType);
if (best != null && colonyTile != best
&& (colonyTile.getProductionOf(unit, workType)
< best.getProductionOf(unit, workType))) {
StringTemplate template
= StringTemplate.template("colonyPanel.notBestTile")
.addStringTemplate("%unit%", Messages.getLabel(unit))
.add("%goods%", workType.getNameKey())
.addStringTemplate("%tile%", best.getLabel());
getGUI().showInformationMessage(template);
}
}
return true;
}
public void addPropertyChangeListeners() {
colonyTile.addPropertyChangeListener(this);
}
public void removePropertyChangeListeners() {
colonyTile.removePropertyChangeListener(this);
}
public void propertyChange(PropertyChangeEvent event) {
String property = event.getPropertyName();
logger.finest(colonyTile.getId() + " change " + property
+ ": " + event.getOldValue()
+ " -> " + event.getNewValue());
initialize();
}
}
}
}