/**
* 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;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.freecolandroid.repackaged.java.awt.Component;
import org.freecolandroid.repackaged.java.awt.Dimension;
import org.freecolandroid.repackaged.java.awt.Graphics;
import org.freecolandroid.repackaged.java.awt.Graphics2D;
import org.freecolandroid.repackaged.java.awt.Point;
import org.freecolandroid.repackaged.java.awt.Rectangle;
import org.freecolandroid.repackaged.java.awt.event.KeyListener;
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.java.awt.event.MouseMotionListener;
import org.freecolandroid.repackaged.javax.swing.BorderFactory;
import org.freecolandroid.repackaged.javax.swing.ImageIcon;
import org.freecolandroid.repackaged.javax.swing.JComponent;
import org.freecolandroid.repackaged.javax.swing.JDesktopPane;
import org.freecolandroid.repackaged.javax.swing.JInternalFrame;
import org.freecolandroid.repackaged.javax.swing.JLayeredPane;
import org.freecolandroid.repackaged.javax.swing.JMenuItem;
import org.freecolandroid.repackaged.javax.swing.SwingUtilities;
import org.freecolandroid.repackaged.javax.swing.border.EmptyBorder;
import org.freecolandroid.repackaged.javax.swing.filechooser.FileFilter;
import org.freecolandroid.repackaged.javax.swing.plaf.basic.BasicInternalFrameUI;
import net.sf.freecol.FreeCol;
import net.sf.freecol.client.FreeColClient;
import net.sf.freecol.client.gui.action.FreeColAction;
import net.sf.freecol.client.gui.action.MapControlsAction;
import net.sf.freecol.client.gui.i18n.Messages;
import net.sf.freecol.client.gui.panel.AboutPanel;
import net.sf.freecol.client.gui.panel.BuildQueuePanel;
import net.sf.freecol.client.gui.panel.CaptureGoodsDialog;
import net.sf.freecol.client.gui.panel.ChatPanel;
import net.sf.freecol.client.gui.panel.ChoiceDialog;
import net.sf.freecol.client.gui.panel.ChoiceItem;
import net.sf.freecol.client.gui.panel.ChooseFoundingFatherDialog;
import net.sf.freecol.client.gui.panel.ClientOptionsDialog;
import net.sf.freecol.client.gui.panel.ColonyPanel;
import net.sf.freecol.client.gui.panel.ColopediaPanel;
import net.sf.freecol.client.gui.panel.CompactLabourReport;
import net.sf.freecol.client.gui.panel.ConfirmDeclarationDialog;
import net.sf.freecol.client.gui.panel.DeclarationDialog;
import net.sf.freecol.client.gui.panel.DifficultyDialog;
import net.sf.freecol.client.gui.panel.DumpCargoDialog;
import net.sf.freecol.client.gui.panel.EditSettlementDialog;
import net.sf.freecol.client.gui.panel.EmigrationPanel;
import net.sf.freecol.client.gui.panel.ErrorPanel;
import net.sf.freecol.client.gui.panel.EuropePanel;
import net.sf.freecol.client.gui.panel.EventPanel;
import net.sf.freecol.client.gui.panel.FindSettlementDialog;
import net.sf.freecol.client.gui.panel.FreeColDialog;
import net.sf.freecol.client.gui.panel.FreeColPanel;
import net.sf.freecol.client.gui.panel.GameOptionsDialog;
import net.sf.freecol.client.gui.panel.IndianSettlementPanel;
import net.sf.freecol.client.gui.panel.LabourData.UnitData;
import net.sf.freecol.client.gui.panel.LoadingSavegameDialog;
import net.sf.freecol.client.gui.panel.MainPanel;
import net.sf.freecol.client.gui.panel.MapControls;
import net.sf.freecol.client.gui.panel.MapGeneratorOptionsDialog;
import net.sf.freecol.client.gui.panel.MonarchPanel;
import net.sf.freecol.client.gui.panel.NegotiationDialog;
import net.sf.freecol.client.gui.panel.PreCombatDialog;
import net.sf.freecol.client.gui.panel.RecruitDialog;
import net.sf.freecol.client.gui.panel.ReportCargoPanel;
import net.sf.freecol.client.gui.panel.ReportColonyPanel;
import net.sf.freecol.client.gui.panel.ReportContinentalCongressPanel;
import net.sf.freecol.client.gui.panel.ReportEducationPanel;
import net.sf.freecol.client.gui.panel.ReportExplorationPanel;
import net.sf.freecol.client.gui.panel.ReportForeignAffairPanel;
import net.sf.freecol.client.gui.panel.ReportHighScoresPanel;
import net.sf.freecol.client.gui.panel.ReportHistoryPanel;
import net.sf.freecol.client.gui.panel.ReportIndianPanel;
import net.sf.freecol.client.gui.panel.ReportLabourPanel;
import net.sf.freecol.client.gui.panel.ReportMilitaryPanel;
import net.sf.freecol.client.gui.panel.ReportNavalPanel;
import net.sf.freecol.client.gui.panel.ReportProductionPanel;
import net.sf.freecol.client.gui.panel.ReportReligiousPanel;
import net.sf.freecol.client.gui.panel.ReportRequirementsPanel;
import net.sf.freecol.client.gui.panel.ReportTradePanel;
import net.sf.freecol.client.gui.panel.ReportTurnPanel;
import net.sf.freecol.client.gui.panel.RiverStylePanel;
import net.sf.freecol.client.gui.panel.SelectAmountDialog;
import net.sf.freecol.client.gui.panel.SelectDestinationDialog;
import net.sf.freecol.client.gui.panel.ServerListPanel;
import net.sf.freecol.client.gui.panel.StartGamePanel;
import net.sf.freecol.client.gui.panel.StatisticsPanel;
import net.sf.freecol.client.gui.panel.StatusPanel;
import net.sf.freecol.client.gui.panel.TilePanel;
import net.sf.freecol.client.gui.panel.TradeRouteDialog;
import net.sf.freecol.client.gui.panel.TradeRouteInputDialog;
import net.sf.freecol.client.gui.panel.TrainDialog;
import net.sf.freecol.client.gui.panel.VictoryPanel;
import net.sf.freecol.client.gui.panel.WarehouseDialog;
import net.sf.freecol.client.gui.panel.WorkProductionPanel;
import net.sf.freecol.common.ServerInfo;
import net.sf.freecol.common.model.Colony;
import net.sf.freecol.common.model.DiplomaticTrade;
import net.sf.freecol.common.model.Europe;
import net.sf.freecol.common.model.FoundingFather;
import net.sf.freecol.common.model.FreeColGameObject;
import net.sf.freecol.common.model.Game;
import net.sf.freecol.common.model.Goods;
import net.sf.freecol.common.model.GoodsType;
import net.sf.freecol.common.model.IndianNationType;
import net.sf.freecol.common.model.IndianSettlement;
import net.sf.freecol.common.model.Location;
import net.sf.freecol.common.model.ModelMessage;
import net.sf.freecol.common.model.Monarch.MonarchAction;
import net.sf.freecol.common.model.Player;
import net.sf.freecol.common.model.Settlement;
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.TradeRoute;
import net.sf.freecol.common.model.Unit;
import net.sf.freecol.common.model.WorkLocation;
import net.sf.freecol.common.option.Option;
import net.sf.freecol.common.option.OptionGroup;
import android.widget.Toast;
/**
* The main container for the other GUI components in FreeCol. This container is
* where the panels, dialogs and menus are added. In addition, this is the
* component in which the map graphics are displayed. <br>
* <b>Displaying panels and a dialogs</b> <br>
* <br>
* <code>Canvas</code> contains methods to display various panels and dialogs.
* Most of these methods use {@link net.sf.freecol.client.gui.i18n i18n} to get
* localized text. Here is an example: <br>
*
* <PRE>
*
* if (canvas.showConfirmDialog("choice.text", "choice.yes", "choice.no")) { //
* DO SOMETHING. }
*
* </PRE>
*
* <br>
* where "choice.text", "choice.yes" and "choice.no" are keys for a localized
* message. See {@link net.sf.freecol.client.gui.i18n i18n} for more
* information. <br>
* <b>The difference between a panel and a dialog</b> <br>
* <br>
* When displaying a dialog, using a <code>showXXXDialog</code>, the calling
* thread will wait until that dialog is dismissed before returning. In
* contrast, a <code>showXXXPanel</code>-method returns immediately.
*/
public final class Canvas extends JDesktopPane {
public static enum BoycottAction {
CANCEL,
PAY_ARREARS,
DUMP_CARGO
}
public static enum BuyAction {
CANCEL,
BUY,
HAGGLE
}
public static enum ClaimAction {
CANCEL,
ACCEPT,
STEAL
}
public static enum EventType {
FIRST_LANDING,
MEETING_NATIVES,
MEETING_EUROPEANS,
MEETING_AZTEC,
MEETING_INCA,
DISCOVER_PACIFIC
}
public static enum MissionaryAction {
CANCEL,
ESTABLISH_MISSION,
DENOUNCE_HERESY,
INCITE_INDIANS
}
public static enum PopupPosition {
ORIGIN,
CENTERED,
CENTERED_LEFT,
CENTERED_RIGHT,
}
public static enum ScoutColonyAction {
CANCEL,
FOREIGN_COLONY_NEGOTIATE,
FOREIGN_COLONY_SPY,
FOREIGN_COLONY_ATTACK
}
public static enum ScoutIndianSettlementAction {
CANCEL,
INDIAN_SETTLEMENT_SPEAK,
INDIAN_SETTLEMENT_TRIBUTE,
INDIAN_SETTLEMENT_ATTACK
}
public static enum SellAction {
CANCEL,
SELL,
HAGGLE,
GIFT
}
public static enum TradeAction {
CANCEL,
BUY,
SELL,
GIFT
}
/**
* Handles the moving of internal frames.
*/
class FrameMotionListener extends MouseAdapter implements MouseMotionListener {
private JInternalFrame f;
private Point loc = null;
FrameMotionListener(JInternalFrame f) {
this.f = f;
}
@Override
public void mouseDragged(MouseEvent e) {
if (loc == null || f.getDesktopPane() == null || f.getDesktopPane().getDesktopManager() == null) {
return;
}
Point p = SwingUtilities.convertPoint((Component) e.getSource(), e.getX(), e.getY(), null);
int moveX = loc.x - p.x;
int moveY = loc.y - p.y;
f.getDesktopPane().getDesktopManager().dragFrame(f, f.getX() - moveX, f.getY() - moveY);
loc = p;
}
@Override
public void mouseMoved(MouseEvent arg0) {
}
@Override
public void mousePressed(MouseEvent e) {
if (f.getDesktopPane() == null || f.getDesktopPane().getDesktopManager() == null) {
return;
}
loc = SwingUtilities.convertPoint((Component) e.getSource(), e.getX(), e.getY(), null);
f.getDesktopPane().getDesktopManager().beginDraggingFrame(f);
}
@Override
public void mouseReleased(MouseEvent e) {
if (loc == null || f.getDesktopPane() == null || f.getDesktopPane().getDesktopManager() == null) {
return;
}
f.getDesktopPane().getDesktopManager().endDraggingFrame(f);
}
}
/**
* A class for frames being used as tool boxes.
*/
class ToolBoxFrame extends JInternalFrame {
}
private static final Logger logger = Logger.getLogger(Canvas.class.getName());
private static final Integer MAIN_LAYER = JLayeredPane.DEFAULT_LAYER;
private static final Integer STATUS_LAYER = JLayeredPane.POPUP_LAYER;
/**
* To save the most recently open dialog in Europe
* (<code>RecruitDialog</code>, <code>PurchaseDialog</code>, <code>TrainDialog</code>)
*/
private FreeColDialog<Integer> europeOpenDialog = null;
private final FreeColClient freeColClient;
private GUI gui;
private MainPanel mainPanel;
private final StartGamePanel startGamePanel;
private final EuropePanel europePanel;
private final StatusPanel statusPanel;
private final ChatPanel chatPanel;
private final MapViewer mapViewer;
private final ServerListPanel serverListPanel;
private final ClientOptionsDialog clientOptionsDialog;
private final LoadingSavegameDialog loadingSavegameDialog;
private boolean clientOptionsDialogShowing = false;
private MapControls mapControls;
/**
* Variable used for detecting resizing.
*/
private Dimension oldSize = null;
private Dimension initialSize = null;
/**
* The constructor to use.
*
* @param client main control class.
* @param size The bounds of this <code>Canvas</code>.
* @param mapViewer The object responsible of drawing the map onto this component.
*/
public Canvas(FreeColClient client, GUI gui, Dimension size, MapViewer mapViewer) {
this.freeColClient = client;
this.gui = gui;
this.mapViewer = mapViewer;
this.initialSize = size;
setLocation(0, 0);
setSize(size);
setDoubleBuffered(true);
setOpaque(false);
setLayout(null);
startGamePanel = new StartGamePanel(freeColClient, gui);
serverListPanel = new ServerListPanel(freeColClient, gui, freeColClient.getConnectController());
europePanel = new EuropePanel(freeColClient, gui, this);
statusPanel = new StatusPanel(freeColClient, gui);
chatPanel = new ChatPanel(freeColClient, gui);
clientOptionsDialog = new ClientOptionsDialog(freeColClient, gui);
loadingSavegameDialog = new LoadingSavegameDialog(freeColClient, gui);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
// takeFocus();
// chatDisplayThread = new ChatDisplayThread();
// chatDisplayThread.start();
// TODO: move shutdown hook from GUI to (say) client!
Runtime runtime = Runtime.getRuntime();
runtime.addShutdownHook(new Thread(FreeCol.CLIENT_THREAD+"Quitting Game") {
@Override
public void run() {
freeColClient.getConnectController().quitGame(true);
}
});
createKeyBindings();
logger.info("Canvas created.");
}
/**
* Adds a component to this Canvas.
*
* @param comp The component to add
* @return The component argument.
*/
@Override
public Component add(Component comp) {
add(comp, null);
return comp;
}
/**
* Adds a component to this Canvas. Removes the statuspanel if visible (and
* <code>comp != statusPanel</code>).
*
* @param comp The component to add to this ToEuropePanel.
* @param i The layer to add the component to (see JLayeredPane).
*/
public void add(Component comp, Integer i) {
add(comp, i, true);
}
/**
* Adds a component to this Canvas. Removes the statuspanel if visible (and
* <code>comp != statusPanel</code>).
*
* @param comp The component to add to this ToEuropePanel.
* @param i The layer to add the component to (see JLayeredPane).
*/
public void add(Component comp, Integer i, boolean update) {
if (comp != statusPanel && !(comp instanceof JMenuItem) && !(comp instanceof FreeColDialog<?>)
&& statusPanel.isVisible()) {
remove(statusPanel, false);
}
try {
if (i == null) {
super.add(comp);
} else {
super.add(comp, i);
}
} catch(Exception e) {
logger.warning("add component failed with layer " + i);
e.printStackTrace();
}
if (update) {
gui.updateMenuBar();
freeColClient.getActionManager().update();
}
}
/**
* Adds a component centered on this Canvas inside a frame. Removes the
* statuspanel if visible (and <code>comp != statusPanel</code>).
*
* @param comp The component to add to this JInternalFrame.
* @return The <code>JInternalFrame</code> that was created and added.
*/
public JInternalFrame addAsFrame(JComponent comp) {
return addAsFrame(comp, false, PopupPosition.CENTERED);
}
/**
* Adds a component centered on this Canvas inside a frame.
* The frame is considered as a tool box (not counted as a frame
* by the methods deciding if a panel is being displayed).
*
* <br><br>
*
* Removes the statuspanel if visible (and
* <code>comp != statusPanel</code>).
*
* @param comp The component to add to this JInternalFrame.
* @return The <code>JInternalFrame</code> that was created and added.
*/
public JInternalFrame addAsToolBox(JComponent comp) {
return addAsFrame(comp, true, PopupPosition.CENTERED);
}
/**
* Closes the {@link MainPanel}.
*/
public void closeMainPanel() {
if (mainPanel != null) {
remove(mainPanel);
mainPanel = null;
}
}
/**
* Checks if this <code>Canvas</code> contains any ingame components.
*
* @return <code>true</code> if there is a single ingame component.
*/
public boolean containsInGameComponents() {
KeyListener[] keyListeners = getKeyListeners();
if (keyListeners.length > 0) {
return true;
}
MouseListener[] mouseListeners = getMouseListeners();
if (mouseListeners.length > 0) {
return true;
}
MouseMotionListener[] mouseMotionListeners = getMouseMotionListeners();
if (mouseMotionListeners.length > 0) {
return true;
}
return false;
}
/**
* Detailed view of a foreign colony when in debug mode.
*
* @param settlement The <code>Settlement</code> with the colony
*/
public void debugForeignColony(Settlement settlement) {
if (settlement instanceof Colony) {
FreeColGameObject fcgo = freeColClient.getFreeColServer().getGame()
.getFreeColGameObject(settlement.getId());
gui.showColonyPanel((Colony) fcgo);
}
}
/**
* Gets the <code>LoadingSavegameDialog</code>.
*
* @return The <code>LoadingSavegameDialog</code>.
*/
public LoadingSavegameDialog getLoadingSavegameDialog() {
return loadingSavegameDialog;
}
/**
* Returns the MapControls of this Canvas.
*
* @return a <code>MapControls</code> value
*/
public MapControls getMapControls() {
return mapControls;
}
@Override
public Dimension getMinimumSize() {
return new Dimension(640, 480);
}
@Override
public Dimension getPreferredSize() {
return initialSize;
}
/**
* The any panel this <code>Canvas</code> is displaying.
*
* @return A <code>Component</code> the <code>Canvas</code> is
* displaying, or null if none found.
*/
public Component getShowingSubPanel() {
Component[] components = getComponents();
for (Component c : components) {
if (c instanceof ToolBoxFrame) {
continue;
}
if (c instanceof JInternalFrame) {
return c;
} else if (c instanceof JInternalFrame.JDesktopIcon) {
return c;
}
}
return null;
}
/**
* Checks if the <code>ClientOptionsDialog</code> is visible.
*
* @return <code>true</code> if no internal frames are open.
*/
public boolean isClientOptionsDialogShowing() {
return clientOptionsDialogShowing;
}
/**
* Checks if mapboard actions should be enabled.
*
* @return <code>true</code> if no internal frames are open.
*/
public boolean isMapboardActionsEnabled() {
return !isShowingSubPanel();
}
/**
* Checks if this <code>Canvas</code> displaying another panel.
* <p>
* Note that the previous implementation could throw exceptions
* in some cases, thus the change.
*
* @return <code>true</code> if the <code>Canvas</code> is displaying an
* internal frame.
*/
public boolean isShowingSubPanel() {
return getShowingSubPanel() != null;
}
/**
* Paints this component. This method will use {@link MapViewer#display} to draw
* the map/background on this component.
*
* @param g The Graphics context in which to draw this component.
* @see MapViewer#display
*/
@Override
public void paintComponent(Graphics g) {
updateSizes();
Graphics2D g2d = (Graphics2D) g;
mapViewer.display(g2d);
}
public void refreshPlayersTable() {
// startGamePanel.refreshPlayersTable();
}
/**
* Removes the given component from this Container.
*
* @param comp The component to remove from this Container.
*/
@Override
public void remove(Component comp) {
remove(comp, true);
}
/**
* Removes the given component from this Container.
*
* @param comp The component to remove from this Container.
* @param update The <code>Canvas</code> will be enabled, the graphics
* repainted and both the menubar and the actions will be updated
* if this parameter is <code>true</code>.
*/
public void remove(Component comp, boolean update) {
if (comp == null) {
return;
} else if (comp instanceof FreeColPanel) {
((FreeColPanel) comp).notifyClose();
}
final Rectangle updateBounds = comp.getBounds();
final JInternalFrame frame = getInternalFrame(comp);
if (frame != null && frame != comp) {
// updateBounds = frame.getBounds();
frame.dispose();
} else {
super.remove(comp);
}
repaint(updateBounds.x, updateBounds.y, updateBounds.width, updateBounds.height);
final boolean takeFocus = (comp != statusPanel);
if (update) {
gui.updateMenuBar();
freeColClient.getActionManager().update();
if (takeFocus && !isShowingSubPanel()) {
requestFocus();
}
}
}
/**
* Removes components that is only used when in game.
*/
public void removeInGameComponents() {
// remove listeners, they will be added when launching the new game...
// KeyListener[] keyListeners = getKeyListeners();
// for (int i = 0; i < keyListeners.length; ++i) {
// removeKeyListener(keyListeners[i]);
// }
//
// MouseListener[] mouseListeners = getMouseListeners();
// for (int i = 0; i < mouseListeners.length; ++i) {
// removeMouseListener(mouseListeners[i]);
// }
//
// MouseMotionListener[] mouseMotionListeners = getMouseMotionListeners();
// for (int i = 0; i < mouseMotionListeners.length; ++i) {
// removeMouseMotionListener(mouseMotionListeners[i]);
// }
// change to default view mode
// Must be done before removing jMenuBar to prevent exception (crash)
gui.getMapViewer().getViewMode().changeViewMode(ViewMode.MOVE_UNITS_MODE);
// for (Component c : getComponents()) {
// remove(c, false);
// }
}
/**
* Closes all panels, changes the background and shows the main menu.
*/
public void returnToTitle() {
// TODO: check if the GUI object knows that we're not
// inGame. (Retrieve value of GUI::inGame.) If GUI thinks
// we're still in the game then log an error because at this
// point the GUI should have been informed.
removeInGameComponents();
gui.showMainPanel();
gui.playSound("sound.intro.general");
repaint();
}
public void showAboutPanel() {
showSubPanel(new AboutPanel(freeColClient, gui));
}
/**
* Displays a dialog that asks the user what he wants to do with his armed
* unit in a native settlement.
*
* @param settlement The <code>IndianSettlement</code> to consider.
* @return The chosen action, tribute, attack or cancel.
*/
public ScoutIndianSettlementAction showArmedUnitIndianSettlementDialog(IndianSettlement settlement) {
List<ChoiceItem<ScoutIndianSettlementAction>> choices
= new ArrayList<ChoiceItem<ScoutIndianSettlementAction>>();
choices.add(new ChoiceItem<ScoutIndianSettlementAction>(
Messages.message("scoutSettlement.tribute"),
ScoutIndianSettlementAction.INDIAN_SETTLEMENT_TRIBUTE));
choices.add(new ChoiceItem<ScoutIndianSettlementAction>(
Messages.message("scoutSettlement.attack"),
ScoutIndianSettlementAction.INDIAN_SETTLEMENT_ATTACK));
String messageId = settlement.getAlarmLevelMessageId(freeColClient.getMyPlayer());
ScoutIndianSettlementAction result
= showChoiceDialog(settlement.getTile(),
Messages.message(StringTemplate.template(messageId)
.addStringTemplate("%nation%", settlement.getOwner().getNationName())),
Messages.message("cancel"),
choices);
return (result == null) ? ScoutIndianSettlementAction.CANCEL : result;
}
/**
* Displays a dialog that asks the user whether to pay arrears for
* boycotted goods or to dump them instead.
*
* @param goods a <code>Goods</code> value
* @param europe an <code>Europe</code> value
* @return a <code>boolean</code> value
*/
public BoycottAction showBoycottedGoodsDialog(Goods goods, Europe europe) {
int arrears = europe.getOwner().getArrears(goods.getType());
List<ChoiceItem<BoycottAction>> choices
= new ArrayList<ChoiceItem<BoycottAction>>();
choices.add(new ChoiceItem<BoycottAction>(
Messages.message("boycottedGoods.payArrears"),
BoycottAction.PAY_ARREARS));
choices.add(new ChoiceItem<BoycottAction>(
Messages.message("boycottedGoods.dumpGoods"),
BoycottAction.DUMP_CARGO));
BoycottAction result =
showChoiceDialog(null,
Messages.message(StringTemplate.template("boycottedGoods.text")
.add("%goods%", goods.getNameKey())
.add("%europe%", europe.getNameKey())
.addAmount("%amount%", arrears)),
Messages.message("cancel"),
choices);
return (result == null) ? BoycottAction.CANCEL : result;
}
public void showBuildQueuePanel(Colony colony) {
showSubPanel(new BuildQueuePanel(freeColClient, gui, colony));
}
public void showBuildQueuePanel(Colony colony, Runnable callBack) {
FreeColPanel panel = new BuildQueuePanel(freeColClient, gui, colony);
panel.addClosingCallback(callBack);
showSubPanel(panel);
}
/**
* Displays the panel for negotiating a purchase from a settlement.
*
* @param unit The <code>Unit</code> that is buying.
* @param settlement The <code>Settlement</code> to buy from.
* @param goods The <code>Goods</code> to buy.
* @param gold The current negotiated price.
* @param canBuy True if buy is a valid option.
* @return The chosen action, buy, haggle, or cancel.
*/
public BuyAction showBuyDialog(Unit unit, Settlement settlement,
Goods goods, int gold, boolean canBuy) {
StringTemplate goodsTemplate
= StringTemplate.template("model.goods.goodsAmount")
.add("%goods%", goods.getType().getNameKey())
.addAmount("%amount%", goods.getAmount());
StringTemplate nation = settlement.getOwner().getNationName();
List<ChoiceItem<BuyAction>> choices
= new ArrayList<ChoiceItem<BuyAction>>();
choices.add(new ChoiceItem<BuyAction>(
Messages.message("buy.takeOffer"),
BuyAction.BUY, canBuy));
choices.add(new ChoiceItem<BuyAction>(
Messages.message("buy.moreGold"),
BuyAction.HAGGLE));
BuyAction result = showChoiceDialog(unit.getTile(),
Messages.message(StringTemplate.template("buy.text")
.addStringTemplate("%nation%", nation)
.addStringTemplate("%goods%", goodsTemplate)
.addAmount("%gold%", gold)),
Messages.message("buyProposition.cancel"),
choices);
return (result == null) ? BuyAction.CANCEL : result;
}
/**
* Displays the <code>LootCargoDialog</code>.
*
* @param winner The <code>Unit</code> that is looting.
* @param loot list of <code>Goods</code> to select from
* @return list of <code>Goods</code> to loot
*/
public List<Goods> showCaptureGoodsDialog(Unit winner, List<Goods> loot) {
CaptureGoodsDialog dialog = new CaptureGoodsDialog(freeColClient, gui, winner, loot);
return showFreeColDialog(dialog, winner.getTile());
}
/**
* Displays the <code>ChatPanel</code>.
*
* @see ChatPanel
*/
public void showChatPanel() {
// TODO: does it have state, or can we create a new one?
if (freeColClient.isSingleplayer()) {
return; // In single player, no chat available
}
showSubPanel(chatPanel);
}
/**
* Displays a dialog with a text and a cancel-button, in addition
* to buttons for each of the objects returned for the given list.
*
* @param tile An optional tile to make visible (not under the dialog).
* @param text The text that explains the choice for the user.
* @param cancelText The text displayed on the "cancel"-button.
* @param choices The <code>List</code> containing the ChoiceItems to
* create buttons for.
* @return The chosen object, or <i>null</i> for the cancel-button.
*/
public <T> T showChoiceDialog(Tile tile, String text, String cancelText,
List<ChoiceItem<T>> choices) {
FreeColDialog<ChoiceItem<T>> choiceDialog
= FreeColDialog.createChoiceDialog(freeColClient, gui, text, cancelText, choices);
if (choiceDialog.getHeight() > getHeight() / 3) {
choiceDialog.setSize(choiceDialog.getWidth(), (getHeight() * 2) / 3);
}
ChoiceItem<T> response = showFreeColDialog(choiceDialog, tile);
return (response == null) ? null : response.getObject();
}
public MonarchAction showChoiceMonarchActionDialog(String monarchTitle, List<ChoiceItem<MonarchAction>> actions) {
ChoiceDialog<MonarchAction> choiceDialog= new ChoiceDialog<MonarchAction>(freeColClient, gui, monarchTitle,
"Cancel", actions);
return showFreeColDialog(choiceDialog);
}
public FoundingFather showChooseFoundingFatherDialog(List<ChoiceItem<FoundingFather>> fathers, String fatherTitle) {
ChoiceDialog<FoundingFather> choiceDialog
= new ChoiceDialog<FoundingFather>(freeColClient, gui, fatherTitle, "Cancel",
fathers);
return showFreeColDialog(choiceDialog);
}
public FoundingFather showChooseFoundingFatherDialog(List<FoundingFather> ffs) {
return showFreeColDialog(new ChooseFoundingFatherDialog(freeColClient, gui, ffs));
}
/**
* Display the panel for claiming land.
*
* @param tile The <code>Tile</code> to claim.
* @param player The <code>Player</code> that is claiming.
* @param price An asking price, if any.
* @param owner The <code>Player</code> that owns the land.
* @param canAccept True if accept is a valid option.
* @return The chosen action, accept, steal or cancel.
*/
public ClaimAction showClaimDialog(Tile tile, Player player, int price,
Player owner, boolean canAccept) {
List<ChoiceItem<ClaimAction>> choices
= new ArrayList<ChoiceItem<ClaimAction>>();
choices.add(new ChoiceItem<ClaimAction>(Messages.message(StringTemplate.template("indianLand.pay")
.addAmount("%amount%", price)),
ClaimAction.ACCEPT, canAccept));
choices.add(new ChoiceItem<ClaimAction>(
Messages.message("indianLand.take"),
ClaimAction.STEAL));
ClaimAction result =
showChoiceDialog(tile,
Messages.message(StringTemplate.template("indianLand.text")
.addStringTemplate("%player%", owner.getNationName())),
Messages.message("indianLand.cancel"),
choices);
return (result == null) ? ClaimAction.CANCEL : result;
}
/**
* Displays a dialog for setting client options.
*
* @return <code>true</code> if the client options have been modified, and
* <code>false</code> otherwise.
*/
public OptionGroup showClientOptionsDialog() {
clientOptionsDialog.initialize();
clientOptionsDialogShowing = true;
OptionGroup group = showFreeColDialog(clientOptionsDialog);
clientOptionsDialogShowing = false;
freeColClient.getActionManager().update();
return group;
}
public void showColonyPanel(Colony colony, Runnable callback) {
FreeColPanel panel = new ColonyPanel(freeColClient, gui, colony);
panel.addClosingCallback(callback);
showSubPanel(panel);
}
/**
* Describe <code>showColonyPanel</code> method here.
*
* @param t a <code>Tile</code> value
*/
public void showColonyPanel(Tile t) {
if (gui.getCurrentViewMode() == ViewMode.MOVE_UNITS_MODE) {
if (t != null && t.getColony() != null
&& freeColClient.getMyPlayer().owns(t.getColony())) {
mapViewer.setFocus(t);
mapViewer.stopBlinking();
gui.showColonyPanel(t.getColony());
}
}
}
public void showColopediaPanel(String nodeId) {
showSubPanel(new ColopediaPanel(freeColClient, gui, nodeId));
}
public void showCompactLabourReport() {
showSubPanel(new CompactLabourReport(freeColClient, gui));
}
public void showCompactLabourReport(UnitData unitData) {
CompactLabourReport details = new CompactLabourReport(freeColClient, gui, unitData);
details.initialize();
addAsFrame(details);
details.requestFocus();
}
/**
* Display a dialog to confirm a declaration of independence.
*
* @return A list of names for a new nation.
*/
public List<String> showConfirmDeclarationDialog() {
return showFreeColDialog(new ConfirmDeclarationDialog(freeColClient, gui));
}
/**
* Display a dialog following declaration of independence.
*/
public void showDeclarationDialog() {
showFreeColDialog(new DeclarationDialog(freeColClient, gui));
}
public void showDifficultyDialog() {
showSubPanel(new DifficultyDialog(freeColClient, gui, freeColClient.getGame().getDifficultyLevel()));
}
public OptionGroup showDifficultyDialog(Specification specification) {
return showFreeColDialog(new DifficultyDialog(freeColClient, gui, specification));
}
/**
* Displays the <code>DumpCargoDialog</code>.
*
* @param unit The <code>Unit</code> that is dumping.
* @return A list of <code>Goods</code> to dump.
*/
public List<Goods> showDumpCargoDialog(Unit unit) {
DumpCargoDialog dumpDialog = new DumpCargoDialog(freeColClient, gui, unit);
return showFreeColDialog(dumpDialog, unit.getTile());
}
public void showEditSettlementDialog(IndianSettlement settlement) {
showFreeColDialog(new EditSettlementDialog(freeColClient, gui, settlement));
}
/**
* Shows the panel that allows the user to choose which unit will emigrate
* from Europe. This method may only be called if the user has William
* Brewster in congress.
*
* @param fountainOfYouth a <code>boolean</code> value
* @return The emigrant that was chosen by the user.
*/
public int showEmigrationPanel(boolean fountainOfYouth) {
EmigrationPanel emigrationPanel = new EmigrationPanel(freeColClient, gui);
emigrationPanel.initialize(freeColClient.getMyPlayer().getEurope(), fountainOfYouth);
return showFreeColDialog(emigrationPanel);
}
/**
* Displays one of the Europe Dialogs for Recruit, Purchase, Train.
* Closes any currently open Dialogs.
* Does not return from this method before the panel is closed.
*
* @param europeAction the type of panel to display
* @return <code>FreeColDialog.getResponseInt</code>.
*/
public int showEuropeDialog(EuropePanel.EuropeAction europeAction) {
// Close any open Europe Dialog (Recruit, Purchase, Train)
try {
if (europeOpenDialog != null) {
europeOpenDialog.setResponse(new Integer(-1));
}
} catch (NumberFormatException e) {
logger.warning("Canvas.showEuropeDialog: Invalid europeDialogType");
}
FreeColDialog<Integer> localDialog = null;
// Open new Dialog
switch (europeAction) {
case EXIT:
case UNLOAD:
case SAIL:
return -1;
case RECRUIT:
localDialog = new RecruitDialog(freeColClient, gui);
break;
case PURCHASE:
case TRAIN:
localDialog = new TrainDialog(freeColClient, gui, europeAction);
break;
}
localDialog.initialize();
europeOpenDialog = localDialog; // Set the open dialog to the class variable
int response = showFreeColDialog(localDialog);
if (europeOpenDialog == localDialog) {
europeOpenDialog = null; // Clear class variable when it's closed
}
return response;
}
/**
* Displays the <code>EuropePanel</code>.
*
* @see EuropePanel
*/
public void showEuropePanel() {
if (freeColClient.getGame() == null) {
gui.errorMessage("europe.noGame");
} else {
europePanel.initialize(freeColClient.getMyPlayer().getEurope(), freeColClient.getGame());
showSubPanel(europePanel);
}
}
/**
* Display an event panel.
*
* @param type The <code>EventType</code>.
*/
public void showEventPanel(EventType type) {
showSubPanel(new EventPanel(freeColClient, gui, type), PopupPosition.CENTERED);
}
public void showFindSettlementDialog() {
showSubPanel(new FindSettlementDialog<Canvas>(freeColClient, gui), PopupPosition.ORIGIN);
}
/**
* Displays the given dialog.
*
* @param freeColDialog The dialog to be displayed
* @return The {@link FreeColDialog#getResponse reponse} returned by
* the dialog.
*/
public <T> T showFreeColDialog(FreeColDialog<T> freeColDialog) {
return showFreeColDialog(freeColDialog, null);
}
public void showGameOptionsDialog(boolean editable, boolean loadCustomOptions) {
showSubPanel(new GameOptionsDialog(freeColClient, gui, editable, loadCustomOptions));
}
/**
* Displays the high scores panel.
*
* @param messageId An optional message to add to the high scores panel.
*/
public void showHighScoresPanel(String messageId) {
showSubPanel(new ReportHighScoresPanel(freeColClient, gui, messageId), PopupPosition.ORIGIN);
}
// A variety of special purpose panels/dialogs follow
/**
* Displays the panel of the given native settlement.
*
* @param indianSettlement The <code>IndianSettlement</code> to display.
*/
public void showIndianSettlementPanel(IndianSettlement indianSettlement) {
IndianSettlementPanel panel
= new IndianSettlementPanel(freeColClient, gui, indianSettlement);
showFreeColPanel(panel, indianSettlement.getTile());
}
/**
* Displays the panel for trading with an <code>IndianSettlement</code>.
*
* @param settlement The native settlement to trade with.
* @param canBuy Show a "buy" option.
* @param canSell Show a "sell" option.
* @param canGift Show a "gift" option.
* @return The chosen action, buy, sell, gift or cancel.
*/
public TradeAction showIndianSettlementTradeDialog(Settlement settlement,
boolean canBuy,
boolean canSell,
boolean canGift) {
ArrayList<ChoiceItem<TradeAction>> choices
= new ArrayList<ChoiceItem<TradeAction>>();
choices.add(new ChoiceItem<TradeAction>(
Messages.message("tradeProposition.toBuy"),
TradeAction.BUY, canBuy));
choices.add(new ChoiceItem<TradeAction>(
Messages.message("tradeProposition.toSell"),
TradeAction.SELL, canSell));
choices.add(new ChoiceItem<TradeAction>(
Messages.message("tradeProposition.toGift"),
TradeAction.GIFT, canGift));
TradeAction result =
showChoiceDialog(settlement.getTile(),
Messages.message(StringTemplate.template("tradeProposition.welcome")
.addStringTemplate("%nation%", settlement.getOwner().getNationName())
.addName("%settlement%", settlement.getName())),
Messages.message("tradeProposition.cancel"),
choices);
return (result == null) ? TradeAction.CANCEL : result;
}
/**
* Displays a dialog where the user may choose a file. This is the same as
* calling:
*
* <br>
* <br>
* <code>
* showLoadDialog(directory, new FileFilter[] {FreeColDialog.getFSGFileFilter()});
* </code>
*
* @param directory The directory containing the files.
* @return The <code>File</code>.
* @see FreeColDialog
*/
public File showLoadDialog(File directory) {
return showLoadDialog(directory, new FileFilter[] { FreeColDialog.getFSGFileFilter() });
}
/**
* Displays a dialog where the user may choose a file.
*
* @param directory The directory containing the files.
* @param fileFilters The file filters which the user can select in the
* dialog.
* @return The <code>File</code>.
* @see FreeColDialog
*/
public File showLoadDialog(File directory, FileFilter[] fileFilters) {
FreeColDialog<File> loadDialog = FreeColDialog.createLoadDialog(freeColClient, gui, directory, fileFilters);
File response = null;
showSubPanel(loadDialog);
for (;;) {
response = (File) loadDialog.getResponse();
if (response == null || response.isFile()) break;
gui.errorMessage("noSuchFile");
}
remove(loadDialog);
return response;
}
/**
* Displays a dialog for setting options when loading a savegame. The
* settings can be retrieved directly from {@link LoadingSavegameDialog}
* after calling this method.
*
* @param publicServer Default value.
* @param singleplayer Default value.
* @return <code>true</code> if the "ok"-button was pressed and
* <code>false</code> otherwise.
*/
public boolean showLoadingSavegameDialog(boolean publicServer, boolean singleplayer) {
loadingSavegameDialog.initialize(publicServer, singleplayer);
return showFreeColDialog(loadingSavegameDialog);
}
public void showLogFilePanel() {
showSubPanel(new ErrorPanel(freeColClient, gui));
}
public OptionGroup showMapGeneratorOptionsDialog(OptionGroup mgo, boolean editable, boolean loadCustomOptions) {
return showFreeColDialog(new MapGeneratorOptionsDialog(freeColClient, gui, mgo, editable, loadCustomOptions));
}
public Dimension showMapSizeDialog() {
return showFreeColDialog(FreeColDialog.createMapSizeDialog(freeColClient, gui));
}
/**
* Displays a number of ModelMessages.
*
* @param modelMessages
*/
public void showModelMessages(ModelMessage... modelMessages) {
List<ModelMessage> messages = filterEventPanels(modelMessages);
if (messages.size() <= 0) return;
Game game = freeColClient.getGame();
String[] messageText = new String[messages.size()];
ImageIcon[] messageIcon = new ImageIcon[messages.size()];
for (int i = 0; i < messages.size(); i++) {
messageText[i] = Messages.message(messages.get(i));
messageIcon[i] = gui.getImageIcon(game
.getMessageDisplay(messages.get(i)), false);
}
// source should be the same for all messages
FreeColGameObject source = game.getMessageSource(messages.get(0));
if ((source instanceof Europe && !europePanel.isShowing())
|| (source instanceof Colony || source instanceof WorkLocation)) {
FreeColDialog<Boolean> confirmDialog
= FreeColDialog.createConfirmDialog(freeColClient, gui, messageText, messageIcon,
Messages.message("ok"), Messages.message("display"));
if (showFreeColDialog(confirmDialog)) {
if (!isShowingSubPanel()) {
freeColClient.getInGameController().nextModelMessage();
}
} else {
if (source instanceof Europe) {
showEuropePanel();
} else if (source instanceof Colony) {
gui.showColonyPanel((Colony) source);
} else if (source instanceof WorkLocation) {
gui.showColonyPanel(((WorkLocation) source).getColony());
}
}
} else {
StringBuilder builder = new StringBuilder();
for (String s : messageText) {
builder.append(s + "\n");
}
final String message = builder.toString();
SwingUtilities.invokeLaterOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(freeColClient.getActivity(), message,
Toast.LENGTH_SHORT).show();
}
});
// showSubPanel(new InformationDialog(freeColClient, gui,
// messageText, messageIcon));
// if (!isShowingSubPanel()) {
// freeColClient.getInGameController().nextModelMessage();
// }
}
}
public boolean showMonarchPanelDialog(MonarchAction action, StringTemplate replace) {
return showFreeColDialog(new MonarchPanel(freeColClient, gui, action, replace));
}
/**
* Displays the <code>NegotiationDialog</code>.
*
* @param unit The <code>Unit</code> that is negotiating.
* @param settlement A <code>Settlement</code> that is negotiating.
* @param agreement The current <code>DiplomaticTrade</code> agreement.
* @return An updated agreement.
* @see NegotiationDialog
*/
public DiplomaticTrade showNegotiationDialog(Unit unit, Settlement settlement, DiplomaticTrade agreement) {
NegotiationDialog negotiationDialog
= new NegotiationDialog(freeColClient, gui, unit, settlement, agreement);
negotiationDialog.initialize();
return showFreeColDialog(negotiationDialog, unit.getTile());
}
/**
* Shows the <code>OpenGamePanel</code>.
*/
public void showOpenGamePanel() {
gui.errorMessage("openGame.unimplemented");
}
/**
* Display a dialog to confirm a combat.
*
* @param attacker The attacker.
* @param defender The defender.
* @param tile A <code>Tile</code> to make visible.
* @return True if the combat is to proceed.
*/
public boolean showPreCombatDialog(FreeColGameObject attacker,
FreeColGameObject defender,
Tile tile) {
return showFreeColDialog(new PreCombatDialog(freeColClient, gui, attacker, defender),
tile);
}
public void showReportCargoPanel() {
showSubPanel(new ReportCargoPanel(freeColClient, gui));
}
public void showReportColonyPanel() {
showSubPanel(new ReportColonyPanel(freeColClient, gui));
}
public void showReportContinentalCongressPanel() {
showSubPanel(new ReportContinentalCongressPanel(freeColClient, gui));
}
public void showReportEducationPanel() {
showSubPanel(new ReportEducationPanel(freeColClient, gui));
}
public void showReportExplorationPanel() {
showSubPanel(new ReportExplorationPanel(freeColClient, gui));
}
public void showReportForeignAffairPanel() {
showSubPanel(new ReportForeignAffairPanel(freeColClient, gui));
}
public void showReportHistoryPanel() {
showSubPanel(new ReportHistoryPanel(freeColClient, gui));
}
public void showReportIndianPanel() {
showSubPanel(new ReportIndianPanel(freeColClient, gui));
}
public void showReportLabourPanel() {
showSubPanel(new ReportLabourPanel(freeColClient, gui));
}
public void showReportMilitaryPanel() {
showSubPanel(new ReportMilitaryPanel(freeColClient, gui));
}
public void showReportNavalPanel() {
showSubPanel(new ReportNavalPanel(freeColClient, gui));
}
public void showReportProductionPanel() {
showSubPanel(new ReportProductionPanel(freeColClient, gui));
}
public void showReportReligiousPanel() {
showSubPanel(new ReportReligiousPanel(freeColClient, gui));
}
public void showReportRequirementsPanel() {
showSubPanel(new ReportRequirementsPanel(freeColClient, gui));
}
public void showReportTradePanel() {
showSubPanel(new ReportTradePanel(freeColClient, gui));
}
/**
* Show the new turn report.
*
* @param messages The <code>ModelMessage</code>s to show.
*/
public void showReportTurnPanel(ModelMessage... messages) {
showSubPanel(new ReportTurnPanel(freeColClient, gui, messages));
}
public int showRiverStyleDialog() {
return showFreeColDialog(new RiverStylePanel(freeColClient, gui));
}
/**
* Displays a dialog where the user may choose a filename. This is the same
* as calling:
*
* <br>
* <br>
* <code>
* showSaveDialog(directory, new FileFilter[] {FreeColDialog.getFSGFileFilter()}, defaultName);
* </code>
*
* @param directory The directory containing the files in which the user may
* overwrite.
* @param defaultName Default filename for the savegame.
* @return The <code>File</code>.
* @see FreeColDialog
*/
public File showSaveDialog(File directory, String defaultName) {
//FIXME Implement save game dialog
return new File(directory, defaultName);
// return showSaveDialog(directory, ".fsg", new FileFilter[] { FreeColDialog.getFSGFileFilter() }, defaultName);
}
/**
* Displays a dialog where the user may choose a filename.
*
* @param directory The directory containing the files in which the user may
* overwrite.
* @param standardName This extension will be added to the specified
* filename (if not added by the user).
* @param fileFilters The available file filters in the dialog.
* @param defaultName Default filename for the savegame.
* @return The <code>File</code>.
* @see FreeColDialog
*/
public File showSaveDialog(File directory, String standardName, FileFilter[] fileFilters, String defaultName) {
FreeColDialog<File> saveDialog = FreeColDialog.createSaveDialog(freeColClient, gui, directory, standardName, fileFilters, defaultName);
return showFreeColDialog(saveDialog);
}
/**
* Displays a dialog that asks the user what he wants to do with his scout
* in the foreign colony.
*
* @param colony The <code>Colony</code> to be scouted.
* @param unit The <code>Unit</code> that is scouting.
* @param canNegotiate True if negotation is a valid choice.
* @return The selected action, either negotiate, spy, attack or cancel.
*/
public ScoutColonyAction showScoutForeignColonyDialog(Colony colony,
Unit unit,
boolean canNegotiate) {
List<ChoiceItem<ScoutColonyAction>> choices
= new ArrayList<ChoiceItem<ScoutColonyAction>>();
// We cannot negotiate with the REF
choices.add(new ChoiceItem<ScoutColonyAction>(
Messages.message("scoutColony.negotiate"),
ScoutColonyAction.FOREIGN_COLONY_NEGOTIATE, canNegotiate));
choices.add(new ChoiceItem<ScoutColonyAction>(
Messages.message("scoutColony.spy"),
ScoutColonyAction.FOREIGN_COLONY_SPY));
choices.add(new ChoiceItem<ScoutColonyAction>(
Messages.message("scoutColony.attack"),
ScoutColonyAction.FOREIGN_COLONY_ATTACK));
StringTemplate template = StringTemplate.template("scoutColony.text")
.addStringTemplate("%unit%", Messages.getLabel(unit))
.addName("%colony%", colony.getName());
ScoutColonyAction result =
showChoiceDialog(unit.getTile(), Messages.message(template),
Messages.message("cancel"), choices);
return (result == null) ? ScoutColonyAction.CANCEL : result;
}
/**
* Displays a dialog that asks the user what he wants to do with
* his scout in a native settlement.
*
* @param settlement The <code>IndianSettlement</code> to be scouted.
* @param number The number of settlements in the settlement owner nation.
* @return The chosen action, speak, tribute, attack or cancel.
*/
public ScoutIndianSettlementAction showScoutIndianSettlementDialog(IndianSettlement settlement, String number) {
StringBuilder text = new StringBuilder(400);
Player owner = settlement.getOwner();
text.append(Messages.message(StringTemplate.template(settlement.getAlarmLevelMessageId(freeColClient.getMyPlayer()))
.addStringTemplate("%nation%", owner.getNationName())));
text.append("\n\n");
text.append(Messages.message(StringTemplate.template("scoutSettlement.greetings")
.addStringTemplate("%nation%", settlement.getOwner().getNationName())
.addName("%settlement%", settlement.getName())
.add("%number%", number)
.add("%settlementType%", ((IndianNationType) owner.getNationType()).getSettlementTypeKey(true))));
text.append(" ");
if (settlement.getLearnableSkill() != null) {
text.append(Messages.message(StringTemplate.template("scoutSettlement.skill")
.add("%skill%", settlement.getLearnableSkill().getNameKey())));
text.append(" ");
}
GoodsType[] wantedGoods = settlement.getWantedGoods();
if (wantedGoods.length > 0) {
StringTemplate template
= StringTemplate.template("scoutSettlement.trade."
+ Integer.toString(wantedGoods.length));
for (int i = 0; i < wantedGoods.length; i++) {
if (wantedGoods[i] != null) {
template.add("%goods" + Integer.toString(i+1) + "%",
wantedGoods[i].getNameKey());
}
}
text.append(Messages.message(template) + "\n\n");
}
List<ChoiceItem<ScoutIndianSettlementAction>> choices
= new ArrayList<ChoiceItem<ScoutIndianSettlementAction>>();
choices.add(new ChoiceItem<ScoutIndianSettlementAction>(
Messages.message("scoutSettlement.speak"),
ScoutIndianSettlementAction.INDIAN_SETTLEMENT_SPEAK));
choices.add(new ChoiceItem<ScoutIndianSettlementAction>(
Messages.message("scoutSettlement.tribute"),
ScoutIndianSettlementAction.INDIAN_SETTLEMENT_TRIBUTE));
choices.add(new ChoiceItem<ScoutIndianSettlementAction>(
Messages.message("scoutSettlement.attack"),
ScoutIndianSettlementAction.INDIAN_SETTLEMENT_ATTACK));
ScoutIndianSettlementAction result = showChoiceDialog(settlement.getTile(),
text.toString(),
Messages.message("cancel"),
choices);
return (result == null) ? ScoutIndianSettlementAction.CANCEL : result;
}
public int showSelectAmountDialog(GoodsType goodsType, int available, int defaultAmount, boolean needToPay) {
return showFreeColDialog(new SelectAmountDialog(freeColClient, gui, goodsType, available, defaultAmount, needToPay));
}
/**
* Display a dialog allowing the user to select a destination for
* a given unit.
*
* @param unit The <code>Unit</code> to select a destination for.
* @return A destination for the unit, or null.
*/
public Location showSelectDestinationDialog(Unit unit) {
return showFreeColDialog(new SelectDestinationDialog(freeColClient, gui, unit),
unit.getTile());
}
/**
* Displays the panel for negotiating a sale to a settlement.
*
* @param unit The <code>Unit</code> that is selling.
* @param settlement The <code>Settlement</code> to sell to.
* @param goods The <code>Goods</code> to sell.
* @param gold The current negotiated price.
* @return The chosen action, sell, gift or haggle, or null.
*/
public SellAction showSellDialog(Unit unit, Settlement settlement,
Goods goods, int gold) {
StringTemplate goodsTemplate
= StringTemplate.template("model.goods.goodsAmount")
.add("%goods%", goods.getType().getNameKey())
.addAmount("%amount%", goods.getAmount());
StringTemplate nation = settlement.getOwner().getNationName();
List<ChoiceItem<SellAction>> choices
= new ArrayList<ChoiceItem<SellAction>>();
choices.add(new ChoiceItem<SellAction>(
Messages.message("sell.takeOffer"),
SellAction.SELL));
choices.add(new ChoiceItem<SellAction>(
Messages.message("sell.moreGold"),
SellAction.HAGGLE));
choices.add(new ChoiceItem<SellAction>(
Messages.message(StringTemplate.template("sell.gift")
.addStringTemplate("%goods%", goodsTemplate)),
SellAction.GIFT));
SellAction result = showChoiceDialog(unit.getTile(),
Messages.message(StringTemplate.template("sell.text")
.addStringTemplate("%nation%", nation)
.addStringTemplate("%goods%", goodsTemplate)
.addAmount("%gold%", gold)),
Messages.message("sellProposition.cancel"),
choices);
return (result == null) ? SellAction.CANCEL : result;
}
/**
* Displays the <code>ServerListPanel</code>.
*
* @param username The username that should be used when connecting to one
* of the servers on the list.
* @param serverList The list containing the servers retrieved from the
* metaserver.
* @see ServerListPanel
*/
public void showServerListPanel(String username, ArrayList<ServerInfo> serverList) {
serverListPanel.initialize(username, serverList);
showSubPanel(serverListPanel);
}
public void showSettlement(Settlement s) {
if (s instanceof Colony) {
if (s.getOwner().equals(freeColClient.getMyPlayer())) {
gui.showColonyPanel((Colony) s);
} else if (FreeCol.isInDebugMode()) {
debugForeignColony(s);
}
} else if (s instanceof IndianSettlement) {
showIndianSettlementPanel((IndianSettlement) s);
} else {
throw new IllegalStateException("Bogus settlement");
}
}
/**
* Displays a dialog with a text and a cancel-button, in addition
* to buttons for each of the objects in the list.
*
* @param tile An optional tile to make visible (not under the dialog).
* @param text The text that explains the choice for the user.
* @param cancelText The text displayed on the "cancel"-button.
* @param objects The List containing the objects to create buttons for.
* @return The chosen object, or <i>null</i> for the cancel-button.
*/
public <T> T showSimpleChoiceDialog(Tile tile,
String text, String cancelText,
List<T> objects) {
List<ChoiceItem<T>> choices = new ArrayList<ChoiceItem<T>>();
for (T object : objects) {
choices.add(new ChoiceItem<T>(object));
}
return showChoiceDialog(tile,
Messages.message(text),
Messages.message(cancelText),
choices);
}
public void showStatisticsPanel() {
showSubPanel(new StatisticsPanel(freeColClient, gui));
}
public void showTilePanel(Tile tile) {
showSubPanel(new TilePanel(freeColClient, gui, tile));
}
/**
* Shows a tile popup.
*
* @param tile The Tile where the popup occurred.
* @param x The x-coordinate on the screen where the popup needs to be
* placed.
* @param y The y-coordinate on the screen where the popup needs to be
* placed.
* @see TilePopup
*/
public void showTilePopup(Tile tile, int x, int y) {
if (tile == null)
return;
TilePopup tp = new TilePopup(freeColClient, gui, tile);
if (tp.hasItem()) {
tp.show(this, x, y);
tp.repaint();
} else if (tile.isExplored()) {
showTilePanel(tile);
}
}
/**
* Display a dialog to select a trade route for a unit.
*
* @param unit The <code>Unit</code> to select a trade route for.
* @return A trade route, or null.
*/
public TradeRoute showTradeRouteDialog(TradeRoute tradeRoute, Tile tile) {
return showFreeColDialog(new TradeRouteDialog(freeColClient, gui, tradeRoute),
tile);
}
public boolean showTradeRouteInputDialog(TradeRoute newRoute) {
return showFreeColDialog(new TradeRouteInputDialog(freeColClient, gui, newRoute));
}
/**
* Displays a dialog that asks the user what he wants to do with his
* missionary in the indian settlement.
*
* @param unit The <code>Unit</code> speaking to the settlement.
* @param settlement The <code>IndianSettlement</code> being visited.
* @param canEstablish Is establish a valid option.
* @param canDenounce Is denounce a valid option.
* @return The chosen action, establish mission, denounce, incite
* or cancel.
*/
public MissionaryAction showUseMissionaryDialog(Unit unit,
IndianSettlement settlement,
boolean canEstablish,
boolean canDenounce) {
List<ChoiceItem<MissionaryAction>> choices
= new ArrayList<ChoiceItem<MissionaryAction>>();
choices.add(new ChoiceItem<MissionaryAction>(
Messages.message("missionarySettlement.establish"),
MissionaryAction.ESTABLISH_MISSION, canEstablish));
choices.add(new ChoiceItem<MissionaryAction>(
Messages.message("missionarySettlement.heresy"),
MissionaryAction.DENOUNCE_HERESY, canDenounce));
choices.add(new ChoiceItem<MissionaryAction>(
Messages.message("missionarySettlement.incite"),
MissionaryAction.INCITE_INDIANS));
String messageId = settlement.getAlarmLevelMessageId(unit.getOwner());
StringBuilder introText
= new StringBuilder(Messages.message(StringTemplate.template(messageId)
.addStringTemplate("%nation%", settlement.getOwner().getNationName())));
introText.append("\n\n");
introText.append(Messages.message(StringTemplate.template("missionarySettlement.question")
.addName("%settlement%", settlement.getName())));
MissionaryAction result = showChoiceDialog(unit.getTile(),
introText.toString(),
Messages.message("cancel"),
choices);
return (result == null) ? MissionaryAction.CANCEL : result;
}
public void showVictoryPanel() {
showSubPanel(new VictoryPanel(freeColClient, gui));
}
public boolean showWarehouseDialog(Colony colony) {
return showFreeColDialog(new WarehouseDialog(freeColClient, gui,
colony));
}
public void showWorkProductionPanel(Unit unit) {
showSubPanel(new WorkProductionPanel(freeColClient, gui, unit));
}
public void updateGameOptions() {
startGamePanel.updateGameOptions();
}
public void updateMapGeneratorOptions() {
startGamePanel.updateMapGeneratorOptions();
}
/**
* Updates the sizes of the components on this Canvas.
*/
public void updateSizes() {
if (oldSize == null) {
oldSize = getSize();
}
if (oldSize.width != getWidth() || oldSize.height != getHeight()) {
MapControlsAction mca = (MapControlsAction) freeColClient
.getActionManager().getFreeColAction(MapControlsAction.id);
MapControls mc = mca.getMapControls();
if (mc != null && mc.isShowing()) {
mc.removeFromComponent(this);
mc.addToComponent(this);
mapControls = mc;
}
mapViewer.setSize(getSize());
mapViewer.forceReposition();
oldSize = getSize();
}
}
void displayChat(String senderNme, String message, boolean privateChat) {
startGamePanel.displayChat(senderNme, message, privateChat);
}
/**
* Refreshes this Canvas visually.
*/
void refresh() {
repaint(0, 0, getWidth(), getHeight());
}
/**
* Adds a component on this Canvas inside a frame. Removes the
* statuspanel if visible (and <code>comp != statusPanel</code>).
*
* @param comp The component to add to this ToEuropePanel.
* @param toolBox Should be set to true if the resulting frame
* is used as a toolbox (that is: it should not be counted
* as a frame).
* @param popupPosition a <code>PopupPosition</code> value
* @return The <code>JInternalFrame</code> that was created and added.
*/
private JInternalFrame addAsFrame(JComponent comp, boolean toolBox, PopupPosition popupPosition) {
final int FRAME_EMPTY_SPACE = 60;
final JInternalFrame f = (toolBox) ? new ToolBoxFrame() : new JInternalFrame();
if (f.getContentPane() instanceof JComponent) {
JComponent c = (JComponent) f.getContentPane();
c.setOpaque(false);
c.setBorder(null);
}
if (comp.getBorder() != null) {
if (comp.getBorder() instanceof EmptyBorder) {
f.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
} else {
f.setBorder(comp.getBorder());
comp.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
} else {
f.setBorder(null);
}
final FrameMotionListener fml = new FrameMotionListener(f);
comp.addMouseMotionListener(fml);
comp.addMouseListener(fml);
if (f.getUI() instanceof BasicInternalFrameUI) {
BasicInternalFrameUI biu = (BasicInternalFrameUI) f.getUI();
biu.setNorthPane(null);
biu.setSouthPane(null);
biu.setWestPane(null);
biu.setEastPane(null);
}
f.getContentPane().add(comp);
f.setOpaque(false);
f.pack();
int width = f.getWidth();
int height = f.getHeight();
if (width > getWidth() - FRAME_EMPTY_SPACE) {
width = Math.min(width, getWidth());
}
if (height > getHeight() - FRAME_EMPTY_SPACE) {
height = Math.min(height, getHeight());
}
f.setSize(width, height);
Point p = null;
if (comp instanceof FreeColPanel
&& freeColClient.getClientOptions().getBoolean("model.option.rememberPanelPositions")
&& (p = ((FreeColPanel) comp).getSavedPosition()) != null) {
// Sanity check stuff coming out of client options.
if (p.getX() < 0
|| p.getX() >= getWidth() - f.getWidth()
|| p.getY() < 0
|| p.getY() >= getHeight() - f.getHeight()) {
p = null;
}
}
if (p == null) {
switch (popupPosition) {
case CENTERED:
f.setLocation((getWidth() - f.getWidth()) / 2,
(getHeight() - f.getHeight()) / 2);
break;
case CENTERED_LEFT:
f.setLocation((getWidth() - f.getWidth()) / 4,
(getHeight() - f.getHeight()) / 2);
break;
case CENTERED_RIGHT:
f.setLocation(((getWidth() - f.getWidth()) * 3) / 4,
(getHeight() - f.getHeight()) / 2);
break;
case ORIGIN:
default:
f.setLocation(0, 0);
break;
}
} else {
f.setLocation(p);
}
add(f, MODAL_LAYER);
f.setName(comp.getClass().getSimpleName());
f.setFrameIcon(null);
f.setVisible(true);
f.setResizable(true);
try {
f.setSelected(true);
} catch (Exception e) {
}
return f;
}
/**
* Adds a component centered on this Canvas. Removes the statuspanel if
* visible (and <code>comp != statusPanel</code>).
*
* @param comp The component to add to this ToEuropePanel.
* @param i The layer to add the component to (see JLayeredPane).
*/
private void addCentered(Component comp, Integer i) {
comp.setLocation((getWidth() - comp.getWidth()) / 2,
(getHeight() - comp.getHeight()) / 2);
add(comp, i);
}
/**
* Create key bindings for all actions.
*/
private void createKeyBindings() {
for (Option option : freeColClient.getActionManager().getOptions()) {
FreeColAction action = (FreeColAction) option;
getInputMap().put(action.getAccelerator(), action.getId());
getActionMap().put(action.getId(), action);
}
}
/**
* Filters out and displays the EventPanel messages.
*
* @param messages The list of <code>ModelMessage</code> to filter.
* @return The list of messages without any EventPanel messages.
*/
private List<ModelMessage> filterEventPanels(ModelMessage[] messages) {
final String eventMatch = "EventPanel.";
List<ModelMessage> normal = new ArrayList<ModelMessage>();
for (int i = 0; i < messages.length; i++) {
String id = messages[i].getId();
if (id.startsWith(eventMatch)) {
id = id.substring(eventMatch.length());
final EventType e = EventType.valueOf(id);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showEventPanel(e);
}
});
} else {
normal.add(messages[i]);
}
}
return normal;
}
/**
* Gets any currently displayed colony panel for the specified colony.
*
* @param colony The <code>Colony</code> to check.
* @return A currently displayed colony panel, or null if not found.
*/
private ColonyPanel getColonyPanel(Colony colony) {
for (Component c1 : getComponents()) {
if (c1 instanceof JInternalFrame) {
for (Component c2 : ((JInternalFrame) c1).getContentPane().getComponents()) {
if (c2 instanceof ColonyPanel
&& ((ColonyPanel) c2).getColony() == colony) {
return (ColonyPanel) c2;
}
}
}
}
return null;
}
/**
* Gets the internal frame for the given component.
*
* @param c The component.
* @return The given component if this is an internal frame or the first
* parent that is an internal frame. Returns <code>null</code> if
* no internal frame is found.
*/
private JInternalFrame getInternalFrame(final Component c) {
Component temp = c;
while (temp != null && !(temp instanceof JInternalFrame)) {
temp = temp.getParent();
}
return (JInternalFrame) temp;
}
/**
* Given a tile to be made visible, determine a position to popup
* a panel.
*
* @param tile A <code>Tile</code> to be made visible.
* @return A <code>PopupPosition</code> for a panel to be displayed.
*/
private PopupPosition getPopupPosition(Tile tile) {
if (tile == null)
return PopupPosition.CENTERED;
int where = mapViewer.setOffsetFocus(tile);
return (where > 0) ? PopupPosition.CENTERED_LEFT
: (where < 0) ? PopupPosition.CENTERED_RIGHT
: PopupPosition.CENTERED;
}
/**
* Displays the given dialog, making sure a tile is visible.
*
* @param freeColDialog The dialog to be displayed
* @param tile A <code>Tile</code> to make visible (not under the dialog!)
* @return The {@link FreeColDialog#getResponse reponse} returned by
* the dialog.
*/
private <T> T showFreeColDialog(FreeColDialog<T> freeColDialog, Tile tile) {
showFreeColPanel(freeColDialog, tile);
T response = freeColDialog.getResponse();
remove(freeColDialog);
return response;
}
/**
* Displays the given panel, making sure a tile is visible.
*
* @param panel The panel to be displayed
* @param tile A <code>Tile</code> to make visible (not under the panel!)
*/
private void showFreeColPanel(FreeColPanel panel, Tile tile) {
showSubPanel(panel, getPopupPosition(tile));
}
/**
* Displays a <code>FreeColPanel</code>.
* @param panel <code>FreeColPanel</code>, panel to show
*/
private void showSubPanel(FreeColPanel panel) {
showSubPanel(panel, PopupPosition.CENTERED);
}
/**
* Displays a <code>FreeColPanel</code> at a generalized position.
*
* @param panel <code>FreeColPanel</code>, panel to show
* @param popupPosition <code>PopupPosition</code> The generalized
* position to place the panel.
*/
private void showSubPanel(FreeColPanel panel, PopupPosition popupPosition) {
repaint();
addAsFrame(panel, false, popupPosition);
panel.requestFocus();
}
}