diff --git a/data/strings/FreeColMessages.properties b/data/strings/FreeColMessages.properties index 06601781cb..2eac425f6b 100644 --- a/data/strings/FreeColMessages.properties +++ b/data/strings/FreeColMessages.properties @@ -3654,6 +3654,7 @@ quickActionMenu.apprentice=Understudy to %unit% quickActionMenu.assignToTeacher=Assign to teacher quickActionMenu.board=Board %unit% quickActionMenu.changeWork=Change work +quickActionMenu.goto=Go To quickActionMenu.clearSpeciality=Clear speciality quickActionMenu.experience=Experience as %job%: quickActionMenu.leaveTown=Leave Town diff --git a/src/net/sf/freecol/client/control/InGameController.java b/src/net/sf/freecol/client/control/InGameController.java index 6bbb661422..b08a23cf6d 100644 --- a/src/net/sf/freecol/client/control/InGameController.java +++ b/src/net/sf/freecol/client/control/InGameController.java @@ -19,32 +19,6 @@ package net.sf.freecol.client.control; -import static net.sf.freecol.common.model.Constants.INFINITY; -import static net.sf.freecol.common.model.Constants.STEAL_LAND; -import static net.sf.freecol.common.util.CollectionUtils.allSame; -import static net.sf.freecol.common.util.CollectionUtils.alwaysTrue; -import static net.sf.freecol.common.util.CollectionUtils.find; -import static net.sf.freecol.common.util.CollectionUtils.none; -import static net.sf.freecol.common.util.CollectionUtils.removeInPlace; -import static net.sf.freecol.common.util.CollectionUtils.transform; -import static net.sf.freecol.common.util.Utils.delay; -import static net.sf.freecol.common.util.Utils.deleteFile; - -import java.awt.Color; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.logging.Level; -import java.util.logging.Logger; - import net.sf.freecol.FreeCol; import net.sf.freecol.client.ClientOptions; import net.sf.freecol.client.FreeColClient; @@ -59,12 +33,7 @@ import net.sf.freecol.common.i18n.Messages; import net.sf.freecol.common.i18n.NameCache; import net.sf.freecol.common.io.FreeColDirectories; -import net.sf.freecol.common.model.Ability; -import net.sf.freecol.common.model.AbstractGoods; -import net.sf.freecol.common.model.BuildableType; -import net.sf.freecol.common.model.Building; -import net.sf.freecol.common.model.Colony; -import net.sf.freecol.common.model.ColonyWas; +import net.sf.freecol.common.model.*; import net.sf.freecol.common.model.Constants.ArmedUnitSettlementAction; import net.sf.freecol.common.model.Constants.ClaimAction; import net.sf.freecol.common.model.Constants.IndianDemandAction; @@ -74,66 +43,46 @@ import net.sf.freecol.common.model.Constants.TradeAction; import net.sf.freecol.common.model.Constants.TradeBuyAction; import net.sf.freecol.common.model.Constants.TradeSellAction; -import net.sf.freecol.common.model.DiplomaticTrade; import net.sf.freecol.common.model.DiplomaticTrade.TradeContext; import net.sf.freecol.common.model.DiplomaticTrade.TradeStatus; -import net.sf.freecol.common.model.Direction; -import net.sf.freecol.common.model.Europe; import net.sf.freecol.common.model.Europe.MigrationType; -import net.sf.freecol.common.model.EuropeWas; -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.Game.LogoutReason; -import net.sf.freecol.common.model.GoldTradeItem; -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.HistoryEvent; -import net.sf.freecol.common.model.IndianSettlement; -import net.sf.freecol.common.model.LastSale; -import net.sf.freecol.common.model.Location; -import net.sf.freecol.common.model.LostCityRumour; -import net.sf.freecol.common.model.Map; -import net.sf.freecol.common.model.MarketWas; -import net.sf.freecol.common.model.ModelMessage; import net.sf.freecol.common.model.ModelMessage.MessageType; -import net.sf.freecol.common.model.Modifier; import net.sf.freecol.common.model.Monarch.MonarchAction; -import net.sf.freecol.common.model.Nameable; -import net.sf.freecol.common.model.NationSummary; -import net.sf.freecol.common.model.NativeTrade; import net.sf.freecol.common.model.NativeTrade.NativeTradeAction; -import net.sf.freecol.common.model.NativeTradeItem; -import net.sf.freecol.common.model.ObjectWas; -import net.sf.freecol.common.model.Ownable; -import net.sf.freecol.common.model.PathNode; -import net.sf.freecol.common.model.Player; import net.sf.freecol.common.model.Player.NoClaimReason; -import net.sf.freecol.common.model.Region; -import net.sf.freecol.common.model.Role; -import net.sf.freecol.common.model.Settlement; -import net.sf.freecol.common.model.Stance; -import net.sf.freecol.common.model.StringTemplate; -import net.sf.freecol.common.model.Tile; -import net.sf.freecol.common.model.TileImprovementType; -import net.sf.freecol.common.model.TradeLocation; -import net.sf.freecol.common.model.TradeRoute; -import net.sf.freecol.common.model.TradeRouteStop; -import net.sf.freecol.common.model.Turn; -import net.sf.freecol.common.model.Unit; import net.sf.freecol.common.model.Unit.UnitState; -import net.sf.freecol.common.model.UnitChangeType; -import net.sf.freecol.common.model.UnitType; -import net.sf.freecol.common.model.UnitTypeChange; -import net.sf.freecol.common.model.UnitWas; -import net.sf.freecol.common.model.WorkLocation; import net.sf.freecol.common.option.GameOptions; import net.sf.freecol.common.util.Introspector; import net.sf.freecol.common.util.LogBuilder; import net.sf.freecol.server.FreeColServer; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static net.sf.freecol.common.model.Constants.INFINITY; +import static net.sf.freecol.common.model.Constants.STEAL_LAND; +import static net.sf.freecol.common.util.CollectionUtils.allSame; +import static net.sf.freecol.common.util.CollectionUtils.alwaysTrue; +import static net.sf.freecol.common.util.CollectionUtils.find; +import static net.sf.freecol.common.util.CollectionUtils.none; +import static net.sf.freecol.common.util.CollectionUtils.removeInPlace; +import static net.sf.freecol.common.util.CollectionUtils.transform; +import static net.sf.freecol.common.util.Utils.delay; +import static net.sf.freecol.common.util.Utils.deleteFile; + /** * The controller that will be used while the game is played. @@ -206,7 +155,7 @@ public InGameController(FreeColClient freeColClient) { public void sound(String soundKey) { getGUI().playSound(soundKey); } - + /** * Require that it is this client's player's turn. * Put up the notYourTurn message if not. @@ -292,7 +241,7 @@ private void changeView(final Tile tile) { } }); } - + /** * Wrapper for GUI.displayChat. * @@ -319,7 +268,7 @@ private void fireChanges(ObjectWas... objs) { } }); } - + /** * Wrapper for GUI.showColonyPanel. * @@ -563,7 +512,7 @@ private void updateGUI(final Tile tile, boolean updateUnit) { Unit active = gui.getActiveUnit(); final boolean update = updateUnit || active == null || (!active.couldMove() && !active.isInEurope()) - || !getMyPlayer().owns(active); + || !getMyPlayer().owns(active); // Tile is displayed if no new active unit is found, // which is useful when the last unit might have died invokeLater(() -> { @@ -666,7 +615,7 @@ private boolean askEmbark(Unit unit, Unit carrier) { } return false; } - + /** * A unit in Europe emigrates. * @@ -832,7 +781,7 @@ private void autoSaveGame () { final String beforeLastTurnName = prefix + "-" + options.getText(ClientOptions.BEFORE_LAST_TURN_NAME) + "." + FreeCol.FREECOL_SAVE_EXTENSION; - + File lastTurnFile = FreeColDirectories.getAutosaveFile(lastTurnName); File beforeLastTurnFile = FreeColDirectories.getAutosaveFile(beforeLastTurnName); @@ -1063,7 +1012,7 @@ private boolean doExecuteGotoOrders() { if (active == unit) active = null; } nextModelMessage(); // Might have LCR messages to display - if (ret) { // If no unit issues, restore previously active unit + if (ret) { // If no unit issues, restore previously active unit changeView(active, false); } return ret; @@ -1079,7 +1028,7 @@ private boolean doEndTurn(boolean showDialog) { final Player player = getMyPlayer(); // Clear any panels first if (getGUI().isPanelShowing()) return false; - + if (showDialog) { List units = transform(player.getUnits(), Unit::couldMove); if (!units.isEmpty()) { @@ -1119,7 +1068,7 @@ private boolean doEndTurn(boolean showDialog) { // Clear outdated turn report messages. turnReportMessages.clear(); - + changeView(null); // Inform the server of end of turn. @@ -1193,7 +1142,7 @@ private boolean moveToDestination(Unit unit, List messages) { // If the unit has moves left, select it ret = unit.getMovesLeft() == 0; } - } else { // Still in transit, do not select + } else { // Still in transit, do not select ret = true; } return ret; @@ -1568,7 +1517,7 @@ && getGUI().confirmPreCombat(unit, target)) { : -1; if (amount > 0) return moveTribute(unit, amount, direction); break; - + default: logger.warning("showArmedUnitSettlementDialog fail: " + act); break; @@ -1992,7 +1941,7 @@ private boolean moveSpy(Unit unit, Direction direction) { askServer().spy(unit, settlement); } else { logger.warning("Unit " + unit + " can not spy on " + settlement); - } + } return false; } @@ -2048,7 +1997,7 @@ private boolean moveTribute(Unit unit, int amount, Direction direction) { askServer().demandTribute(unit, direction); return false; } - + // Europeans might be human players, so we convert to a diplomacy // dialog. DiplomaticTrade agreement = DiplomaticTrade @@ -2139,7 +2088,7 @@ private boolean followTradeRoute(Unit unit, List messages) { changeState(unit, UnitState.SKIPPED); break; } - + // Try to follow the path. If the unit does not reach // the stop it is finished for now. movePath(unit, path); @@ -2250,7 +2199,7 @@ private boolean loadUnitAtStop(Unit unit, LogBuilder lb) { StringTemplate left = StringTemplate.label(", "); StringTemplate loaded = StringTemplate.label(", "); StringTemplate nonePresent = StringTemplate.label(", "); - + // Check the goods already on board. If it is not expected to // be loaded at this stop then complain (unload must have // failed somewhere). If it is expected to load, reduce the @@ -2376,7 +2325,7 @@ private boolean loadUnitAtStop(Unit unit, LogBuilder lb) { if (enhancedTradeRoutes) { // Prioritize by goods amount toLoad.sort(AbstractGoods.descendingAmountComparator); } - + // Load the goods. boolean done = false; for (AbstractGoods ag : toLoad) { @@ -2774,7 +2723,7 @@ public boolean buildColony(Unit unit) { if (!ret) { ret = askClaimTile(player, tile, unit, player.getLandPrice(tile)); if (!ret) NameCache.putSettlementName(player, name); - } + } if (ret) { ret = askServer().buildColony(name, unit) && tile.hasSettlement(); @@ -2853,7 +2802,7 @@ public void chatHandler(String sender, String message, Color color, boolean pri) { displayChat(sender, message, color, pri); } - + /** * Changes the state of this {@code Unit}. * @@ -3018,7 +2967,7 @@ private boolean chooseFoundingFather(List ffs, */ public void chooseFoundingFatherHandler(List ffs) { if (ffs == null || ffs.isEmpty()) return; - + invokeLater(() -> getGUI().showChooseFoundingFatherDialog(ffs, (FoundingFather ff) -> chooseFoundingFather(ffs, ff))); @@ -3492,7 +3441,7 @@ public void featureChangeHandler(FreeColGameObject parent, logger.warning("Feature change NYI: " + parent + "/" + add + "/" + fco); } - } else { + } else { logger.warning("featureChange unrecognized: " + fco); } } @@ -3644,7 +3593,7 @@ public boolean ignoreMessage(ModelMessage message, boolean flag) { public void inciteHandler(Unit unit, IndianSettlement is, Player enemy, int gold) { final Player player = getMyPlayer(); - + if (gold < 0) { ; // protocol fail } else if (!player.checkGold(gold)) { @@ -3738,7 +3687,7 @@ private boolean joinColony(Unit unit) { } return ret; } - + /** * Leave a ship. The ship must be in harbour. * @@ -3835,7 +3784,7 @@ public void loadGame() { FreeColDirectories.setSavegameFile(file.getPath()); if (!getConnectController().startSavedGame(file)) { getGUI().showMainPanel(null); - } + } } /** @@ -3855,7 +3804,7 @@ public void logoutHandler(Player player, LogoutReason reason) { getFreeColClient().getConnectController().logout(reason); } } - + /** * Loot some cargo. * @@ -4073,7 +4022,7 @@ public void nationSummaryHandler(Player other, NationSummary ns) { */ public void nativeTradeHandler(NativeTradeAction action, NativeTrade nt) { if (nt == null) return; - + final GUI gui = getGUI(); final IndianSettlement is = nt.getIndianSettlement(); final Unit unit = nt.getUnit(); @@ -4161,7 +4110,7 @@ public void nativeTradeHandler(NativeTradeAction action, NativeTrade nt) { nativeTrade(nt, act, nti, prompt); uw.fireChanges(); gui.changeView(current, false); - }); + }); } /** @@ -4180,12 +4129,12 @@ private void nativeTrade(NativeTrade nt, TradeAction act, .template("trade.welcome") .addStringTemplate("%nation%", is.getOwner().getNationLabel()) .addStringTemplate("%settlement%", is.getLocationLabelFor(unit.getOwner())); - + // Col1 only displays at most 3 types of goods for sale. // Maintain this for now but consider lifting in a future // "enhanced trade" mode. nt.limitSettlementToUnit(3); - + final Function> goodsMapper = i -> { String label = Messages.message(i.getGoods().getLabel(true)); @@ -4221,7 +4170,7 @@ private void nativeTrade(NativeTrade nt, TradeAction act, nti.setPrice(NativeTradeItem.PRICE_UNSET); askServer().nativeTrade(NativeTradeAction.BUY, nt); return; - } + } break; case SELL: act = null; @@ -4440,7 +4389,7 @@ private boolean newTurn(int turn) { public void newTurnHandler(int turn) { invokeLater(() -> newTurn(turn)); } - + /** * Makes a new unit active. * @@ -4647,14 +4596,14 @@ public void removeHandler(List objects, boolean visibilityChange = false, updateUnit = false; for (FreeColGameObject fcgo : objects) { if (divert != null) player.divertModelMessages(fcgo, divert); - + if (fcgo instanceof Settlement) { Settlement settlement = (Settlement)fcgo; if (settlement.getOwner() != null) { settlement.getOwner().removeSettlement(settlement); } visibilityChange = true;//-vis(player) - + } else if (fcgo instanceof Unit) { // Deselect the object if it is the current active unit. Unit u = (Unit)fcgo; @@ -4673,7 +4622,7 @@ public void removeHandler(List objects, if (visibilityChange) player.invalidateCanSeeTiles();//+vis(player) if (updateUnit) updateGUI(null, true); } - + /** * Renames a {@code Nameable}. * @@ -4803,7 +4752,7 @@ public void scoutSpeakToChiefHandler(Unit unit, IndianSettlement is, break; } } - + /** * Selects a destination for this unit. Europe and the player's * colonies are valid destinations. @@ -4820,13 +4769,17 @@ public boolean selectDestination(Unit unit) { Location destination = getGUI().showSelectDestinationDialog(unit); if (destination == null) return false; + return goTo(unit, destination); + } + + public boolean goTo(Unit unit, Location destination) { UnitWas unitWas = new UnitWas(unit); boolean ret = askSetDestination(unit, destination); if (ret) { if (destination instanceof Europe) { if (unit.hasTile() && unit.getTile().isDirectlyHighSeasConnected()) { - moveTowardEurope(unit, (Europe)destination); + moveTowardEurope(unit, (Europe) destination); } else { moveToDestination(unit, null); } @@ -4861,7 +4814,7 @@ public boolean sellGoods(Goods goods) { EuropeWas europeWas = new EuropeWas(player.getEurope()); MarketWas marketWas = new MarketWas(player); - + UnitWas unitWas = new UnitWas(carrier); boolean ret = askUnloadGoods(goods.getType(), goods.getAmount(), carrier); if (ret) { @@ -4949,7 +4902,7 @@ && currentPlayerIsMyPlayer()) { Europe.MigrationType.getUnspecificSlot()); } } - + // Wake up human! if (!getFreeColClient().getSinglePlayer()) { sound("sound.anthem." + player.getNationId()); @@ -5097,7 +5050,7 @@ public void spySettlementHandler(Tile tile) { final Colony colony = tile.getColony(); if (colony != null) showColonyPanel(colony, null); } - + /** * Trains a unit of a specified type in Europe. * @@ -5262,7 +5215,7 @@ private boolean victory(Boolean quit) { } return true; } - + /** * Tell a unit to wait. * diff --git a/src/net/sf/freecol/client/gui/dialog/SelectDestinationDialog.java b/src/net/sf/freecol/client/gui/dialog/SelectDestinationDialog.java index 2f16568ce4..5aa4e6a0e6 100644 --- a/src/net/sf/freecol/client/gui/dialog/SelectDestinationDialog.java +++ b/src/net/sf/freecol/client/gui/dialog/SelectDestinationDialog.java @@ -19,44 +19,6 @@ package net.sf.freecol.client.gui.dialog; -import static net.sf.freecol.common.model.Constants.INFINITY; -import static net.sf.freecol.common.util.CollectionUtils.alwaysTrue; -import static net.sf.freecol.common.util.CollectionUtils.find; -import static net.sf.freecol.common.util.CollectionUtils.first; -import static net.sf.freecol.common.util.CollectionUtils.flatten; -import static net.sf.freecol.common.util.CollectionUtils.isNotNull; -import static net.sf.freecol.common.util.CollectionUtils.toList; -import static net.sf.freecol.common.util.CollectionUtils.transform; - -import java.awt.Dimension; -import java.awt.event.ItemEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.logging.Logger; -import java.util.stream.Stream; - -import javax.swing.DefaultListModel; -import javax.swing.ImageIcon; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.ListSelectionModel; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; - import net.miginfocom.swing.MigLayout; import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.gui.ChoiceItem; @@ -87,6 +49,35 @@ import net.sf.freecol.common.resources.ResourceManager; import net.sf.freecol.common.util.LogBuilder; +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.logging.Logger; +import java.util.stream.Stream; + +import static net.sf.freecol.common.model.Constants.INFINITY; +import static net.sf.freecol.common.util.CollectionUtils.alwaysTrue; +import static net.sf.freecol.common.util.CollectionUtils.find; +import static net.sf.freecol.common.util.CollectionUtils.first; +import static net.sf.freecol.common.util.CollectionUtils.flatten; +import static net.sf.freecol.common.util.CollectionUtils.isNotNull; +import static net.sf.freecol.common.util.CollectionUtils.toList; +import static net.sf.freecol.common.util.CollectionUtils.transform; + /** * Select a location as the destination for a given unit. @@ -102,7 +93,7 @@ public final class SelectDestinationDialog extends FreeColDialog * A container for a destination location, with associated * distance and extra characteristics. */ - private static class Destination { + public static class Destination { /** Basic destination comparator, that just uses the name field. */ private static Comparator nameComparator @@ -125,25 +116,22 @@ public int compare(Destination d1, Destination d2) { .thenComparing(Destination.nameComparator); /** The unit that is travelling. */ - public final Unit unit; + private final Unit unit; /** The location to travel to. */ - public final Location location; + private final Location location; /** The displayed name of the location (needed in text and comparator)*/ - public final String name; + private final String name; /** The number of turns to reach the destination. */ - public final int turns; - - /** Extra special information about the destination */ - public final String extras; + private final int turns; /** A magic score for the destination for the comparator/s. */ - public final int score; + private final int score; /** The full text to display. */ - public final String text; + private final String text; /** @@ -160,13 +148,14 @@ public Destination(Location location, int turns, Unit unit, this.location = location; this.name = Messages.message(location.getLocationLabelFor(unit.getOwner())); this.turns = turns; - this.extras = getExtras(location, unit, goodsTypes); + /** Extra special information about the destination */ + String extras = getExtras(location, unit, goodsTypes); this.score = calculateScore(); this.text = Messages.message(StringTemplate .template("selectDestinationDialog.destinationTurns") .addName("%location%", this.name) .addAmount("%turns%", this.turns) - .addName("%extras%", this.extras)); + .addName("%extras%", extras)); } /** @@ -268,6 +257,13 @@ public int getScore() { return this.score; } + public Location getLocation() { + return location; + } + + public String getText() { + return text; + } public static int getDestinationComparatorIndex(Comparator dc) { return (dc == nameComparator) ? 1 @@ -286,7 +282,7 @@ private static class LocationRenderer extends FreeColComboBoxRenderer { private final ImageLibrary lib; - + /** * Create a new location renderer. * @@ -317,7 +313,7 @@ public void setLabelValues(JLabel label, Destination value) { /** How to order the destinations. */ private static AtomicReference> destinationComparator = new AtomicReference<>(null); - + /** The available destinations. */ private final List destinations = new ArrayList<>(); @@ -343,11 +339,7 @@ public SelectDestinationDialog(FreeColClient freeColClient, JFrame frame, super(freeColClient, frame); final ImageLibrary lib = getImageLibrary(); - // Collect the goods the unit is carrying and set this.destinations. - final List goodsTypes - = transform(unit.getCompactGoodsList(), alwaysTrue(), - Goods::getType); - loadDestinations(unit, goodsTypes); + this.destinations.addAll(getPossibleDestinations(unit, getGame())); DefaultListModel model = new DefaultListModel<>(); @@ -416,7 +408,7 @@ public void mouseClicked(MouseEvent e) { * * @return The destination comparator. */ - private Comparator getDestinationComparator() { + private static Comparator getDestinationComparator() { Comparator ret = destinationComparator.get(); if (ret == null) { ret = Destination.getDestinationComparator(0); @@ -433,23 +425,25 @@ private Comparator getDestinationComparator() { private void setDestinationComparator(Comparator dc) { destinationComparator.set(dc); } - + /** * Load destinations for a given unit and carried goods types. * * @param unit The {@code Unit} to select destinations for. - * @param goodsTypes A list of {@code GoodsType}s carried. */ - private void loadDestinations(final Unit unit, - List goodsTypes) { - if (unit.isInEurope() && !unit.getType().canMoveToHighSeas()) return; + public static List getPossibleDestinations(Unit unit, Game game) { + // Collect the goods the unit is carrying and set this.destinations. + final List goodsTypes + = transform(unit.getCompactGoodsList(), alwaysTrue(), + Goods::getType); + + if (unit.isInEurope() && !unit.getType().canMoveToHighSeas()) return Collections.emptyList(); final Player player = unit.getOwner(); final Settlement inSettlement = unit.getSettlement(); final boolean canTrade = player.hasAbility(Ability.TRADE_WITH_FOREIGN_COLONIES); final Europe europe = player.getEurope(); - final Game game = getGame(); final Map map = game.getMap(); // Quick check for whether a settlement is reachable by the unit. // Used to knock out obviously impossible candidates before invoking @@ -499,7 +493,7 @@ private void loadDestinations(final Unit unit, + Messages.message(e.getKey().getLocationLabel()) + " path=" + p.fullPathToString()); return null; - } + } int turns = p.getTotalTurns(); if (unit.isInEurope()) turns += unit.getSailTurns(); if (p.getMovesLeft() < unit.getInitialMovesLeft()) turns++; @@ -508,9 +502,9 @@ private void loadDestinations(final Unit unit, td.addAll(transform(md.getResults().entrySet(), isNotNull(), dmapper)); // Drop inaccessible destinations and sort as specified. - this.destinations.addAll(transform(td, d -> d.turns < Unit.MANY_TURNS, + return transform(td, d -> d.turns < Unit.MANY_TURNS, Function.identity(), - getDestinationComparator())); + getDestinationComparator()); } /** @@ -563,7 +557,7 @@ private void updateDestinationComparator() { // Interface ListSelectionListener - + /** * {@inheritDoc} */ diff --git a/src/net/sf/freecol/client/gui/label/UnitLabel.java b/src/net/sf/freecol/client/gui/label/UnitLabel.java index eccffd0d8e..06b23633d3 100644 --- a/src/net/sf/freecol/client/gui/label/UnitLabel.java +++ b/src/net/sf/freecol/client/gui/label/UnitLabel.java @@ -19,26 +19,8 @@ package net.sf.freecol.client.gui.label; -import static net.sf.freecol.common.util.StringUtils.upCase; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Logger; - -import javax.swing.Icon; -import javax.swing.ImageIcon; - import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.control.InGameController; -import net.sf.freecol.client.gui.FontLibrary; import net.sf.freecol.client.gui.GUI; import net.sf.freecol.client.gui.ImageLibrary; import net.sf.freecol.client.gui.panel.CargoPanel; @@ -58,6 +40,15 @@ import net.sf.freecol.common.model.Unit; import net.sf.freecol.common.model.Unit.UnitLabelType; import net.sf.freecol.common.model.Unit.UnitState; +import net.sf.freecol.common.model.UnitLocation; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.logging.Logger; + +import static net.sf.freecol.common.util.StringUtils.upCase; /** @@ -78,10 +69,11 @@ public enum UnitAction { SENTRY, COLOPEDIA, LEAVE_TOWN, - WORK_COLONYTILE, // Must match the WorkLocation actual type - WORK_BUILDING, // Must match the WorkLocation actual type + WORK_COLONYTILE, // Must match the WorkLocation actual type, see net.sf.freecol.client.gui.panel.QuickActionMenu.getWorkLabel + WORK_BUILDING, // Must match the WorkLocation actual type, see net.sf.freecol.client.gui.panel.QuickActionMenu.getWorkLabel CLEAR_ORDERS, ASSIGN_TRADE_ROUTE, + GO_TO, LEAVE_SHIP, UNLOAD, } @@ -354,6 +346,10 @@ public void actionPerformed(ActionEvent ae) { case ASSIGN_TRADE_ROUTE: getGUI().showTradeRoutePanel(this.unit); break; + case GO_TO: + igc.putOutsideColony(this.unit); + igc.goTo(this.unit, game.getFreeColGameObject(args[1], UnitLocation.class)); + break; case LEAVE_SHIP: igc.leaveShip(this.unit); break; diff --git a/src/net/sf/freecol/client/gui/panel/QuickActionMenu.java b/src/net/sf/freecol/client/gui/panel/QuickActionMenu.java index 2ec58e97dd..6e76e2bfa0 100644 --- a/src/net/sf/freecol/client/gui/panel/QuickActionMenu.java +++ b/src/net/sf/freecol/client/gui/panel/QuickActionMenu.java @@ -19,30 +19,18 @@ package net.sf.freecol.client.gui.panel; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.util.*; -import java.util.logging.Logger; - -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; - import net.miginfocom.swing.MigLayout; - import net.sf.freecol.client.FreeColClient; import net.sf.freecol.client.control.InGameController; -import net.sf.freecol.client.gui.*; -import net.sf.freecol.client.gui.panel.ColonyPanel.TilesPanel.ASingleTilePanel; +import net.sf.freecol.client.gui.GUI; +import net.sf.freecol.client.gui.ImageLibrary; +import net.sf.freecol.client.gui.ModifierFormat; +import net.sf.freecol.client.gui.dialog.SelectDestinationDialog; import net.sf.freecol.client.gui.label.GoodsLabel; import net.sf.freecol.client.gui.label.MarketLabel; import net.sf.freecol.client.gui.label.UnitLabel; import net.sf.freecol.client.gui.label.UnitLabel.UnitAction; +import net.sf.freecol.client.gui.panel.ColonyPanel.TilesPanel.ASingleTilePanel; import net.sf.freecol.common.FreeColException; import net.sf.freecol.common.debug.DebugUtils; import net.sf.freecol.common.debug.FreeColDebugger; @@ -57,20 +45,33 @@ import net.sf.freecol.common.model.GoodsType; import net.sf.freecol.common.model.Location; import net.sf.freecol.common.model.Player; +import net.sf.freecol.common.model.Role; 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.Role; import net.sf.freecol.common.model.Unit; -import net.sf.freecol.common.model.UnitChangeType; -import net.sf.freecol.common.model.UnitTypeChange; import net.sf.freecol.common.model.Unit.UnitState; +import net.sf.freecol.common.model.UnitChangeType; import net.sf.freecol.common.model.UnitLocation; import net.sf.freecol.common.model.UnitType; +import net.sf.freecol.common.model.UnitTypeChange; import net.sf.freecol.common.model.WorkLocation; import net.sf.freecol.common.option.GameOptions; -import static net.sf.freecol.common.util.CollectionUtils.*; -import static net.sf.freecol.common.util.StringUtils.*; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import static net.sf.freecol.common.util.CollectionUtils.find; +import static net.sf.freecol.common.util.CollectionUtils.sort; +import static net.sf.freecol.common.util.CollectionUtils.transform; +import static net.sf.freecol.common.util.StringUtils.lastPart; +import static net.sf.freecol.common.util.StringUtils.upCase; /** @@ -185,6 +186,7 @@ private void createUnitMenu(final UnitLabel unitLabel) { if (addTileItem(unitLabel)) this.addSeparator(); if (addWorkItems(unitLabel)) this.addSeparator(); if (addEducationItems(unitLabel)) this.addSeparator(); + if (addGoToItems(unitLabel)) this.addSeparator(); if (unit.isInColony() && colony.canReducePopulation()) { JMenuItem menuItem = Utility.localizedMenuItem("quickActionMenu.leaveTown"); menuItem.setActionCommand(UnitAction.LEAVE_TOWN.toString()); @@ -289,7 +291,6 @@ private List descendingList(final Map map) { return sort(map.keySet(), comp); } - private JMenuItem makeProductionItem(GoodsType type, WorkLocation wl, int amount, UnitLabel unitLabel, boolean claim) { @@ -313,6 +314,35 @@ private JMenuItem makeProductionItem(GoodsType type, WorkLocation wl, } + private boolean addGoToItems(UnitLabel unitLabel) { + Unit unit = unitLabel.getUnit(); + JMenu container = Utility.localizedMenu("quickActionMenu.goto"); + List destinations = SelectDestinationDialog.getPossibleDestinations(unit, unit.getGame()); + for (SelectDestinationDialog.Destination destination : destinations) { + Location location = destination.getLocation(); + if (!includeLocation(location, unit.getOwner())) { + continue; + } + JMenuItem menuItem = new JMenuItem(destination.getText()); + menuItem.setActionCommand(UnitAction.GO_TO + "/" + location.getId()); + menuItem.addActionListener(unitLabel); + container.add(menuItem); + } + if (container.getItemCount() == 0) { + return false; + } + this.add(container); + return true; + } + + private boolean includeLocation(Location location, Player owner) { + if (location instanceof Europe) { + return true; + } + Colony colony = location.getColony(); + return colony != null && colony.getOwner() == owner; + } + private boolean addWorkItems(final UnitLabel unitLabel) { final Unit unit = unitLabel.getUnit(); if (unit.isCarrier()) return false;