Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

13168 Multi-Location Command includes the option to sort the order of the commands generated #13168

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion vassal-app/src/main/java/VASSAL/build/GameModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@
import VASSAL.tools.menu.MenuManager;
import VASSAL.tools.swing.SwingUtils;
import VASSAL.tools.version.VersionUtils;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import VASSAL.counters.KeyBuffer;
import VASSAL.counters.KeyCommand;
import VASSAL.counters.KeyCommandSubMenu;
import VASSAL.counters.MultiLocationCommand;
import VASSAL.counters.MenuSeparator;
import VASSAL.counters.MultiLocationCommand;
import VASSAL.counters.PieceFinder;
import VASSAL.counters.Properties;
import VASSAL.tools.NamedKeyManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,15 @@ public Point snapTo(Point p) {
return snapTo(p, false, false);
}

/**
* @return a center point for the zone
*/
public Point getCenter() {
final Rectangle r = getBounds();
final Rectangle r2 = getBoard().bounds();
return new Point(r2.x + r.x + r.width / 2, r2.y + r.y + r.height / 2);
}

@Override
public Dimension getSize() {
return myPolygon.getBounds().getSize();
Expand Down
1 change: 1 addition & 0 deletions vassal-app/src/main/java/VASSAL/counters/KeyBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ public Command keyCommand(javax.swing.KeyStroke stroke) {
}
}
}

for (final GamePiece p : targets) {
bounds.addPiece(p);
p.setProperty(Properties.SNAPSHOT, ((PropertyExporter) p).getProperties()); // save state prior to command
Expand Down
83 changes: 79 additions & 4 deletions vassal-app/src/main/java/VASSAL/counters/MultiLocationCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@
import VASSAL.tools.FormattedString;
import VASSAL.tools.NamedKeyStroke;
import VASSAL.tools.SequenceEncoder;
import org.apache.commons.lang3.math.NumberUtils;

import javax.swing.KeyStroke;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
Expand All @@ -68,6 +70,8 @@ public class MultiLocationCommand extends Decorator implements TranslatablePiece
public static final String LOC_ZONE = "ZoneOfCommand"; //NON-NLS
public static final String LOC_BOARD = "BoardOfCommand"; //NON-NLS
public static final String LOC_MAP = "MapOfCommand"; //NON-NLS
public static final String LOC_X = "XOfCommand"; //NON-NLS
public static final String LOC_Y = "YOfCommand"; //NON-NLS

public static final String LOC_REGIONS = "locRegions"; //NON-NLS
public static final String LOC_ZONES = "locZones"; //NON-NLS
Expand All @@ -80,6 +84,9 @@ public class MultiLocationCommand extends Decorator implements TranslatablePiece
protected Boolean curMapOnly = true;
protected PropertyExpression propertiesFilter = new PropertyExpression("");
protected FormattedString menuText = new FormattedString("");
protected FormattedString menuSort = new FormattedString("");
protected Boolean ascending = true;
protected Boolean numeric = true;
protected NamedKeyStroke key;

// Private stuff (shhhh!)
Expand All @@ -89,6 +96,8 @@ public class MultiLocationCommand extends Decorator implements TranslatablePiece
private String evalZone = "";
private String evalBoard = "";
private String evalMap = "";
private String evalX = "";
private String evalY = "";
private boolean everBuilt = false;

/**
Expand All @@ -101,13 +110,31 @@ public static class MultiLocationKeyCommand extends KeyCommand {
private final String zoneName;
private final String boardName;
private final String mapName;
private final String xName;
private final String yName;
private final String sortKey;

// For backwards compatibility
public MultiLocationKeyCommand(String name, NamedKeyStroke key, GamePiece target, TranslatablePiece i18nPiece, String locationName, String zoneName, String boardName, String mapName) {
super(name, key, target, i18nPiece);
this.locationName = locationName;
this.zoneName = zoneName;
this.boardName = boardName;
this.mapName = mapName;
xName = "";
yName = "";
sortKey = "";
}

public MultiLocationKeyCommand(String name, NamedKeyStroke key, GamePiece target, TranslatablePiece i18nPiece, String locationName, String zoneName, String boardName, String mapName, String xName, String yName, String sortKey) {
super(name, key, target, i18nPiece);
this.locationName = locationName;
this.zoneName = zoneName;
this.boardName = boardName;
this.mapName = mapName;
this.xName = xName;
this.yName = yName;
this.sortKey = sortKey;
}

public String getLocationName() {
Expand Down Expand Up @@ -141,6 +168,12 @@ else if (LOC_BOARD.equals(key)) {
else if (LOC_MAP.equals(key)) {
return evalMap;
}
else if (LOC_X.equals(key)) {
return evalX;
}
else if (LOC_Y.equals(key)) {
return evalY;
}
else {
return Decorator.getOutermost(piece).getProperty(key);
}
Expand Down Expand Up @@ -173,6 +206,9 @@ public void mySetType(String type) {
menuText.setFormat(st.nextToken(Resources.getString("Editor.MultiLocationCommand.loc_default_command")));
key = st.nextNamedKeyStroke();
curMapOnly = st.nextBoolean(true);
menuSort.setFormat(st.nextToken(""));
ascending = st.nextBoolean(true);
numeric = st.nextBoolean(false);
}

@Override
Expand All @@ -183,7 +219,10 @@ public String myGetType() {
.append(propertiesFilter.getExpression())
.append(menuText.getFormat())
.append(key)
.append(curMapOnly);
.append(curMapOnly)
.append(menuSort.getFormat())
.append(ascending)
.append(numeric);
return ID + se.getValue();
}

Expand Down Expand Up @@ -242,7 +281,11 @@ private void tryName(String name) {
if (propertiesFilter.getExpression().isBlank() || propertiesFilter.isTrue(locPS)) {
final AuditTrail audit = AuditTrail.create(locPS, menuText.getFormat(), Resources.getString("Editor.MultiLocationCommand.evaluate_menu_text"));
final String myMenuText = menuText.getLocalizedText(locPS, this, audit);
keyCommands.add(new MultiLocationKeyCommand(myMenuText, key, Decorator.getOutermost(this), this, evalLocation, evalZone, evalBoard, evalMap));

final AuditTrail audit2 = AuditTrail.create(locPS, menuSort.getFormat(), Resources.getString("Editor.MultiLocationCommand.evaluate_sort_string"));
final String myMenuSort = menuSort.getLocalizedText(locPS, this, audit2);

keyCommands.add(new MultiLocationKeyCommand(myMenuText, key, Decorator.getOutermost(this), this, evalLocation, evalZone, evalBoard, evalMap, evalX, evalY, myMenuSort));
}
}

Expand All @@ -251,6 +294,9 @@ private void tryName(String name) {
* @param zone zone to test
*/
private void tryZone(Zone zone) {
final Point center = zone.getCenter();
evalX = String.valueOf(center.x);
evalY = String.valueOf(center.y);
tryName(zone.getName());
}

Expand All @@ -259,6 +305,11 @@ private void tryZone(Zone zone) {
* @param region region to test
*/
private void tryRegion(Region region) {
final Rectangle r2 = region.getBoard().bounds();
final Point loc = new Point(region.getOrigin().x + r2.x, region.getOrigin().y + r2.y);

evalX = String.valueOf(loc.x);
evalY = String.valueOf(loc.y);
tryName(region.getName());
}

Expand Down Expand Up @@ -325,6 +376,10 @@ public KeyCommand[] myGetKeyCommands() {
}
}

keyCommands.sort((left, right) -> ((numeric && NumberUtils.isParsable(left.sortKey) && NumberUtils.isParsable(right.sortKey)) ?
Integer.compare(NumberUtils.toInt(left.sortKey), NumberUtils.toInt(right.sortKey)) * (ascending ? 1 : -1) :
left.sortKey.compareTo(right.sortKey) * (ascending ? 1 : -1)));

return keyCommands.toArray(new KeyCommand[0]);
}

Expand Down Expand Up @@ -361,6 +416,8 @@ public Command myKeyEvent(KeyStroke stroke) {
setProperty(LOC_ZONE, ((MultiLocationKeyCommand) kc).zoneName);
setProperty(LOC_BOARD, ((MultiLocationKeyCommand) kc).boardName);
setProperty(LOC_MAP, ((MultiLocationKeyCommand) kc).mapName);
setProperty(LOC_X, ((MultiLocationKeyCommand) kc).xName);
setProperty(LOC_Y, ((MultiLocationKeyCommand) kc).yName);
}

return null;
Expand Down Expand Up @@ -411,6 +468,9 @@ public boolean testEquals(Object o) {
if (!Objects.equals(propertiesFilter.getExpression(), c.propertiesFilter.getExpression())) return false;
if (!Objects.equals(menuText.getFormat(), c.menuText.getFormat())) return false;
if (!Objects.equals(curMapOnly, c.curMapOnly)) return false;
if (!Objects.equals(menuSort.getFormat(), c.menuSort.getFormat())) return false;
if (!Objects.equals(ascending, c.ascending)) return false;
if (!Objects.equals(numeric, c.numeric)) return false;
return Objects.equals(key, c.key);
}

Expand All @@ -424,7 +484,7 @@ public HelpFile getHelpFile() {
*/
@Override
public List<String> getPropertyNames() {
return Arrays.asList(LOC_BOARD, LOC_MAP, LOC_NAME, LOC_ZONE);
return Arrays.asList(LOC_BOARD, LOC_MAP, LOC_NAME, LOC_ZONE, LOC_X, LOC_Y);
}

public static class Ed implements PieceEditor {
Expand All @@ -434,6 +494,9 @@ public static class Ed implements PieceEditor {
private final PropertyExpressionConfigurer propertyMatchInput;
private final FormattedStringConfigurer menuTextInput;
private final NamedHotKeyConfigurer keyInput;
private final FormattedStringConfigurer menuSortInput;
private final BooleanConfigurer ascendingInput;
private final BooleanConfigurer numericInput;

private final TraitConfigPanel controls;

Expand Down Expand Up @@ -463,6 +526,15 @@ public Ed(MultiLocationCommand p) {
menuTextInput = new FormattedExpressionConfigurer(p.menuText.getFormat(), p);
controls.add("Editor.MultiLocationCommand.menu_format", menuTextInput);

menuSortInput = new FormattedExpressionConfigurer(p.menuSort.getFormat(), p);
controls.add("Editor.MultiLocationCommand.menu_sort", menuSortInput);

ascendingInput = new BooleanConfigurer(p.ascending);
controls.add("Editor.MultiLocationCommand.ascending", ascendingInput);

numericInput = new BooleanConfigurer(p.numeric);
controls.add("Editor.MultiLocationCommand.numeric", numericInput);

keyInput = new NamedHotKeyConfigurer(p.key);
controls.add("Editor.MultiLocationCommand.key_command", keyInput);
}
Expand All @@ -480,7 +552,10 @@ public String getType() {
.append(propertyMatchInput.getValueString())
.append(menuTextInput.getValueString())
.append(keyInput.getValueString())
.append(curMapOnlyInput.getValueString());
.append(curMapOnlyInput.getValueString())
.append(menuSortInput.getValueString())
.append(ascendingInput.getValueString())
.append(numericInput.getValueString());

return ID + se.getValue();
}
Expand Down
4 changes: 1 addition & 3 deletions vassal-app/src/main/java/VASSAL/counters/SendToLocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -436,9 +436,7 @@ else if (auditSource instanceof AbstractConfigurable) {
}
}
else {
final Rectangle r = z.getBounds();
final Rectangle r2 = z.getBoard().bounds();
dest = new Point(r2.x + r.x + r.width / 2, r2.y + r.y + r.height / 2);
dest = z.getCenter();
}
break;

Expand Down
4 changes: 4 additions & 0 deletions vassal-app/src/main/resources/VASSAL/i18n/Editor.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1715,7 +1715,11 @@ Editor.MultiLocationCommand.evaluate_menu_text=Evaluating menu text in Location
Editor.MultiLocationCommand.location_type=Type of Location
Editor.MultiLocationCommand.matching_properties=Matching Properties
Editor.MultiLocationCommand.menu_format=Menu item format
Editor.MultiLocationCommand.menu_sort=Sort menu items by this key string
Editor.MultiLocationCommand.ascending=Ascending sort
Editor.MultiLocationCommand.numeric=Numeric sort
Editor.MultiLocationCommand.key_command=Key Command generated by menu item
Editor.MultiLocationCommand.evaluate_sort_string=Evaluating sort string in Location Command

# Multi-Zone Grid
Editor.MultiZoneGrid.component_type=Multi-zoned Grid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ Whenever the player selects _any_ of the menu items associated with a Multi-Loca

*Menu item format:*:: The format for constructing menu items from the locations. The trait's properties (e.g., _LocationOfCommand_, etc) can be used with $..$ to make string substitutions.

*Sort menu items by this keystring:*:: This field lets you provide a keystring to control the order that the generated commands will appear in the context menu. For example ``$LocationOfCommand$`` would sort based on the location name, or ``$YOfCommand`` would order the list based on the Y position (i.e. from north to south).

*Ascending sort:*:: Controls whether an ascending or descending sort is used.

*Numeric sort:*:: If this box is checked, the sort key is considered to be a numeric field (so that e.g. "90" is treated as lower than "100" which wouldn't be true in an alphabetic sort). If unchecked an alphabetic sort is performed.

*Key command generated by menu item:*:: Whenever any menu item generated by this trait is picked by the player, this key command will be generated.

|image:images/MultiLocationCommand.png[]
Expand Down Expand Up @@ -55,5 +61,9 @@ A Multi-Location trait exposes the following <<Properties.adoc#top,Properties>>.

* _MapOfCommand_ The map of the command

* _XOfCommand_ The X position on the map of the command

* _YOfCommand_ The Y position on the map of the command