mirror of https://github.com/FreeCol/freecol.git
2746 lines
90 KiB
Java
2746 lines
90 KiB
Java
/**
|
|
* Copyright (C) 2002-2015 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.awt.Color;
|
|
import java.awt.Component;
|
|
import java.awt.Dimension;
|
|
import java.awt.Font;
|
|
import java.awt.Graphics;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.GraphicsDevice;
|
|
import java.awt.Image;
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.awt.RenderingHints;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.KeyListener;
|
|
import java.awt.event.MouseListener;
|
|
import java.awt.event.MouseMotionListener;
|
|
import java.awt.font.TextLayout;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.io.File;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.stream.Collectors;
|
|
|
|
import javax.swing.ImageIcon;
|
|
import javax.swing.JComponent;
|
|
import javax.swing.JDesktopPane;
|
|
import javax.swing.JInternalFrame;
|
|
import javax.swing.JLayeredPane;
|
|
import javax.swing.JMenuBar;
|
|
import javax.swing.JMenuItem;
|
|
import javax.swing.SwingUtilities;
|
|
import javax.swing.UIManager;
|
|
import javax.swing.border.EmptyBorder;
|
|
import javax.swing.filechooser.FileFilter;
|
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
|
import javax.swing.plaf.basic.BasicInternalFrameUI;
|
|
|
|
import net.sf.freecol.FreeCol;
|
|
import net.sf.freecol.client.ClientOptions;
|
|
import net.sf.freecol.client.FreeColClient;
|
|
import net.sf.freecol.client.gui.action.FreeColAction;
|
|
import net.sf.freecol.client.gui.panel.*;
|
|
import net.sf.freecol.client.gui.panel.LabourData.UnitData;
|
|
import net.sf.freecol.common.ServerInfo;
|
|
import net.sf.freecol.common.i18n.Messages;
|
|
import net.sf.freecol.common.model.Colony;
|
|
import net.sf.freecol.common.model.DiplomaticTrade;
|
|
import net.sf.freecol.common.model.Direction;
|
|
import net.sf.freecol.common.model.FoundingFather;
|
|
import net.sf.freecol.common.model.FreeColGameObject;
|
|
import net.sf.freecol.common.model.FreeColObject;
|
|
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.HighScore;
|
|
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.PathNode;
|
|
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.TypeCountMap;
|
|
import net.sf.freecol.common.model.Unit;
|
|
import net.sf.freecol.common.model.UnitType;
|
|
import net.sf.freecol.common.option.IntegerOption;
|
|
import net.sf.freecol.common.option.Option;
|
|
import net.sf.freecol.common.option.OptionGroup;
|
|
import net.sf.freecol.common.resources.ResourceManager;
|
|
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* <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.common.i18n i18n} to get
|
|
* localized text. Dialogs return results, and may be modal or non-modal.
|
|
*/
|
|
public final class Canvas extends JDesktopPane {
|
|
|
|
private static final Logger logger = Logger.getLogger(Canvas.class.getName());
|
|
|
|
/** A wrapper class for non-modal dialogs. */
|
|
private class DialogCallback<T> implements Runnable {
|
|
|
|
/** The dialog to show. */
|
|
private final FreeColDialog<T> fcd;
|
|
|
|
/** An optional tile to guide the dialog placement. */
|
|
private final Tile tile;
|
|
|
|
/** The handler for the dialog response. */
|
|
private final DialogHandler<T> handler;
|
|
|
|
|
|
/**
|
|
* Constructor.
|
|
*/
|
|
public DialogCallback(FreeColDialog<T> fcd, Tile tile,
|
|
DialogHandler<T> handler) {
|
|
this.fcd = fcd;
|
|
this.tile = tile;
|
|
this.handler = handler;
|
|
}
|
|
|
|
|
|
// Implement Runnable
|
|
|
|
@Override
|
|
public void run() {
|
|
// Display the dialog...
|
|
viewFreeColDialog(fcd, tile);
|
|
// ...and use another thread to wait for a dialog response...
|
|
new Thread(fcd.toString()) {
|
|
@Override
|
|
public void run() {
|
|
while (!fcd.responded()) {
|
|
try {
|
|
Thread.sleep(500);
|
|
} catch (InterruptedException e) {}
|
|
}
|
|
// ...before handling the result.
|
|
handler.handle(fcd.getResponse());
|
|
}
|
|
}.start();
|
|
}
|
|
};
|
|
|
|
private static enum PopupPosition {
|
|
ORIGIN,
|
|
CENTERED,
|
|
CENTERED_LEFT,
|
|
CENTERED_RIGHT,
|
|
}
|
|
|
|
/** Number of tries to find a clear spot on the canvas. */
|
|
private static final int MAXTRY = 3;
|
|
|
|
/** A class for frames being used as tool boxes. */
|
|
private static class ToolBoxFrame extends JInternalFrame {}
|
|
|
|
/** The game client. */
|
|
private final FreeColClient freeColClient;
|
|
|
|
/** The parent GUI. */
|
|
private final SwingGUI gui;
|
|
|
|
private final GraphicsDevice graphicsDevice;
|
|
|
|
/** The parent frame, either a window or the full screen. */
|
|
private FreeColFrame frame;
|
|
|
|
private boolean windowed;
|
|
|
|
private MainPanel mainPanel;
|
|
|
|
private final StartGamePanel startGamePanel;
|
|
|
|
private final StatusPanel statusPanel;
|
|
|
|
private final ChatPanel chatPanel;
|
|
|
|
private final ChatDisplay chatDisplay;
|
|
|
|
private final MapViewer mapViewer;
|
|
|
|
private Point gotoDragPoint;
|
|
|
|
private GrayLayer greyLayer;
|
|
|
|
private final ServerListPanel serverListPanel;
|
|
|
|
/** Used to detect resizing. */
|
|
private Dimension oldSize = null;
|
|
|
|
private boolean clientOptionsDialogShowing = false;
|
|
|
|
private LoadingSavegameDialog loadingSavegameDialog;
|
|
|
|
/** Filters for loadable game files. */
|
|
private FileFilter[] fileFilters = null;
|
|
|
|
/** The dialogs in view. */
|
|
private final List<FreeColDialog<?>> dialogs = new ArrayList<>();
|
|
|
|
|
|
/**
|
|
* The constructor to use.
|
|
*
|
|
* @param freeColClient The <code>FreeColClient</code> for the game.
|
|
* @param graphicsDevice The used graphics device.
|
|
* @param gui The gui.
|
|
* @param desiredSize The desired size of the frame.
|
|
* @param mapViewer The object responsible of drawing the map onto
|
|
* this component.
|
|
*/
|
|
Canvas(final FreeColClient freeColClient,
|
|
final GraphicsDevice graphicsDevice,
|
|
final SwingGUI gui,
|
|
final Dimension desiredSize,
|
|
MapViewer mapViewer) {
|
|
this.freeColClient = freeColClient;
|
|
this.gui = gui;
|
|
this.graphicsDevice = graphicsDevice;
|
|
chatDisplay = new ChatDisplay();
|
|
this.mapViewer = mapViewer;
|
|
|
|
// Determine if windowed mode should be used and set the window size.
|
|
Rectangle windowBounds = null;
|
|
if (desiredSize == null) {
|
|
if(graphicsDevice.isFullScreenSupported()) {
|
|
windowed = false;
|
|
logger.info("Full screen mode used.");
|
|
} else {
|
|
windowed = true;
|
|
logger.warning("Full screen mode not supported.");
|
|
System.err.println(Messages.message("client.fullScreen"));
|
|
}
|
|
} else {
|
|
windowed = true;
|
|
if(desiredSize.width > 0 && desiredSize.height > 0) {
|
|
windowBounds = new Rectangle(desiredSize);
|
|
logger.info("Windowed mode using desired window size of " + desiredSize);
|
|
} else {
|
|
logger.info("Windowed mode used.");
|
|
}
|
|
}
|
|
|
|
setDoubleBuffered(true);
|
|
setOpaque(false);
|
|
setLayout(null);
|
|
|
|
startGamePanel = new StartGamePanel(freeColClient);
|
|
serverListPanel = new ServerListPanel(freeColClient,
|
|
freeColClient.getConnectController());
|
|
statusPanel = new StatusPanel(freeColClient);
|
|
chatPanel = new ChatPanel(freeColClient);
|
|
|
|
setFocusable(true);
|
|
setFocusTraversalKeysEnabled(false);
|
|
|
|
createKeyBindings();
|
|
createFrame(null, windowBounds);
|
|
mapViewer.startCursorBlinking();
|
|
logger.info("Canvas created.");
|
|
}
|
|
|
|
boolean isWindowed() {
|
|
return windowed;
|
|
}
|
|
|
|
/**
|
|
* Change the windowed mode.
|
|
*/
|
|
void changeWindowedMode() {
|
|
// Clean up the old frame
|
|
JMenuBar menuBar = null;
|
|
Rectangle windowBounds = null;
|
|
if (frame != null) {
|
|
menuBar = frame.getJMenuBar();
|
|
if (windowed) {
|
|
windowBounds = frame.getBounds();
|
|
}
|
|
frame.setVisible(false);
|
|
frame.dispose();
|
|
}
|
|
windowed = !windowed;
|
|
|
|
createFrame(menuBar, windowBounds);
|
|
}
|
|
|
|
private void createFrame(JMenuBar menuBar, Rectangle windowBounds) {
|
|
// FIXME: Check this:
|
|
// User might have moved window to new screen in a
|
|
// multi-screen setup, so make this.gd point to the current screen.
|
|
frame = new FreeColFrame(freeColClient, graphicsDevice,
|
|
menuBar, this, windowed, windowBounds);
|
|
updateSizes();
|
|
frame.setVisible(true);
|
|
}
|
|
|
|
/**
|
|
* Start the GUI for the map editor.
|
|
*/
|
|
void startMapEditorGUI() {
|
|
if (frame == null) return;
|
|
|
|
// We may need to reset the zoom value to the default value
|
|
gui.resetMapZoom();
|
|
|
|
frame.setMapEditorMenuBar();
|
|
showMapEditorTransformPanel();
|
|
|
|
CanvasMapEditorMouseListener listener
|
|
= new CanvasMapEditorMouseListener(freeColClient, this);
|
|
addMouseListener(listener);
|
|
addMouseMotionListener(listener);
|
|
}
|
|
|
|
/**
|
|
* Quit the GUI. All that is required is to exit the full screen.
|
|
*/
|
|
void quit() throws Exception {
|
|
if (frame != null && !windowed) {
|
|
frame.exitFullScreen();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In game initializations.
|
|
*/
|
|
void initializeInGame() {
|
|
if (frame == null) return;
|
|
frame.setInGameMenuBar();
|
|
}
|
|
|
|
/**
|
|
* Reset the menu bar.
|
|
*/
|
|
void resetMenuBar() {
|
|
if (frame == null) return;
|
|
frame.resetMenuBar();
|
|
}
|
|
|
|
/**
|
|
* Update the menu bar.
|
|
*/
|
|
void updateMenuBar() {
|
|
if (frame == null) return;
|
|
frame.updateMenuBar();
|
|
}
|
|
|
|
/**
|
|
* Scroll the map in the given direction.
|
|
*
|
|
* @param direction The <code>Direction</code> to scroll in.
|
|
* @return True if scrolling occurred.
|
|
*/
|
|
boolean scrollMap(Direction direction) {
|
|
return mapViewer.scrollMap(direction);
|
|
}
|
|
|
|
/**
|
|
* Converts the given screen coordinates to Map coordinates.
|
|
* It checks to see to which Tile the given pixel 'belongs'.
|
|
*
|
|
* @param x The x-coordinate in pixels.
|
|
* @param y The y-coordinate in pixels.
|
|
* @return The Tile that is located at the given position on the screen.
|
|
*/
|
|
Tile convertToMapTile(int x, int y) {
|
|
return mapViewer.convertToMapTile(x, y);
|
|
}
|
|
|
|
/**
|
|
* Get the view mode.
|
|
*
|
|
* @return The view mode.
|
|
*/
|
|
public int getViewMode() {
|
|
return mapViewer.getViewMode();
|
|
}
|
|
|
|
/**
|
|
* Gets the active unit.
|
|
*
|
|
* @return The <code>Unit</code>.
|
|
*/
|
|
Unit getActiveUnit() {
|
|
return mapViewer.getActiveUnit();
|
|
}
|
|
|
|
/**
|
|
* Set the current active unit path.
|
|
*
|
|
* @param path The current <code>PathNode</code>.
|
|
*/
|
|
void setCurrentPath(PathNode path) {
|
|
mapViewer.setCurrentPath(path);
|
|
}
|
|
|
|
/**
|
|
* Sets the path of the active unit to display it.
|
|
*/
|
|
void updateCurrentPathForActiveUnit() {
|
|
mapViewer.updateCurrentPathForActiveUnit();
|
|
}
|
|
|
|
/**
|
|
* Gets the point at which the map was clicked for a drag.
|
|
*
|
|
* @return The Point where the mouse was initially clicked.
|
|
*/
|
|
Point getDragPoint() {
|
|
return gotoDragPoint;
|
|
}
|
|
|
|
/**
|
|
* Sets the point at which the map was clicked for a drag.
|
|
*
|
|
* @param x The mouse's x position.
|
|
* @param y The mouse's y position.
|
|
*/
|
|
void setDragPoint(int x, int y) {
|
|
gotoDragPoint = new Point(x, y);
|
|
}
|
|
|
|
/**
|
|
* Checks if there is currently a goto operation on the mapboard.
|
|
*
|
|
* @return True if a goto operation is in progress.
|
|
*/
|
|
boolean isGotoStarted() {
|
|
return mapViewer.isGotoStarted();
|
|
}
|
|
|
|
/**
|
|
* Gets the path to be drawn on the map.
|
|
*
|
|
* @return The path that should be drawn on the map or
|
|
* <code>null</code> if no path should be drawn.
|
|
*/
|
|
PathNode getGotoPath() {
|
|
return mapViewer.getGotoPath();
|
|
}
|
|
|
|
/**
|
|
* Sets the path to be drawn on the map.
|
|
*
|
|
* @param gotoPath The path that should be drawn on the map
|
|
* or <code>null</code> if no path should be drawn.
|
|
*/
|
|
void setGotoPath(PathNode gotoPath) {
|
|
mapViewer.setGotoPath(gotoPath);
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Starts a goto operation.
|
|
*/
|
|
void startGoto() {
|
|
setCursor((java.awt.Cursor)UIManager.get("cursor.go"));
|
|
mapViewer.startGoto();
|
|
refresh();
|
|
}
|
|
|
|
/**
|
|
* Stops any ongoing goto operation.
|
|
*/
|
|
void stopGoto() {
|
|
setCursor(null);
|
|
mapViewer.stopGoto();
|
|
refresh();
|
|
}
|
|
|
|
|
|
// Internals
|
|
|
|
/**
|
|
* Adds a component on this Canvas inside a frame.
|
|
*
|
|
* @param comp The component to add to the canvas.
|
|
* @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 preferred <code>PopupPosition</code>.
|
|
* @param resizable Whether this component can be resized.
|
|
* @return The <code>JInternalFrame</code> that was created and added.
|
|
*/
|
|
private JInternalFrame addAsFrame(JComponent comp, boolean toolBox,
|
|
PopupPosition popupPosition,
|
|
boolean resizable) {
|
|
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(Utility.blankBorder(10, 10, 10, 10));
|
|
} else {
|
|
f.setBorder(comp.getBorder());
|
|
comp.setBorder(Utility.blankBorder(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 = chooseLocation(comp, width, height, popupPosition);
|
|
f.setLocation(p);
|
|
this.add(f, MODAL_LAYER);
|
|
f.setName(comp.getClass().getSimpleName());
|
|
|
|
f.setFrameIcon(null);
|
|
f.setVisible(true);
|
|
f.setResizable(resizable);
|
|
try {
|
|
f.setSelected(true);
|
|
} catch (java.beans.PropertyVetoException e) {}
|
|
|
|
return f;
|
|
}
|
|
|
|
/**
|
|
* Adds a component centered on this Canvas.
|
|
*
|
|
* @param comp The <code>Component</code> to add to this canvas.
|
|
* @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);
|
|
|
|
this.add(comp, i);
|
|
}
|
|
|
|
/**
|
|
* Adds a component to this Canvas. Removes the statusPanel if
|
|
* visible (and <code>comp != statusPanel</code>).
|
|
*
|
|
* @param comp The <code>Component</code> to add to this canvas.
|
|
* @param i The layer to add the component to (see JLayeredPane).
|
|
*/
|
|
private void addToCanvas(Component comp, Integer i) {
|
|
if (comp != statusPanel && !(comp instanceof JMenuItem)
|
|
&& statusPanel.isVisible()) {
|
|
removeFromCanvas(statusPanel);
|
|
}
|
|
|
|
try {
|
|
super.add(comp, (i == null) ? JLayeredPane.DEFAULT_LAYER : i);
|
|
} catch (Exception e) {
|
|
logger.log(Level.WARNING, "addToCanvas(" + comp + ", " + i
|
|
+ ") failed.", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Choose a location for a component.
|
|
*
|
|
* @param comp The <code>Component</code> to place.
|
|
* @param width The component width to use.
|
|
* @param height The component height to use.
|
|
* @param popupPosition An optional <code>PopupPosition</code> hint.
|
|
* @return A suitable <code>Point</code> to place the component.
|
|
*/
|
|
private Point chooseLocation(Component comp, int width, int height,
|
|
PopupPosition popupPosition) {
|
|
Point p = null;
|
|
if ((comp instanceof FreeColPanel)
|
|
&& (p = getSavedPosition(comp)) != null) {
|
|
// Sanity check stuff coming out of client options.
|
|
if (p.getX() < 0
|
|
|| p.getX() >= getWidth() - width
|
|
|| p.getY() < 0
|
|
|| p.getY() >= getHeight() - height) {
|
|
p = null;
|
|
}
|
|
}
|
|
int x = 0, y = 0;
|
|
if (p != null) {
|
|
x = (int)p.getX();
|
|
y = (int)p.getY();
|
|
} else if (popupPosition != null) {
|
|
switch (popupPosition) {
|
|
case CENTERED:
|
|
x = (getWidth() - width) / 2;
|
|
y = (getHeight() - height) / 2;
|
|
break;
|
|
case CENTERED_LEFT:
|
|
x = (getWidth() - width) / 4;
|
|
y = (getHeight() - height) / 2;
|
|
break;
|
|
case CENTERED_RIGHT:
|
|
x = ((getWidth() - width) * 3) / 4;
|
|
y = (getHeight() - height) / 2;
|
|
break;
|
|
case ORIGIN:
|
|
x = y = 0;
|
|
break;
|
|
}
|
|
}
|
|
if ((p = getClearSpace(x, y, width, height, MAXTRY)) != null
|
|
&& p.x >= 0 && p.x < getWidth()
|
|
&& p.y >= 0 && p.y < getHeight()) {
|
|
x = p.x;
|
|
y = p.y;
|
|
}
|
|
return new Point(x, y);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Try to find some free space on the canvas for a component,
|
|
* starting at x,y.
|
|
*
|
|
* @param x A starting x coordinate.
|
|
* @param y A starting y coordinate.
|
|
* @param w The component width to use.
|
|
* @param h The component height to use.
|
|
* @return A <code>Point</code> to place the component at or null
|
|
* on failure.
|
|
*/
|
|
private Point getClearSpace(final int x, final int y,
|
|
final int w, final int h, int tries) {
|
|
final Rectangle bounds = this.getBounds();
|
|
if (!bounds.contains(x, y)) return null;
|
|
|
|
tries = 3 * tries + 1; // 3 new candidates per level
|
|
List<Point> todo = new ArrayList<>();
|
|
Point p = new Point(x, y);
|
|
todo.add(p);
|
|
|
|
List<Component> allComponents = Arrays.stream(this.getComponents())
|
|
.filter(c -> !(c instanceof GrayLayer) && c.isValid())
|
|
.collect(Collectors.toList());
|
|
for (FreeColDialog<?> fcd : dialogs) allComponents.add(fcd);
|
|
|
|
// Find the position with the least overlap
|
|
int bestScore = Integer.MAX_VALUE;
|
|
Point best = p;
|
|
while (!todo.isEmpty()) {
|
|
p = todo.remove(0);
|
|
Rectangle r = new Rectangle(p.x, p.y, w, h);
|
|
if (!bounds.contains(r)) {
|
|
continue;
|
|
}
|
|
|
|
// Find the most overlapping component at this position,
|
|
// as well as the globally least.
|
|
int foundScore = 0;
|
|
Component found = null;
|
|
for (Component c : allComponents) {
|
|
if (c.getBounds().intersects(r)) {
|
|
Rectangle rr = c.getBounds().intersection(r);
|
|
int score = (int)Math.round(rr.getWidth() * rr.getHeight());
|
|
if (foundScore < score) {
|
|
foundScore = score;
|
|
found = c;
|
|
}
|
|
}
|
|
}
|
|
if (found == null) { // Can not improve on no overlap, return now
|
|
return p;
|
|
}
|
|
if (bestScore > foundScore) {
|
|
bestScore = foundScore;
|
|
best = p;
|
|
}
|
|
// Guarantee eventual completion
|
|
if (--tries <= 0) break;
|
|
|
|
int n = todo.size(),
|
|
// Some alternative new positions
|
|
// 0: move right/down to avoid the collision
|
|
// 1: move as far as possible right/down
|
|
// 2: wrap back to the far left
|
|
x0 = found.getX() + found.getWidth() + 1,
|
|
y0 = found.getY() + found.getHeight() + 1,
|
|
x1 = bounds.x + bounds.width - w - 1,
|
|
y1 = bounds.y + bounds.height - h - 1,
|
|
x2 = bounds.x,
|
|
y2 = bounds.y;
|
|
boolean x0ok = bounds.contains(x0 + w, y),
|
|
y0ok = bounds.contains(x, y0 + h),
|
|
x1ok = bounds.contains(x1, y),
|
|
y1ok = bounds.contains(x, y1);
|
|
todo.add(n, new Point((x0ok) ? x0 : (x1ok) ? x1 : x2,
|
|
(y0ok) ? y0 : (y1ok) ? y1 : y2));
|
|
todo.add(n, new Point(x, (y0ok) ? y0 : (y1ok) ? y1 : y2));
|
|
todo.add(n, new Point((x0ok) ? x0 : (x1ok) ? x1 : x2, y));
|
|
}
|
|
return best;
|
|
}
|
|
|
|
/**
|
|
* Gets any currently displayed colony panel for the specified colony.
|
|
*
|
|
* This is distinct from {@link #getExistingFreeColPanel} because
|
|
* there can be multiple ColonyPanels.
|
|
*
|
|
* @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 <code>Component</code>.
|
|
* @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;
|
|
}
|
|
|
|
/**
|
|
* Make a tile visible, then determine corresponding 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 setOffsetFocus(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;
|
|
}
|
|
|
|
/**
|
|
* Gets the saved position of a component.
|
|
*
|
|
* @param comp The <code>Component</code> to use.
|
|
* @return The saved position as a <code>Point</code>, or null if no
|
|
* saved position is found.
|
|
*/
|
|
private Point getSavedPosition(Component comp) {
|
|
final ClientOptions co = freeColClient.getClientOptions();
|
|
if (co == null) return null;
|
|
try {
|
|
if (!co.getBoolean(ClientOptions.REMEMBER_PANEL_POSITIONS)) {
|
|
return null;
|
|
}
|
|
} catch (Exception e) {}
|
|
|
|
String className = comp.getClass().getName();
|
|
try {
|
|
return new Point(co.getInteger(className + ".x"),
|
|
co.getInteger(className + ".y"));
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the saved size of a component.
|
|
*
|
|
* @param comp The <code>Component</code> to use.
|
|
* @return A <code>Dimension</code> for the component or null if
|
|
* no saved size is found.
|
|
*/
|
|
private Dimension getSavedSize(Component comp) {
|
|
final ClientOptions co = freeColClient.getClientOptions();
|
|
if (co == null) return null;
|
|
try {
|
|
if (!co.getBoolean(ClientOptions.REMEMBER_PANEL_SIZES)) {
|
|
return null;
|
|
}
|
|
} catch (Exception e) {}
|
|
|
|
String className = comp.getClass().getName();
|
|
try {
|
|
return new Dimension(co.getInteger(className + ".w"),
|
|
co.getInteger(className + ".h"));
|
|
} catch (Exception e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the file filters to filter for saved games.
|
|
*
|
|
* @return File filters for the FreeCol save game extension.
|
|
*/
|
|
private FileFilter[] getFileFilters() {
|
|
if (fileFilters == null) {
|
|
String s = Messages.message("filter.savedGames");
|
|
fileFilters = new FileFilter[] {
|
|
new FileNameExtensionFilter(s, FreeCol.FREECOL_SAVE_EXTENSION)
|
|
};
|
|
}
|
|
return fileFilters;
|
|
}
|
|
|
|
/**
|
|
* A component is closing. Some components need position and size
|
|
* to be saved.
|
|
*
|
|
* @param c The closing <code>Component</code>.
|
|
* @param frame The enclosing <code>JInternalFrame</code>.
|
|
*/
|
|
private void notifyClose(Component c, JInternalFrame frame) {
|
|
if (frame == null) return;
|
|
|
|
if (c instanceof FreeColPanel) {
|
|
FreeColPanel fcp = (FreeColPanel)c;
|
|
fcp.firePropertyChange("closing", false, true);
|
|
|
|
savePosition(fcp, frame.getLocation());
|
|
saveSize(fcp, fcp.getSize());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove the panels derived from the EuropePanel.
|
|
*/
|
|
private void removeEuropeanSubpanels() {
|
|
FreeColPanel panel;
|
|
if ((panel = getExistingFreeColPanel(RecruitPanel.class)) != null)
|
|
removeFromCanvas(panel);
|
|
if ((panel = getExistingFreeColPanel(PurchasePanel.class)) != null)
|
|
removeFromCanvas(panel);
|
|
if ((panel = getExistingFreeColPanel(TrainPanel.class)) != null)
|
|
removeFromCanvas(panel);
|
|
}
|
|
|
|
/**
|
|
* Save an <code>int</code> value to the saved ClientOptions,
|
|
* using the name of the components class plus the given key as
|
|
* and identifier.
|
|
*
|
|
* @param className The class name for the component.
|
|
* @param key The key to save.
|
|
* @param value The value to save.
|
|
*/
|
|
private void saveInteger(String className, String key, int value) {
|
|
if (freeColClient != null
|
|
&& freeColClient.getClientOptions() != null) {
|
|
Option o = freeColClient.getClientOptions()
|
|
.getOption(className + key);
|
|
if (o == null) {
|
|
Specification specification = (freeColClient.getGame() == null)
|
|
? null : freeColClient.getGame().getSpecification();
|
|
IntegerOption io = new IntegerOption(className + key,
|
|
specification);
|
|
io.setValue(value);
|
|
freeColClient.getClientOptions().add(io);
|
|
} else if (o instanceof IntegerOption) {
|
|
((IntegerOption)o).setValue(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save the position of a component.
|
|
*
|
|
* @param comp The <code>Component</code> to use.
|
|
* @param position The position to save.
|
|
*/
|
|
private void savePosition(Component comp, Point position) {
|
|
try {
|
|
if (!freeColClient.getClientOptions()
|
|
.getBoolean(ClientOptions.REMEMBER_PANEL_POSITIONS)) return;
|
|
} catch (Exception e) {}
|
|
|
|
String className = comp.getClass().getName();
|
|
saveInteger(className, ".x", position.x);
|
|
saveInteger(className, ".y", position.y);
|
|
}
|
|
|
|
/**
|
|
* Save the size of a component.
|
|
*
|
|
* @param comp The <code>Component</code> to use.
|
|
* @param size The <code>Dimension</code> to save.
|
|
*/
|
|
private void saveSize(Component comp, Dimension size) {
|
|
try {
|
|
if (!freeColClient.getClientOptions()
|
|
.getBoolean(ClientOptions.REMEMBER_PANEL_SIZES)) return;
|
|
} catch (Exception e) {}
|
|
|
|
String className = comp.getClass().getName();
|
|
saveInteger(className, ".w", size.width);
|
|
saveInteger(className, ".h", size.height);
|
|
}
|
|
|
|
/**
|
|
* Restart blinking on the map. Switching it on again needs to check
|
|
* for the presence of other dialogs.
|
|
*/
|
|
private void restartBlinking() {
|
|
if (mapViewer.getViewMode() != GUI.MOVE_UNITS_MODE) return;
|
|
for (FreeColDialog<?> f : dialogs) {
|
|
if (f.isModal()) return;
|
|
}
|
|
mapViewer.restartBlinking();
|
|
}
|
|
|
|
/**
|
|
* Stop blinking on the map.
|
|
*/
|
|
private void stopBlinking() {
|
|
mapViewer.stopBlinking();
|
|
}
|
|
|
|
/**
|
|
* Displays the given dialog, optionally making sure a tile is visible.
|
|
*
|
|
* @param freeColDialog The dialog to be displayed
|
|
* @param tile An optional <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) {
|
|
viewFreeColDialog(freeColDialog, tile);
|
|
T response = freeColDialog.getResponse();
|
|
remove(freeColDialog);
|
|
dialogRemove(freeColDialog);
|
|
if (freeColDialog.isModal()) restartBlinking();
|
|
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!)
|
|
* @param resizable Should the panel be resizable?
|
|
*/
|
|
private void showFreeColPanel(FreeColPanel panel, Tile tile,
|
|
boolean resizable) {
|
|
showSubPanel(panel, setOffsetFocus(tile), resizable);
|
|
}
|
|
|
|
/**
|
|
* Displays a <code>FreeColPanel</code>.
|
|
*
|
|
* @param panel <code>FreeColPanel</code>, panel to show
|
|
* @param resizable Should the panel be resizable?
|
|
*/
|
|
private void showSubPanel(FreeColPanel panel, boolean resizable) {
|
|
showSubPanel(panel, PopupPosition.CENTERED, resizable);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
* @param resizable Should the panel be resizable?
|
|
*/
|
|
private void showSubPanel(FreeColPanel panel, PopupPosition popupPosition,
|
|
boolean resizable) {
|
|
repaint();
|
|
addAsFrame(panel, false, popupPosition, resizable);
|
|
panel.requestFocus();
|
|
}
|
|
|
|
|
|
// Public API
|
|
|
|
/**
|
|
* Adds a component to this Canvas.
|
|
*
|
|
* @param comp The <code>Component</code> to add.
|
|
* @return The component argument.
|
|
*/
|
|
@Override
|
|
public Component add(Component comp) {
|
|
this.add(comp, JLayeredPane.DEFAULT_LAYER);
|
|
return comp;
|
|
}
|
|
|
|
/**
|
|
* Adds a component to this Canvas.
|
|
*
|
|
* @param comp The <code>Component</code> to add to this canvas.
|
|
* @param i The layer to add the component to (see JLayeredPane).
|
|
*/
|
|
public void add(Component comp, Integer i) {
|
|
addToCanvas(comp, i);
|
|
gui.updateMenuBar();
|
|
}
|
|
|
|
/**
|
|
* Closes all the menus that are currently open.
|
|
*/
|
|
void closeMenus() {
|
|
for (JInternalFrame frame : getAllFrames()) {
|
|
for (Component c : frame.getContentPane().getComponents()) {
|
|
notifyClose(c, frame);
|
|
}
|
|
frame.dispose();
|
|
}
|
|
while (!dialogs.isEmpty()) {
|
|
FreeColDialog<?> dialog = dialogs.remove(0);
|
|
dialog.dispose();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes the {@link MainPanel}.
|
|
*/
|
|
void closeMainPanel() {
|
|
if (mainPanel != null) {
|
|
remove(mainPanel);
|
|
mainPanel = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes the <code>StatusPanel</code>.
|
|
*
|
|
* @see #showStatusPanel
|
|
*/
|
|
void closeStatusPanel() {
|
|
if (statusPanel.isVisible()) {
|
|
remove(statusPanel);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if this <code>Canvas</code> contains any in game components.
|
|
*
|
|
* @return <code>true</code> if there is any in game components.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Tells that a chat message was received.
|
|
*
|
|
* @param message The chat message.
|
|
*/
|
|
void displayChatMessage(GUIMessage message) {
|
|
chatDisplay.addMessage(message);
|
|
repaint(0, 0, getWidth(), getHeight());
|
|
}
|
|
|
|
/**
|
|
* Add a dialog to the current dialog list.
|
|
*
|
|
* @param fcd The dialog to add.
|
|
*/
|
|
private void dialogAdd(FreeColDialog<?> fcd) {
|
|
dialogs.add(fcd);
|
|
}
|
|
|
|
/**
|
|
* Remove a dialog from the current dialog list.
|
|
*
|
|
* @param fcd The dialog to remove.
|
|
*/
|
|
void dialogRemove(FreeColDialog<?> fcd) {
|
|
dialogs.remove(fcd);
|
|
}
|
|
|
|
/**
|
|
* Gets a currently displayed FreeColPanel of a given type.
|
|
*
|
|
* @param type The type of <code>FreeColPanel</code> to look for.
|
|
* @return A currently displayed <code>FreeColPanel</code> of the
|
|
* requested type, or null if none found.
|
|
*/
|
|
private <T extends FreeColPanel> T getExistingFreeColPanel(Class<T> type) {
|
|
for (Component c1 : getComponents()) {
|
|
if (c1 instanceof JInternalFrame) {
|
|
for (Component c2 : ((JInternalFrame)c1).getContentPane()
|
|
.getComponents()) {
|
|
try {
|
|
T ret = type.cast(c2);
|
|
if (ret != null) {
|
|
final JInternalFrame jif = (JInternalFrame)c1;
|
|
SwingUtilities.invokeLater(() -> {
|
|
jif.toFront();
|
|
jif.repaint();
|
|
});
|
|
return ret;
|
|
}
|
|
} catch (ClassCastException cce) {}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Gets the last <code>LoadingSavegameDialog</code>.
|
|
*
|
|
* FIXME: clean this up
|
|
*
|
|
* @return The <code>LoadingSavegameDialog</code>.
|
|
*/
|
|
LoadingSavegameDialog getLoadingSavegameDialog() {
|
|
return loadingSavegameDialog;
|
|
}
|
|
|
|
/**
|
|
* Get any panel this <code>Canvas</code> is displaying.
|
|
*
|
|
* @return A <code>Component</code> the <code>Canvas</code> is
|
|
* displaying, or null if none found.
|
|
*/
|
|
Component getShowingSubPanel() {
|
|
for (Component c : getComponents()) {
|
|
if (c instanceof ToolBoxFrame) {
|
|
continue;
|
|
}
|
|
if (c instanceof JInternalFrame) {
|
|
return c;
|
|
} else if (c instanceof JInternalFrame.JDesktopIcon) {
|
|
return c;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Checks if a client options dialog is present.
|
|
*
|
|
* @return True if the client options are showing.
|
|
*/
|
|
boolean isClientOptionsDialogShowing() {
|
|
return clientOptionsDialogShowing;
|
|
}
|
|
|
|
/**
|
|
* Checks if mapboard actions should be enabled.
|
|
*
|
|
* @return <code>true</code> if no internal frames are open.
|
|
*/
|
|
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.
|
|
*/
|
|
boolean isShowingSubPanel() {
|
|
return getShowingSubPanel() != null;
|
|
}
|
|
|
|
/**
|
|
* Refresh this canvas.
|
|
*/
|
|
void refresh() {
|
|
repaint(0, 0, getWidth(), getHeight());
|
|
}
|
|
|
|
/**
|
|
* Removes the given component from this canvas.
|
|
*
|
|
* @param comp The <code>Component</code> to remove.
|
|
*/
|
|
public void removeFromCanvas(Component comp) {
|
|
if (comp == null) return;
|
|
|
|
final Rectangle updateBounds = comp.getBounds();
|
|
final JInternalFrame frame = getInternalFrame(comp);
|
|
notifyClose(comp, frame);
|
|
if (frame != null && frame != comp) {
|
|
frame.dispose();
|
|
} else {
|
|
// Java 1.7.0 as seen on Fedora with:
|
|
// Java version: 1.7.0_40
|
|
// Java WM version: 24.0-b56
|
|
// crashes here deep in the java libraries.
|
|
try {
|
|
super.remove(comp);
|
|
} catch (Exception e) {
|
|
logger.log(Level.WARNING, "Java crash", e);
|
|
}
|
|
}
|
|
repaint(updateBounds.x, updateBounds.y,
|
|
updateBounds.width, updateBounds.height);
|
|
}
|
|
|
|
/**
|
|
* Removes components that is only used when in game.
|
|
*/
|
|
void removeInGameComponents() {
|
|
// remove listeners, they will be added when launching the new game...
|
|
KeyListener[] keyListeners = getKeyListeners();
|
|
for (KeyListener keyListener : keyListeners) {
|
|
removeKeyListener(keyListener);
|
|
}
|
|
|
|
MouseListener[] mouseListeners = getMouseListeners();
|
|
for (MouseListener mouseListener : mouseListeners) {
|
|
removeMouseListener(mouseListener);
|
|
}
|
|
|
|
MouseMotionListener[] mouseMotionListeners = getMouseMotionListeners();
|
|
for (MouseMotionListener mouseMotionListener : mouseMotionListeners) {
|
|
removeMouseMotionListener(mouseMotionListener);
|
|
}
|
|
|
|
for (Component c : getComponents()) {
|
|
removeFromCanvas(c);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set preferred size to saved size, or to the given
|
|
* <code>Dimension</code> if no saved size was found. Call this
|
|
* method in the constructor of a FreeColPanel in order to
|
|
* remember its size and position.
|
|
*
|
|
* @param comp The <code>Component</code> to use.
|
|
* @param d The <code>Dimension</code> to use as default.
|
|
*/
|
|
void restoreSavedSize(Component comp, Dimension d) {
|
|
final Dimension pref = comp.getPreferredSize();
|
|
final Dimension sugg = (d == null) ? pref : d;
|
|
boolean save = false;
|
|
|
|
Dimension size = getSavedSize(comp);
|
|
if (size == null) {
|
|
size = new Dimension(pref);
|
|
save = true;
|
|
}
|
|
|
|
// Fix up broken/outdated saved sizes
|
|
if(size.width < sugg.width) {
|
|
size.width = sugg.width;
|
|
save = true;
|
|
}
|
|
if(size.height < sugg.height) {
|
|
size.height = sugg.height;
|
|
save = true;
|
|
}
|
|
if(size.width < pref.width) {
|
|
size.width = pref.width;
|
|
save = true;
|
|
}
|
|
if(size.height < pref.height) {
|
|
size.height = pref.height;
|
|
save = true;
|
|
}
|
|
|
|
if(save) {
|
|
saveSize(comp, size);
|
|
}
|
|
|
|
if (!pref.equals(size)) {
|
|
comp.setPreferredSize(size);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes all panels, changes the background and shows the main menu.
|
|
*/
|
|
void returnToTitle() {
|
|
// FIXME: 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();
|
|
showMainPanel(null);
|
|
repaint();
|
|
}
|
|
|
|
void setupMouseListeners() {
|
|
addMouseListener(new CanvasMouseListener(freeColClient, this));
|
|
addMouseMotionListener(new CanvasMouseMotionListener(freeColClient, this));
|
|
}
|
|
|
|
/**
|
|
* Updates the sizes of the components on this Canvas.
|
|
*/
|
|
private void updateSizes() {
|
|
if (oldSize == null
|
|
|| oldSize.width != getWidth()
|
|
|| oldSize.height != getHeight()) {
|
|
gui.updateMapControlsInCanvas();
|
|
mapViewer.setSize(getSize());
|
|
mapViewer.forceReposition();
|
|
oldSize = getSize();
|
|
}
|
|
}
|
|
|
|
|
|
// Override JComponent
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void paintComponent(Graphics g) {
|
|
updateSizes();
|
|
Graphics2D g2d = (Graphics2D) g;
|
|
chatDisplay.removeOldMessages();
|
|
|
|
Dimension size = getSize();
|
|
if ((freeColClient.getGame() != null)
|
|
&& (freeColClient.getGame().getMap() != null)
|
|
&& (mapViewer.getFocus() != null)
|
|
&& freeColClient.isInGame()) {
|
|
/* ingame view */
|
|
|
|
// paint map
|
|
mapViewer.displayMap(g2d);
|
|
|
|
// Grey out the map if it is not my turn (and a multiplayer game).
|
|
if (!freeColClient.isMapEditor() && freeColClient.getGame() != null
|
|
&& !freeColClient.currentPlayerIsMyPlayer()) {
|
|
if (greyLayer == null) {
|
|
greyLayer = new GrayLayer(freeColClient);
|
|
}
|
|
if (greyLayer.getParent() == null) {
|
|
add(greyLayer, JLayeredPane.DRAG_LAYER);
|
|
}
|
|
greyLayer.setBounds(0, 0, size.width, size.height);
|
|
greyLayer.setPlayer(freeColClient.getGame().getCurrentPlayer());
|
|
} else {
|
|
if (greyLayer != null && greyLayer.getParent() != null) {
|
|
removeFromCanvas(greyLayer);
|
|
}
|
|
}
|
|
|
|
// paint chat display
|
|
chatDisplay.display(g2d, mapViewer.getImageLibrary(), size);
|
|
|
|
} else {
|
|
if (!freeColClient.isMapEditor()) {
|
|
/* main menu */
|
|
// TODO: Check if its right to sometimes have an unfocused map
|
|
// ingame and end up here after clicking outside map.
|
|
|
|
final String bgImageKey = "image.flavor.Canvas.map";
|
|
if (ResourceManager.hasImageResource(bgImageKey)) {
|
|
// Get the background without scaling, to avoid wasting
|
|
// memory needlessly keeping an unbounded number of rescaled
|
|
// versions of the largest image in FreeCol, forever.
|
|
final Image bgImage = ResourceManager.getImage(bgImageKey);
|
|
// Draw background image with scaling.
|
|
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
|
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
g2d.drawImage(bgImage, 0, 0, size.width, size.height, this);
|
|
String versionStr = "v. " + FreeCol.getVersion();
|
|
Font oldFont = g2d.getFont();
|
|
Color oldColor = g2d.getColor();
|
|
Font newFont = oldFont.deriveFont(Font.BOLD);
|
|
TextLayout layout = new TextLayout(versionStr, newFont,
|
|
g2d.getFontRenderContext());
|
|
Rectangle2D bounds = layout.getBounds();
|
|
float x = size.width - (float) bounds.getWidth() - 5;
|
|
float y = size.height - (float) bounds.getHeight();
|
|
g2d.setColor(Color.white);
|
|
layout.draw(g2d, x, y);
|
|
g2d.setFont(oldFont);
|
|
g2d.setColor(oldColor);
|
|
} else {
|
|
g2d.setColor(Color.BLACK);
|
|
g2d.fillRect(0, 0, size.width, size.height);
|
|
}
|
|
|
|
} else {
|
|
/* map editor??? */
|
|
g2d.setColor(Color.BLACK);
|
|
g2d.fillRect(0, 0, size.width, size.height);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Override Container
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public void remove(Component comp) {
|
|
removeFromCanvas(comp);
|
|
gui.updateMenuBar();
|
|
if (comp != statusPanel && !isShowingSubPanel()) {
|
|
requestFocus();
|
|
}
|
|
}
|
|
|
|
|
|
// Special handling for the startGamePanel.
|
|
|
|
/**
|
|
* Refresh the player's table (called when a new player is added
|
|
* from PreGameInputHandler.addPlayer).
|
|
*/
|
|
void refreshPlayersTable() {
|
|
startGamePanel.refreshPlayersTable();
|
|
}
|
|
|
|
/**
|
|
* Update the game options in the start panel.
|
|
*/
|
|
void updateGameOptions() {
|
|
startGamePanel.updateGameOptions();
|
|
}
|
|
|
|
/**
|
|
* Update the map generator options in the start panel.
|
|
*/
|
|
void updateMapGeneratorOptions() {
|
|
startGamePanel.updateMapGeneratorOptions();
|
|
}
|
|
|
|
|
|
// Dialog display
|
|
|
|
/**
|
|
* Displays a modal dialog with text and a choice of options.
|
|
*
|
|
* @param tile An optional <code>Tile</code> to make visible (not
|
|
* under the dialog!)
|
|
* @param obj An object that explains the choice for the user.
|
|
* @param icon An optional icon to display.
|
|
* @param cancelKey Key for the text of the optional cancel button.
|
|
* @param choices The <code>List</code> containing the ChoiceItems to
|
|
* create buttons for.
|
|
* @return The corresponding member of the values array to the selected
|
|
* option.
|
|
*/
|
|
<T> T showChoiceDialog(Tile tile, Object obj, ImageIcon icon,
|
|
String cancelKey, List<ChoiceItem<T>> choices) {
|
|
FreeColChoiceDialog<T> fcd
|
|
= new FreeColChoiceDialog<>(freeColClient, frame, true, obj, icon,
|
|
cancelKey, choices);
|
|
return showFreeColDialog(fcd, tile);
|
|
}
|
|
|
|
/**
|
|
* Displays a modal dialog with a text and a ok/cancel option.
|
|
*
|
|
* @param tile An optional <code>Tile</code> to make visible (not
|
|
* under the dialog!)
|
|
* @param obj An object that explains the choice for the user.
|
|
* @param icon An optional icon to display.
|
|
* @param okKey The text displayed on the "ok"-button.
|
|
* @param cancelKey The text displayed on the "cancel"-button.
|
|
* @return True if the user clicked the "ok"-button.
|
|
*/
|
|
boolean showConfirmDialog(Tile tile, Object obj, ImageIcon icon,
|
|
String okKey, String cancelKey) {
|
|
FreeColConfirmDialog fcd
|
|
= new FreeColConfirmDialog(freeColClient, frame, true, obj, icon,
|
|
okKey, cancelKey);
|
|
return showFreeColDialog(fcd, tile);
|
|
}
|
|
|
|
/**
|
|
* Displays a modal dialog with a text field and a ok/cancel option.
|
|
*
|
|
* @param tile An optional tile to make visible (not under the dialog).
|
|
* @param template A <code>StringTemplate</code> that explains the
|
|
* action to the user.
|
|
* @param defaultValue The default value appearing in the text field.
|
|
* @param okKey A key displayed on the "ok"-button.
|
|
* @param cancelKey A key displayed on the optional "cancel"-button.
|
|
* @return The text the user entered, or null if cancelled.
|
|
*/
|
|
String showInputDialog(Tile tile, StringTemplate template,
|
|
String defaultValue,
|
|
String okKey, String cancelKey) {
|
|
FreeColStringInputDialog fcd
|
|
= new FreeColStringInputDialog(freeColClient, frame, true,
|
|
Messages.message(template),
|
|
defaultValue, okKey, cancelKey);
|
|
return showFreeColDialog(fcd, tile);
|
|
}
|
|
|
|
/**
|
|
* Displays the given dialog, optionally making sure a tile is visible.
|
|
*
|
|
* @param freeColDialog The dialog to be displayed
|
|
* @param tile An optional <code>Tile</code> to make visible (not
|
|
* under the dialog!)
|
|
*/
|
|
private <T> void viewFreeColDialog(final FreeColDialog<T> freeColDialog,
|
|
Tile tile) {
|
|
PopupPosition pp = setOffsetFocus(tile);
|
|
|
|
// TODO: Remove compatibility code when all non-modal dialogs
|
|
// have been converted into panels.
|
|
if(!freeColDialog.isModal()) {
|
|
int canvasWidth = getWidth();
|
|
int dialogWidth = freeColDialog.getWidth();
|
|
if(dialogWidth*2 <= canvasWidth) {
|
|
Point location = freeColDialog.getLocation();
|
|
if(pp == PopupPosition.CENTERED_LEFT) {
|
|
freeColDialog.setLocation(location.x - canvasWidth/4,
|
|
location.y);
|
|
} else if(pp == PopupPosition.CENTERED_RIGHT) {
|
|
freeColDialog.setLocation(location.x + canvasWidth/4,
|
|
location.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
dialogAdd(freeColDialog);
|
|
if (freeColDialog.isModal()) stopBlinking();
|
|
freeColDialog.requestFocus();
|
|
freeColDialog.setVisible(true);
|
|
}
|
|
|
|
|
|
// Simple front ends to display each panel or dialog.
|
|
|
|
void removeTradeRoutePanel(TradeRoutePanel panel) {
|
|
remove(panel);
|
|
TradeRouteInputPanel trip
|
|
= getExistingFreeColPanel(TradeRouteInputPanel.class);
|
|
if (trip != null) trip.cancelTradeRoute();
|
|
}
|
|
|
|
/**
|
|
* Display the AboutPanel.
|
|
*/
|
|
void showAboutPanel() {
|
|
showSubPanel(new AboutPanel(freeColClient), false);
|
|
}
|
|
|
|
/**
|
|
* Show the BuildQueuePanel for a given colony.
|
|
*
|
|
* @param colony The <code>Colony</code> to show the build queue of.
|
|
*/
|
|
void showBuildQueuePanel(Colony colony) {
|
|
BuildQueuePanel panel = getExistingFreeColPanel(BuildQueuePanel.class);
|
|
if (panel == null || panel.getColony() != colony) {
|
|
showSubPanel(new BuildQueuePanel(freeColClient, colony), true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show a build queue panel, with a special callback when it is closed.
|
|
*
|
|
* @param colony The <code>Colony</code> to show the build queue of.
|
|
* @param callBack The <code>Runnable</code> that is run when the
|
|
* panel closes.
|
|
*/
|
|
void showBuildQueuePanel(Colony colony, Runnable callBack) {
|
|
FreeColPanel panel = new BuildQueuePanel(freeColClient, colony);
|
|
panel.addClosingCallback(callBack);
|
|
showSubPanel(panel, true);
|
|
}
|
|
|
|
/**
|
|
* Display the <code>CaptureGoodsDialog</code>.
|
|
*
|
|
* @param unit The <code>Unit</code> capturing goods.
|
|
* @param gl The list of <code>Goods</code> to choose from.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showCaptureGoodsDialog(Unit unit, List<Goods> gl,
|
|
DialogHandler<List<Goods>> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new CaptureGoodsDialog(freeColClient, frame, unit, gl),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>ChatPanel</code>.
|
|
*
|
|
* @see ChatPanel
|
|
*/
|
|
void showChatPanel() {
|
|
// FIXME: does it have state, or can we create a new one?
|
|
if (freeColClient.isSinglePlayer()) return; // chat with who?
|
|
showSubPanel(chatPanel, true);
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>ChooseFoundingFatherDialog</code>.
|
|
*
|
|
* @param ffs The <code>FoundingFather</code>s to choose from.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showChooseFoundingFatherDialog(List<FoundingFather> ffs,
|
|
DialogHandler<FoundingFather> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new ChooseFoundingFatherDialog(freeColClient, frame, ffs),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Displays a dialog for setting client options.
|
|
*
|
|
* @return The modified <code>OptionGroup</code>, or null if not modified.
|
|
*/
|
|
OptionGroup showClientOptionsDialog() {
|
|
ClientOptionsDialog dialog = new ClientOptionsDialog(freeColClient, frame);
|
|
OptionGroup group = null;
|
|
clientOptionsDialogShowing = true;
|
|
try {
|
|
group = showFreeColDialog(dialog, null);
|
|
} finally {
|
|
clientOptionsDialogShowing = false;
|
|
}
|
|
return group;
|
|
}
|
|
|
|
/**
|
|
* Displays the colony panel of the given <code>Colony</code>.
|
|
* Defends against duplicates as this can duplicate messages
|
|
* generated by multiple property change listeners registered
|
|
* against the same colony.
|
|
*
|
|
* @param colony The colony whose panel needs to be displayed.
|
|
* @param unit An optional <code>Unit</code> to select within the panel.
|
|
* @return The colony panel.
|
|
* @see ColonyPanel
|
|
*/
|
|
public ColonyPanel showColonyPanel(Colony colony, Unit unit) {
|
|
ColonyPanel panel = getColonyPanel(colony);
|
|
if (panel == null) {
|
|
panel = new ColonyPanel(freeColClient, colony);
|
|
showFreeColPanel(panel, colony.getTile(), true);
|
|
} else {
|
|
panel.requestFocus();
|
|
}
|
|
if (unit != null) panel.setSelectedUnit(unit);
|
|
return panel;
|
|
}
|
|
|
|
/**
|
|
* Show the colopedia entry for a given node.
|
|
*
|
|
* @param nodeId The node identifier to display.
|
|
*/
|
|
void showColopediaPanel(String nodeId) {
|
|
showSubPanel(new ColopediaPanel(freeColClient, nodeId), true);
|
|
}
|
|
|
|
/**
|
|
* Show a <code>ColorChooserPanel</code>.
|
|
*
|
|
* @param al An <code>ActionListener</code> to handle panel button
|
|
* presses.
|
|
* @return The <code>ColorChooserPanel</code> created.
|
|
*/
|
|
ColorChooserPanel showColorChooserPanel(ActionListener al) {
|
|
ColorChooserPanel ccp = new ColorChooserPanel(freeColClient, al);
|
|
showFreeColPanel(ccp, null, false);
|
|
return ccp;
|
|
}
|
|
|
|
/**
|
|
* Show the compact labour report.
|
|
*/
|
|
void showCompactLabourReport() {
|
|
CompactLabourReport details = new CompactLabourReport(freeColClient);
|
|
details.initialize();
|
|
showSubPanel(details, false);
|
|
|
|
}
|
|
|
|
/**
|
|
* Show the compat labour report for the specified unit data.
|
|
*
|
|
* @param unitData The <code>UnitData</code> to display.
|
|
*/
|
|
void showCompactLabourReport(UnitData unitData) {
|
|
CompactLabourReport details = new CompactLabourReport(freeColClient,
|
|
unitData);
|
|
details.initialize();
|
|
showSubPanel(details, false);
|
|
}
|
|
|
|
/**
|
|
* Display a dialog to confirm a declaration of independence.
|
|
*
|
|
* @return A list of names for a new nation.
|
|
*/
|
|
List<String> showConfirmDeclarationDialog() {
|
|
return showFreeColDialog(new ConfirmDeclarationDialog(freeColClient, frame),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display a panel showing the declaration of independence with
|
|
* animated signature.
|
|
*/
|
|
void showDeclarationPanel() {
|
|
showSubPanel(new DeclarationPanel(freeColClient),
|
|
PopupPosition.CENTERED, false);
|
|
}
|
|
|
|
/**
|
|
* Display the difficulty dialog for a given group.
|
|
*
|
|
* @param spec The enclosing <code>Specification</code>.
|
|
* @param group The <code>OptionGroup</code> containing the difficulty.
|
|
* @param editable If the options should be editable.
|
|
* @return The resulting <code>OptionGroup</code>.
|
|
*/
|
|
OptionGroup showDifficultyDialog(Specification spec,
|
|
OptionGroup group, boolean editable) {
|
|
return showFreeColDialog(new DifficultyDialog(freeColClient, frame,
|
|
spec, group, editable),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>DumpCargoDialog</code>.
|
|
*
|
|
* @param unit The <code>Unit</code> that is dumping.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showDumpCargoDialog(Unit unit, DialogHandler<List<Goods>> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new DumpCargoDialog(freeColClient, frame, unit),
|
|
unit.getTile(), handler));
|
|
}
|
|
|
|
/**
|
|
* Display the EditOptionDialog.
|
|
*
|
|
* @param option The <code>Option</code> to edit.
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
boolean showEditOptionDialog(Option option) {
|
|
return showFreeColDialog(new EditOptionDialog(freeColClient, frame, option),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display the EditSettlementDialog.
|
|
*
|
|
* @param settlement The <code>IndianSettlement</code> to edit.
|
|
*/
|
|
void showEditSettlementDialog(IndianSettlement settlement) {
|
|
showFreeColDialog(new EditSettlementDialog(freeColClient, frame, settlement),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Shows the panel that allows the user to choose which unit will emigrate
|
|
* from Europe.
|
|
*
|
|
* @param player The <code>Player</code> whose unit is emigrating.
|
|
* @param fountainOfYouth Is this dialog displayed as a result of a
|
|
* fountain of youth.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showEmigrationDialog(Player player, boolean fountainOfYouth,
|
|
DialogHandler<Integer> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new EmigrationDialog(freeColClient, frame, player.getEurope(),
|
|
fountainOfYouth),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Display the EndTurnDialog with given units that could still move.
|
|
*
|
|
* @param units A list of <code>Unit</code>s that could still move.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showEndTurnDialog(List<Unit> units,
|
|
DialogHandler<Boolean> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new EndTurnDialog(freeColClient, frame, units),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Displays an error message.
|
|
*
|
|
* @param messageId The i18n-keyname of the error message to display.
|
|
*/
|
|
void showErrorMessage(String messageId) {
|
|
showErrorMessage(messageId, "Unspecified error: " + messageId);
|
|
}
|
|
|
|
/**
|
|
* Displays an error message.
|
|
*
|
|
* @param messageId The i18n-keyname of the error message to display.
|
|
* @param message An alternative (possibly non-i18n) message to
|
|
* display if the resource specified by <code>messageId</code>
|
|
* is unavailable.
|
|
*/
|
|
void showErrorMessage(String messageId, String message) {
|
|
String display = null;
|
|
if (messageId != null) {
|
|
display = Messages.message(messageId);
|
|
}
|
|
if (display == null || display.isEmpty()) display = message;
|
|
ErrorPanel errorPanel = new ErrorPanel(freeColClient, display);
|
|
showSubPanel(errorPanel, true);
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>EuropePanel</code>.
|
|
*
|
|
* @see EuropePanel
|
|
*/
|
|
void showEuropePanel() {
|
|
if (freeColClient.getGame() == null) return;
|
|
EuropePanel panel = getExistingFreeColPanel(EuropePanel.class);
|
|
if (panel == null) {
|
|
panel = new EuropePanel(freeColClient, (getHeight() > 780));
|
|
panel.addClosingCallback(() -> { removeEuropeanSubpanels(); });
|
|
showSubPanel(panel, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display an event panel.
|
|
*
|
|
* @param header The title.
|
|
* @param image A resource key for the image to display.
|
|
* @param footer Optional footer text.
|
|
*/
|
|
void showEventPanel(String header, String image, String footer) {
|
|
showSubPanel(new EventPanel(freeColClient, header, image, footer),
|
|
PopupPosition.CENTERED, false);
|
|
}
|
|
|
|
/**
|
|
* Display the FindSettlementPanel.
|
|
*/
|
|
void showFindSettlementPanel() {
|
|
showSubPanel(new FindSettlementPanel(freeColClient),
|
|
PopupPosition.ORIGIN, true);
|
|
}
|
|
|
|
/**
|
|
* Display the first contact dialog (which is really just a
|
|
* non-modal confirm dialog).
|
|
*
|
|
* @param player The <code>Player</code> making contact.
|
|
* @param other The <code>Player</code> to contact.
|
|
* @param tile An optional <code>Tile</code> on offer.
|
|
* @param settlementCount The number of settlements the other
|
|
* player has (from the server, other.getNumberOfSettlements()
|
|
* is wrong here!).
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showFirstContactDialog(Player player, Player other,
|
|
Tile tile, int settlementCount,
|
|
DialogHandler<Boolean> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new FirstContactDialog(freeColClient, frame, player, other, tile,
|
|
settlementCount),
|
|
tile, handler));
|
|
}
|
|
|
|
/**
|
|
* Detailed view of a foreign colony when in debug mode.
|
|
*
|
|
* @param settlement The <code>Settlement</code> with the colony
|
|
*/
|
|
void showForeignColony(Settlement settlement) {
|
|
if (settlement instanceof Colony) {
|
|
Colony colony = freeColClient.getFreeColServer().getGame()
|
|
.getFreeColGameObject(settlement.getId(), Colony.class);
|
|
showColonyPanel(colony, null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the GameOptionsDialog.
|
|
*
|
|
* @param editable Should the game options be editable?
|
|
* @param custom Whether to load custom options.
|
|
* @return The <code>OptionGroup</code> selected.
|
|
*/
|
|
OptionGroup showGameOptionsDialog(boolean editable,
|
|
boolean custom) {
|
|
GameOptionsDialog god = new GameOptionsDialog(freeColClient, frame, editable,
|
|
custom);
|
|
return showFreeColDialog(god, null);
|
|
}
|
|
|
|
/**
|
|
* Displays the high scores panel.
|
|
*
|
|
* @param messageId An optional message to add to the high scores panel.
|
|
* @param scores The list of <code>HighScore</code>s to display.
|
|
*/
|
|
void showHighScoresPanel(String messageId, List<HighScore> scores) {
|
|
showSubPanel(new ReportHighScoresPanel(freeColClient, messageId, scores),
|
|
PopupPosition.CENTERED, true);
|
|
}
|
|
|
|
/**
|
|
* Displays the panel of the given native settlement.
|
|
*
|
|
* @param indianSettlement The <code>IndianSettlement</code> to display.
|
|
*/
|
|
void showIndianSettlementPanel(IndianSettlement indianSettlement) {
|
|
IndianSettlementPanel panel
|
|
= new IndianSettlementPanel(freeColClient, indianSettlement);
|
|
showFreeColPanel(panel, indianSettlement.getTile(), true);
|
|
}
|
|
|
|
/**
|
|
* Make image icon from an image.
|
|
* Use only if you know having null is possible!
|
|
*
|
|
* @param image The <code>Image</code> to create an icon for.
|
|
* @return The <code>ImageIcon</code>.
|
|
*/
|
|
private static ImageIcon createImageIcon(Image image) {
|
|
return (image==null) ? null : new ImageIcon(image);
|
|
}
|
|
|
|
/**
|
|
* Make image icon from an object.
|
|
*
|
|
* @param display The FreeColObject to find an icon for.
|
|
* @return The <code>ImageIcon</code> found.
|
|
*/
|
|
private ImageIcon createObjectImageIcon(FreeColObject display) {
|
|
return (display == null) ? null
|
|
: createImageIcon(gui.getImageLibrary().getObjectImage(display, 2f));
|
|
}
|
|
|
|
/**
|
|
* Shows a message with some information and an "OK"-button.
|
|
*
|
|
* @param displayObject Optional object for displaying an icon.
|
|
* @param template The <code>StringTemplate</code> to display.
|
|
*/
|
|
void showInformationMessage(FreeColObject displayObject,
|
|
StringTemplate template) {
|
|
ImageIcon icon = null;
|
|
Tile tile = null;
|
|
if(displayObject != null) {
|
|
icon = createObjectImageIcon(displayObject);
|
|
tile = (displayObject instanceof Location)
|
|
? ((Location)displayObject).getTile()
|
|
: null;
|
|
}
|
|
showInformationMessage(displayObject, tile, icon, template);
|
|
}
|
|
|
|
/**
|
|
* Shows a message with some information and an "OK"-button.
|
|
*
|
|
* @param displayObject Optional object for displaying.
|
|
* @param tile The Tile the object is at.
|
|
* @param icon The icon to display for the object.
|
|
* @param template The <code>StringTemplate</code> to display.
|
|
*/
|
|
void showInformationMessage(FreeColObject displayObject,
|
|
Tile tile, ImageIcon icon,
|
|
StringTemplate template) {
|
|
String text = Messages.message(template);
|
|
showFreeColPanel(new InformationPanel(freeColClient, text,
|
|
displayObject, icon),
|
|
tile, true);
|
|
}
|
|
|
|
/**
|
|
* Displays a dialog where the user may choose a file.
|
|
*
|
|
* @param directory The directory containing the files.
|
|
* @param filters The file filters which the user can select in the dialog.
|
|
* @return The selected <code>File</code>.
|
|
*/
|
|
File showLoadDialog(File directory, FileFilter[] filters) {
|
|
if (filters == null) filters = getFileFilters();
|
|
File response = null;
|
|
for (;;) {
|
|
response = showFreeColDialog(new LoadDialog(freeColClient, frame,
|
|
directory, filters),
|
|
null);
|
|
if (response == null || response.isFile()) break;
|
|
showErrorMessage("error.noSuchFile");
|
|
}
|
|
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.
|
|
*/
|
|
boolean showLoadingSavegameDialog(boolean publicServer,
|
|
boolean singlePlayer) {
|
|
loadingSavegameDialog = new LoadingSavegameDialog(freeColClient, frame);
|
|
return showFreeColDialog(loadingSavegameDialog, null);
|
|
}
|
|
|
|
/**
|
|
* Show a panel containing the log file.
|
|
*/
|
|
void showLogFilePanel() {
|
|
showSubPanel(new ErrorPanel(freeColClient), true);
|
|
|
|
}
|
|
|
|
/**
|
|
* Shows the <code>MainPanel</code>.
|
|
*
|
|
* @param userMsg An option message key to show.
|
|
* @see MainPanel
|
|
*/
|
|
void showMainPanel(String userMsg) {
|
|
closeMenus();
|
|
frame.removeMenuBar();
|
|
mainPanel = new MainPanel(freeColClient);
|
|
addCentered(mainPanel, JLayeredPane.DEFAULT_LAYER);
|
|
if (userMsg != null) gui.showInformationMessage(userMsg);
|
|
mainPanel.requestFocus();
|
|
}
|
|
|
|
/**
|
|
* Display the map editor transform panel.
|
|
*/
|
|
void showMapEditorTransformPanel() {
|
|
JInternalFrame f = addAsFrame(new MapEditorTransformPanel(freeColClient),
|
|
true, PopupPosition.CENTERED, false);
|
|
f.setLocation(f.getX(), 50);
|
|
repaint();
|
|
}
|
|
|
|
/**
|
|
* Display the map generator options dialog.
|
|
*
|
|
* @param editable Should these options be editable.
|
|
* @return The <code>OptionGroup</code> as edited.
|
|
*/
|
|
OptionGroup showMapGeneratorOptionsDialog(boolean editable) {
|
|
MapGeneratorOptionsDialog mgod
|
|
= new MapGeneratorOptionsDialog(freeColClient, frame, editable);
|
|
return showFreeColDialog(mgod, null);
|
|
}
|
|
|
|
/**
|
|
* Display the map size dialog.
|
|
*
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
Dimension showMapSizeDialog() {
|
|
return showFreeColDialog(new MapSizeDialog(freeColClient, frame), null);
|
|
}
|
|
|
|
/**
|
|
* Displays a number of ModelMessages.
|
|
*
|
|
* @param messages The <code>ModelMessage</code>s to display.
|
|
*/
|
|
void showModelMessages(List<ModelMessage> messages) {
|
|
if (messages.isEmpty()) return;
|
|
final Game game = freeColClient.getGame();
|
|
int n = messages.size();
|
|
String[] texts = new String[n];
|
|
FreeColObject[] fcos = new FreeColObject[n];
|
|
ImageIcon[] icons = new ImageIcon[n];
|
|
Tile tile = null;
|
|
for (int i = 0; i < n; i++) {
|
|
ModelMessage m = messages.get(i);
|
|
texts[i] = Messages.message(m);
|
|
fcos[i] = game.getMessageSource(m);
|
|
icons[i] = createObjectImageIcon(game.getMessageDisplay(m));
|
|
if (tile == null && fcos[i] instanceof Location) {
|
|
tile = ((Location)fcos[i]).getTile();
|
|
}
|
|
}
|
|
|
|
showFreeColPanel(new InformationPanel(freeColClient, texts, fcos,
|
|
icons),
|
|
tile, true);
|
|
}
|
|
|
|
/**
|
|
* Display the monarch dialog.
|
|
*
|
|
* @param action The <code>MonarchAction</code> underway.
|
|
* @param template The <code>StringTemplate</code> describing the
|
|
* situation.
|
|
* @param monarchKey The resource key for the monarch image.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showMonarchDialog(MonarchAction action,
|
|
StringTemplate template, String monarchKey,
|
|
DialogHandler<Boolean> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new MonarchDialog(freeColClient, frame, action, template, monarchKey),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Display a dialog to set a new name for something.
|
|
*
|
|
* @param template A <code>StringTemplate</code> for the message
|
|
* to explain the dialog.
|
|
* @param defaultName The default name.
|
|
* @param unit The <code>Unit</code> discovering it.
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showNamingDialog(StringTemplate template, String defaultName,
|
|
Unit unit, DialogHandler<String> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(
|
|
new FreeColStringInputDialog(freeColClient, frame, false,
|
|
Messages.message(template),
|
|
defaultName, "ok", null),
|
|
unit.getTile(), handler));
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>NegotiationDialog</code>.
|
|
*
|
|
* @param our Our <code>FreeColGameObject</code> that is negotiating.
|
|
* @param other The other <code>FreeColGameObject</code>.
|
|
* @param agreement The current <code>DiplomaticTrade</code> agreement.
|
|
* @param comment An optional <code>StringTemplate</code> containing a
|
|
* commentary message.
|
|
* @return An updated agreement.
|
|
*/
|
|
DiplomaticTrade showNegotiationDialog(FreeColGameObject our,
|
|
FreeColGameObject other,
|
|
DiplomaticTrade agreement,
|
|
StringTemplate comment) {
|
|
if ((!(our instanceof Unit) && !(our instanceof Colony))
|
|
|| (!(other instanceof Unit) && !(other instanceof Colony))
|
|
|| (our instanceof Colony && other instanceof Colony)) {
|
|
throw new RuntimeException("Bad DTD args: " + our + ", " + other);
|
|
}
|
|
NegotiationDialog dtd = new NegotiationDialog(freeColClient, frame,
|
|
our, other, agreement, comment);
|
|
return showFreeColDialog(dtd, ((Location)our).getTile());
|
|
}
|
|
|
|
/**
|
|
* Display the NewPanel for a given optional specification.
|
|
*
|
|
* @param specification The <code>Specification</code> to use.
|
|
*/
|
|
void showNewPanel(Specification specification) {
|
|
showSubPanel(new NewPanel(freeColClient, specification), false);
|
|
}
|
|
|
|
/**
|
|
* Shows the given video Component.
|
|
*
|
|
* @param vp The video Component.
|
|
* @param ml A MouseListener for stopping the video.
|
|
* @param kl A KeyListener for stopping the video.
|
|
*/
|
|
void showVideoComponent(final Component vp,
|
|
final MouseListener ml,
|
|
final KeyListener kl) {
|
|
addMouseListener(ml);
|
|
addKeyListener(kl);
|
|
addCentered(vp, JLayeredPane.PALETTE_LAYER);
|
|
}
|
|
|
|
/**
|
|
* Display the parameters dialog.
|
|
*
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
Parameters showParametersDialog() {
|
|
return showFreeColDialog(new ParametersDialog(freeColClient, frame),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display a dialog to confirm a combat.
|
|
*
|
|
* @param attacker The attacker <code>Unit</code>.
|
|
* @param defender The defender.
|
|
* @param tile A <code>Tile</code> to make visible.
|
|
* @return True if the combat is to proceed.
|
|
*/
|
|
boolean showPreCombatDialog(Unit attacker,
|
|
FreeColGameObject defender,
|
|
Tile tile) {
|
|
return showFreeColDialog(new PreCombatDialog(freeColClient, frame,
|
|
attacker, defender),
|
|
tile);
|
|
}
|
|
|
|
/**
|
|
* Displays the purchase panel.
|
|
*/
|
|
void showPurchasePanel() {
|
|
PurchasePanel panel = getExistingFreeColPanel(PurchasePanel.class);
|
|
if (panel == null) {
|
|
showFreeColPanel(new PurchasePanel(freeColClient), null, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Displays the recruit panel.
|
|
*/
|
|
void showRecruitPanel() {
|
|
RecruitPanel panel = getExistingFreeColPanel(RecruitPanel.class);
|
|
if (panel == null) {
|
|
showFreeColPanel(new RecruitPanel(freeColClient), null, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the labour detail panel.
|
|
*
|
|
* @param unitType The <code>UnitType</code> to display.
|
|
* @param data The labour data.
|
|
* @param unitCount A map of unit distribution.
|
|
* @param colonies The list of player <code>Colony</code>s.
|
|
*/
|
|
void showReportLabourDetailPanel(UnitType unitType,
|
|
Map<UnitType, Map<Location, Integer>> data,
|
|
TypeCountMap<UnitType> unitCount, List<Colony> colonies) {
|
|
ReportLabourDetailPanel details
|
|
= new ReportLabourDetailPanel(freeColClient, unitType, data,
|
|
unitCount, colonies);
|
|
details.initialize();
|
|
showSubPanel(details, true);
|
|
}
|
|
|
|
/**
|
|
* Display the river style dialog.
|
|
*
|
|
* @param tile An optional tile to make visible (not under the dialog).
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
String showRiverStyleDialog(Tile tile) {
|
|
return showFreeColDialog(new RiverStyleDialog(freeColClient, frame), tile);
|
|
}
|
|
|
|
/**
|
|
* Displays a dialog where the user may choose a filename.
|
|
*
|
|
* @param directory The directory containing the files in which
|
|
* the user may overwrite.
|
|
* @param filters The available file filters in the dialog.
|
|
* @param defaultName Default filename for the savegame.
|
|
* @return The selected <code>File</code>.
|
|
*/
|
|
public File showSaveDialog(File directory, FileFilter[] filters,
|
|
String defaultName) {
|
|
if (filters == null) filters = getFileFilters();
|
|
return showFreeColDialog(new SaveDialog(freeColClient, frame, directory,
|
|
filters, defaultName),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display the scale map size dialog.
|
|
*
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
Dimension showScaleMapSizeDialog() {
|
|
return showFreeColDialog(new ScaleMapSizeDialog(freeColClient, frame),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display the select-amount dialog.
|
|
*
|
|
* @param goodsType The <code>GoodsType</code> to select an amount of.
|
|
* @param available The amount of goods available.
|
|
* @param defaultAmount The amount to select to start with.
|
|
* @param needToPay If true, check the player has sufficient funds.
|
|
* @return The amount selected.
|
|
*/
|
|
int showSelectAmountDialog(GoodsType goodsType, int available,
|
|
int defaultAmount, boolean needToPay) {
|
|
FreeColDialog<Integer> fcd
|
|
= new SelectAmountDialog(freeColClient, frame, goodsType, available,
|
|
defaultAmount, needToPay);
|
|
Integer result = showFreeColDialog(fcd, null);
|
|
return (result == null) ? -1 : result;
|
|
}
|
|
|
|
/**
|
|
* display the select-tribute-amount dialog.
|
|
*
|
|
* @param question a <code>stringtemplate</code> describing the
|
|
* amount of tribute to demand.
|
|
* @param maximum The maximum amount available.
|
|
* @return The amount selected.
|
|
*/
|
|
int showSelectTributeAmountDialog(StringTemplate question,
|
|
int maximum) {
|
|
FreeColDialog<Integer> fcd
|
|
= new SelectTributeAmountDialog(freeColClient, frame, question, maximum);
|
|
Integer result = showFreeColDialog(fcd, null);
|
|
return (result == null) ? -1 : result;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
Location showSelectDestinationDialog(Unit unit) {
|
|
return showFreeColDialog(new SelectDestinationDialog(freeColClient, frame,
|
|
unit), unit.getTile());
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>ServerListPanel</code>.
|
|
*
|
|
* @param serverList The list containing the servers retrieved from the
|
|
* metaserver.
|
|
* @see ServerListPanel
|
|
*/
|
|
void showServerListPanel(List<ServerInfo> serverList) {
|
|
closeMenus();
|
|
|
|
serverListPanel.initialize(serverList);
|
|
showSubPanel(serverListPanel, true);
|
|
}
|
|
|
|
/**
|
|
* Displays the colony panel of the given <code>Colony</code>
|
|
* following a spying action.
|
|
*
|
|
* @param tile The <code>Tile</code> containing the colony to display.
|
|
* @return The colony panel.
|
|
* @see ColonyPanel
|
|
*/
|
|
ColonyPanel showSpyColonyPanel(Tile tile) {
|
|
Colony colony = tile.getColony();
|
|
if (colony == null) return null;
|
|
ColonyPanel panel = new ColonyPanel(freeColClient, colony);
|
|
showFreeColPanel(panel, tile, true);
|
|
return panel;
|
|
}
|
|
|
|
/**
|
|
* Displays the <code>StartGamePanel</code>.
|
|
*
|
|
* @param game The <code>Game</code> that is about to start.
|
|
* @param player The <code>Player</code> using this client.
|
|
* @param singlePlayerMode True to start a single player game.
|
|
* @see StartGamePanel
|
|
*/
|
|
void showStartGamePanel(Game game, Player player,
|
|
boolean singlePlayerMode) {
|
|
if (game == null) {
|
|
logger.warning("StartGamePanel requires game != null.");
|
|
} else if (player == null) {
|
|
logger.warning("StartGamePanel requires player != null.");
|
|
} else {
|
|
closeMenus();
|
|
startGamePanel.initialize(singlePlayerMode);
|
|
showSubPanel(startGamePanel, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the statistics panel.
|
|
*/
|
|
void showStatisticsPanel() {
|
|
showSubPanel(new StatisticsPanel(freeColClient), true);
|
|
}
|
|
|
|
/**
|
|
* Shows a status message that cannot be dismissed. The panel
|
|
* will be removed when another component is added to this
|
|
* <code>Canvas</code>. This includes all the
|
|
* <code>showXXX</code>-methods. In addition,
|
|
* {@link #closeStatusPanel()} also removes this panel.
|
|
*
|
|
* @param message The text message to display on the status panel.
|
|
* @see StatusPanel
|
|
*/
|
|
void showStatusPanel(String message) {
|
|
statusPanel.setStatusMessage(message);
|
|
addCentered(statusPanel, JLayeredPane.POPUP_LAYER);
|
|
}
|
|
|
|
/**
|
|
* Display the tile panel for a given tile.
|
|
*
|
|
* @param tile The <code>Tile</code> to display.
|
|
*/
|
|
void showTilePanel(Tile tile) {
|
|
if (tile == null || !tile.isExplored()) return;
|
|
showSubPanel(new TilePanel(freeColClient, tile), false);
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
void showTilePopup(Tile tile, int x, int y) {
|
|
if (tile == null)
|
|
return;
|
|
TilePopup tp = new TilePopup(freeColClient, this, tile);
|
|
if (tp.hasItem()) {
|
|
tp.show(this, x, y);
|
|
tp.repaint();
|
|
} else if (tile.isExplored()) {
|
|
showTilePanel(tile);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display a panel to select a trade route for a unit.
|
|
*
|
|
* @param unit An optional <code>Unit</code> to select a trade route for.
|
|
*/
|
|
void showTradeRoutePanel(Unit unit) {
|
|
showFreeColPanel(new TradeRoutePanel(freeColClient, unit),
|
|
(unit == null) ? null : unit.getTile(), true);
|
|
}
|
|
|
|
/**
|
|
* Display the trade route input panel for a given trade route.
|
|
*
|
|
* @param newRoute The <code>TradeRoute</code> to display.
|
|
* @param callBack The <code>Runnable</code> that is run when the
|
|
* panel closes.
|
|
*/
|
|
void showTradeRouteInputPanel(TradeRoute newRoute,
|
|
Runnable callBack) {
|
|
FreeColPanel panel = new TradeRouteInputPanel(freeColClient, newRoute);
|
|
panel.addClosingCallback(callBack);
|
|
showSubPanel(panel, null, true);
|
|
}
|
|
|
|
/**
|
|
* Displays the training panel.
|
|
*/
|
|
void showTrainPanel() {
|
|
TrainPanel panel = getExistingFreeColPanel(TrainPanel.class);
|
|
if (panel == null) {
|
|
showFreeColPanel(new TrainPanel(freeColClient), null, false);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the victory dialog.
|
|
*
|
|
* @param handler A <code>DialogHandler</code> for the dialog response.
|
|
*/
|
|
void showVictoryDialog(DialogHandler<Boolean> handler) {
|
|
SwingUtilities.invokeLater(
|
|
new DialogCallback<>(new VictoryDialog(freeColClient, frame),
|
|
null, handler));
|
|
}
|
|
|
|
/**
|
|
* Display the warehouse dialog for a colony.
|
|
*
|
|
* Run out of ColonyPanel, so the tile is already displayed.
|
|
*
|
|
* @param colony The <code>Colony</code> to display.
|
|
* @return The response returned by the dialog.
|
|
*/
|
|
boolean showWarehouseDialog(Colony colony) {
|
|
return showFreeColDialog(new WarehouseDialog(freeColClient, frame, colony),
|
|
null);
|
|
}
|
|
|
|
/**
|
|
* Display the production of a unit.
|
|
*
|
|
* @param unit The <code>Unit</code> to display.
|
|
*/
|
|
void showWorkProductionPanel(Unit unit) {
|
|
showSubPanel(new WorkProductionPanel(freeColClient, unit), true);
|
|
}
|
|
|
|
/**
|
|
* Update all panels derived from the EuropePanel.
|
|
*/
|
|
void updateEuropeanSubpanels() {
|
|
RecruitPanel rp
|
|
= getExistingFreeColPanel(RecruitPanel.class);
|
|
if (rp != null) rp.update();
|
|
PurchasePanel pp
|
|
= getExistingFreeColPanel(PurchasePanel.class);
|
|
if (pp != null) pp.update();
|
|
TrainPanel tp
|
|
= getExistingFreeColPanel(TrainPanel.class);
|
|
if (tp != null) tp.update();
|
|
}
|
|
|
|
// Singleton specialist reports
|
|
|
|
void showReportCargoPanel() {
|
|
ReportCargoPanel r
|
|
= getExistingFreeColPanel(ReportCargoPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportCargoPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportColonyPanel() {
|
|
boolean compact;
|
|
try {
|
|
compact = freeColClient.getClientOptions()
|
|
.getInteger(ClientOptions.COLONY_REPORT)
|
|
== ClientOptions.COLONY_REPORT_COMPACT;
|
|
} catch (Exception e) {
|
|
compact = false;
|
|
}
|
|
ReportPanel r = (compact)
|
|
? getExistingFreeColPanel(ReportCompactColonyPanel.class)
|
|
: getExistingFreeColPanel(ReportClassicColonyPanel.class);
|
|
if (r == null) {
|
|
showSubPanel((compact)
|
|
? new ReportCompactColonyPanel(freeColClient)
|
|
: new ReportClassicColonyPanel(freeColClient),
|
|
true);
|
|
}
|
|
}
|
|
|
|
void showReportContinentalCongressPanel() {
|
|
ReportContinentalCongressPanel
|
|
r = getExistingFreeColPanel(ReportContinentalCongressPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportContinentalCongressPanel(freeColClient),
|
|
true);
|
|
}
|
|
}
|
|
|
|
void showReportEducationPanel() {
|
|
ReportEducationPanel r
|
|
= getExistingFreeColPanel(ReportEducationPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportEducationPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportExplorationPanel() {
|
|
ReportExplorationPanel r
|
|
= getExistingFreeColPanel(ReportExplorationPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportExplorationPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportForeignAffairPanel() {
|
|
ReportForeignAffairPanel r
|
|
= getExistingFreeColPanel(ReportForeignAffairPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportForeignAffairPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportHistoryPanel() {
|
|
ReportHistoryPanel r
|
|
= getExistingFreeColPanel(ReportHistoryPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportHistoryPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportIndianPanel() {
|
|
ReportIndianPanel r
|
|
= getExistingFreeColPanel(ReportIndianPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportIndianPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportLabourPanel() {
|
|
ReportLabourPanel r
|
|
= getExistingFreeColPanel(ReportLabourPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportLabourPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportMilitaryPanel() {
|
|
ReportMilitaryPanel r
|
|
= getExistingFreeColPanel(ReportMilitaryPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportMilitaryPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportNavalPanel() {
|
|
ReportNavalPanel r
|
|
= getExistingFreeColPanel(ReportNavalPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportNavalPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportProductionPanel() {
|
|
ReportProductionPanel r
|
|
= getExistingFreeColPanel(ReportProductionPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportProductionPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportReligiousPanel() {
|
|
ReportReligiousPanel r
|
|
= getExistingFreeColPanel(ReportReligiousPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportReligiousPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportRequirementsPanel() {
|
|
ReportRequirementsPanel r
|
|
= getExistingFreeColPanel(ReportRequirementsPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportRequirementsPanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
void showReportTradePanel() {
|
|
ReportTradePanel r
|
|
= getExistingFreeColPanel(ReportTradePanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportTradePanel(freeColClient), true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show the turn report.
|
|
*
|
|
* @param messages The <code>ModelMessage</code>s to show.
|
|
*/
|
|
void showReportTurnPanel(List<ModelMessage> messages) {
|
|
ReportTurnPanel r = getExistingFreeColPanel(ReportTurnPanel.class);
|
|
if (r == null) {
|
|
showSubPanel(new ReportTurnPanel(freeColClient, messages), true);
|
|
} else {
|
|
r.setMessages(messages);
|
|
}
|
|
}
|
|
}
|