Refactor context menu building logic for editor tables

This commit is contained in:
drdev
2014-01-05 22:26:01 +00:00
parent ba7cd330e6
commit 802aed63df
14 changed files with 229 additions and 182 deletions

1
.gitattributes vendored
View File

@@ -15443,6 +15443,7 @@ forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java -text
forge-gui/src/main/java/forge/gui/player/TargetSelection.java svneol=native#text/plain
forge-gui/src/main/java/forge/gui/player/package-info.java -text
forge-gui/src/main/java/forge/gui/toolbox/CardFaceSymbols.java svneol=native#text/plain
forge-gui/src/main/java/forge/gui/toolbox/ContextMenuBuilder.java -text
forge-gui/src/main/java/forge/gui/toolbox/FAbsolutePositioner.java -text
forge-gui/src/main/java/forge/gui/toolbox/FButton.java -text
forge-gui/src/main/java/forge/gui/toolbox/FCheckBox.java -text

View File

@@ -17,15 +17,11 @@
*/
package forge.gui.deckeditor;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map.Entry;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
@@ -33,7 +29,6 @@ import javax.swing.event.ListSelectionListener;
import forge.Command;
import forge.Singletons;
import forge.deck.DeckBase;
import forge.gui.GuiUtils;
import forge.gui.deckeditor.controllers.ACEditorBase;
import forge.gui.deckeditor.controllers.CEditorConstructed;
import forge.gui.deckeditor.controllers.CProbabilities;
@@ -45,7 +40,6 @@ import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
import forge.gui.match.controllers.CDetail;
import forge.gui.match.controllers.CPicture;
import forge.gui.toolbox.FMouseAdapter;
import forge.gui.toolbox.itemmanager.ItemManager;
import forge.gui.toolbox.itemmanager.SItemManagerIO;
import forge.gui.toolbox.itemmanager.SItemManagerIO.EditorPreference;
@@ -195,120 +189,10 @@ public enum CDeckEditorUI implements ICDoc {
}, Integer.MAX_VALUE);
}
//========== Other methods
private interface _MoveCard {
void moveCard(boolean toAlternate, int qty);
}
private class _ContextMenuBuilder implements ACEditorBase.ContextMenuBuilder {
private final MouseEvent _e;
private final ItemManager<?> _itemManager;
private final ItemManager<?> _nextItemManager;
private final _MoveCard _onMove;
private final JPopupMenu _menu = new JPopupMenu("ItemViewContextMenu");
public _ContextMenuBuilder(MouseEvent e, ItemManager<?> itemManager, ItemManager<?> nextItemManager, _MoveCard onMove) {
_e = e;
_itemManager = itemManager;
_nextItemManager = nextItemManager;
_onMove = onMove;
//ensure the item manager has focus
itemManager.focus();
//if item under the cursor is not selected, select it
int index = itemManager.getTable().getIndexAtPoint(e.getPoint());
boolean needSelection = true;
for (Integer selectedIndex : itemManager.getSelectedIndices()) {
if (selectedIndex == index) {
needSelection = false;
break;
}
}
if (needSelection) {
itemManager.setSelectedIndex(index);
}
}
private void show() {
_menu.addSeparator();
GuiUtils.addMenuItem(_menu, "Jump to previous table",
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new Runnable() {
@Override public void run() { _nextItemManager.focus(); }
});
GuiUtils.addMenuItem(_menu, "Jump to next table",
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new Runnable() {
@Override public void run() { _nextItemManager.focus(); }
});
GuiUtils.addMenuItem(_menu, "Jump to text filter",
KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override public void run() {
_itemManager.focusSearch();
}
});
_menu.show(_e.getComponent(), _e.getX(), _e.getY());
}
private String _doNoun(String nounSingular, String nounPlural) {
int numSelected = _itemManager.getSelectionCount();
if (1 == numSelected) {
return nounSingular;
}
return String.format("%d %s", numSelected, nounPlural);
}
private String _doDest(String destination) {
if (null == destination) {
return "";
}
return " " + destination;
}
@Override
public void addMoveItems(String verb, String nounSingular, String nounPlural, String destination) {
String noun = _doNoun(nounSingular, nounPlural);
String dest = _doDest(destination);
GuiUtils.addMenuItem(_menu,
String.format("%s %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), new Runnable() {
@Override public void run() { _onMove.moveCard(false, 1); }
}, true, true);
GuiUtils.addMenuItem(_menu,
String.format("%s 4 copies of %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.SHIFT_DOWN_MASK), new Runnable() {
@Override public void run() { _onMove.moveCard(false, 4); }
});
}
@Override
public void addMoveAlternateItems(String verb, String nounSingular, String nounPlural, String destination) {
String noun = _doNoun(nounSingular, nounPlural);
String dest = _doDest(destination);
// yes, CTRL_DOWN_MASK and not getMenuShortcutKeyMask(). On OSX, cmd-space is hard-coded to bring up Spotlight
GuiUtils.addMenuItem(_menu,
String.format("%s %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_DOWN_MASK), new Runnable() {
@Override public void run() { _onMove.moveCard(true, 1); }
});
// getMenuShortcutKeyMask() instead of CTRL_DOWN_MASK since on OSX, ctrl-shift-space brings up the window manager
GuiUtils.addMenuItem(_menu,
String.format("%s 4 copies of %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.SHIFT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override public void run() { _onMove.moveCard(true, 4); }
});
}
}
/**
* Set current editor controller
*/
@SuppressWarnings("serial")
private void setCurrentEditorController(ACEditorBase<? extends InventoryItem, ? extends DeckBase> childController0) {
this.childController = childController0;
Singletons.getControl().getForgeMenu().setProvider(childController0);
@@ -362,49 +246,22 @@ public enum CDeckEditorUI implements ICDoc {
}
});
final _MoveCard onAdd = new _MoveCard() {
catView.setItemActivateCommand(new Command() {
@Override
public void moveCard(boolean toAlternate, int qty) {
addSelectedCards(toAlternate, qty);
}
};
final _MoveCard onRemove = new _MoveCard() {
@Override
public void moveCard(boolean toAlternate, int qty) {
removeSelectedCards(toAlternate, qty);
}
};
catTable.getComponent().addMouseListener(new FMouseAdapter() {
@Override
public void onLeftDoubleClick(MouseEvent e) {
if (e.isConsumed()) { return; } //don't add cards if inline button double clicked
public void run() {
addSelectedCards(false, 1);
}
@Override
public void onRightClick(MouseEvent e) {
_ContextMenuBuilder cmb = new _ContextMenuBuilder(e, catView, deckView, onAdd);
childController.buildAddContextMenu(cmb);
cmb.show();
}
});
deckTable.getComponent().addMouseListener(new FMouseAdapter() {
deckView.setItemActivateCommand(new Command() {
@Override
public void onLeftDoubleClick(MouseEvent e) {
if (e.isConsumed()) { return; } //don't remove cards if inline button double clicked
public void run() {
removeSelectedCards(false, 1);
}
@Override
public void onRightClick(MouseEvent e) {
_ContextMenuBuilder cmb = new _ContextMenuBuilder(e, deckView, catView, onRemove);
childController.buildRemoveContextMenu(cmb);
cmb.show();
}
});
catView.setContextMenuBuilder(childController.createContextMenuBuilder(true));
deckView.setContextMenuBuilder(childController.createContextMenuBuilder(false));
//set card when selection changes
catView.addSelectionListener(new ListSelectionListener() {
@Override

View File

@@ -17,15 +17,20 @@
*/
package forge.gui.deckeditor.controllers;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Map.Entry;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import forge.Command;
import forge.deck.DeckBase;
import forge.deck.DeckSection;
import forge.gui.GuiUtils;
import forge.gui.deckeditor.CDeckEditorUI;
import forge.gui.deckeditor.menus.CDeckEditorUIMenus;
import forge.gui.framework.DragCell;
@@ -34,6 +39,7 @@ import forge.gui.framework.ICDoc;
import forge.gui.framework.IVDoc;
import forge.gui.framework.SRearrangingUtil;
import forge.gui.menus.IMenuProvider;
import forge.gui.toolbox.ContextMenuBuilder;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
import forge.gui.toolbox.itemmanager.ItemManager;
@@ -57,19 +63,6 @@ import forge.view.FView;
* @param <TModel> extends {@link forge.deck.DeckBase}
*/
public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends DeckBase> implements IMenuProvider {
public interface ContextMenuBuilder {
/**
* Adds move-related items to the context menu
*
* @param verb Examples: "Sell", "Add"
* @param nounSingular Examples: "item", "card"
* @param nounPlural Examples: "items", "cards"
* @param destination Examples: null, "to deck", "to sideboard"
*/
public void addMoveItems (String verb, String nounSingular, String nounPlural, String destination);
public void addMoveAlternateItems (String verb, String nounSingular, String nounPlural, String destination);
}
public boolean listenersHooked;
private final FScreen screen;
private ItemManager<TItem> catalogManager;
@@ -183,8 +176,8 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
*/
protected abstract void onRemoveItems(Iterable<Entry<TItem, Integer>> items, boolean toAlternate);
public abstract void buildAddContextMenu(ContextMenuBuilder cmb);
public abstract void buildRemoveContextMenu(ContextMenuBuilder cmb);
protected abstract void buildAddContextMenu(EditorContextMenuBuilder cmb);
protected abstract void buildRemoveContextMenu(EditorContextMenuBuilder cmb);
/**
* Resets the cards in the catalog table and current deck table.
@@ -320,4 +313,136 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
public FLabel getBtnRemove() { return btnRemove; }
public FLabel getBtnRemove4() { return btnRemove4; }
public FLabel getBtnCycleSection() { return btnCycleSection; }
public ContextMenuBuilder createContextMenuBuilder(boolean isAddContextMenu0) {
return new EditorContextMenuBuilder(isAddContextMenu0);
}
protected class EditorContextMenuBuilder implements ContextMenuBuilder {
private final boolean isAddContextMenu;
private JPopupMenu menu;
private EditorContextMenuBuilder(boolean isAddContextMenu0) {
isAddContextMenu = isAddContextMenu0;
}
private ItemManager<?> getItemManager() {
return isAddContextMenu ? catalogManager : deckManager;
}
private ItemManager<?> getNextItemManager() {
return isAddContextMenu ? deckManager : catalogManager;
}
private void moveCard(boolean toAlternate, int qty) {
if (isAddContextMenu) {
CDeckEditorUI.SINGLETON_INSTANCE.addSelectedCards(toAlternate, qty);
}
else {
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(toAlternate, qty);
}
}
@Override
public void buildContextMenu(JPopupMenu menu) {
this.menu = menu; //cache menu while controller populates menu
if (isAddContextMenu) {
buildAddContextMenu(this);
}
else {
buildRemoveContextMenu(this);
}
this.menu = null;
menu.addSeparator();
GuiUtils.addMenuItem(menu, "Jump to previous table",
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
new Runnable() {
@Override
public void run() {
getNextItemManager().focus();
}
});
GuiUtils.addMenuItem(menu, "Jump to next table",
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
new Runnable() {
@Override
public void run() {
getNextItemManager().focus();
}
});
GuiUtils.addMenuItem(menu, "Jump to text filter",
KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override
public void run() {
getItemManager().focusSearch();
}
});
}
private String doNoun(String nounSingular, String nounPlural) {
int numSelected = getItemManager().getSelectionCount();
if (1 == numSelected) {
return nounSingular;
}
return String.format("%d %s", numSelected, nounPlural);
}
private String doDest(String destination) {
if (null == destination) {
return "";
}
return " " + destination;
}
public void addMoveItems(String verb, String nounSingular, String nounPlural, String destination) {
String noun = doNoun(nounSingular, nounPlural);
String dest = doDest(destination);
GuiUtils.addMenuItem(menu,
String.format("%s %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), new Runnable() {
@Override
public void run() {
moveCard(false, 1);
}
}, true, true);
GuiUtils.addMenuItem(menu,
String.format("%s 4 copies of %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.SHIFT_DOWN_MASK), new Runnable() {
@Override
public void run() {
moveCard(false, 4);
}
});
}
public void addMoveAlternateItems(String verb, String nounSingular, String nounPlural, String destination) {
String noun = doNoun(nounSingular, nounPlural);
String dest = doDest(destination);
// yes, CTRL_DOWN_MASK and not getMenuShortcutKeyMask(). On OSX, cmd-space is hard-coded to bring up Spotlight
GuiUtils.addMenuItem(menu,
String.format("%s %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_DOWN_MASK), new Runnable() {
@Override
public void run() {
moveCard(true, 1);
}
});
// getMenuShortcutKeyMask() instead of CTRL_DOWN_MASK since on OSX, ctrl-shift-space brings up the window manager
GuiUtils.addMenuItem(menu,
String.format("%s 4 copies of %s%s", verb, noun, dest),
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.SHIFT_DOWN_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
new Runnable() {
@Override
public void run() {
moveCard(true, 4);
}
});
}
}
}

View File

@@ -143,12 +143,12 @@ public final class CEditorCommander extends ACEditorBase<PaperCard, Deck> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to deck");
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to sideboard");
}

View File

@@ -150,13 +150,13 @@ public final class CEditorConstructed extends ACEditorBase<PaperCard, Deck> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems(sectionMode == DeckSection.Sideboard ? "Move" : "Add", "card", "cards", sectionMode == DeckSection.Sideboard ? "to sideboard" : "to deck");
cmb.addMoveAlternateItems(sectionMode == DeckSection.Sideboard ? "Remove" : "Add", "card", "cards", sectionMode == DeckSection.Sideboard ? "from deck" : "to sideboard");
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems(sectionMode == DeckSection.Sideboard ? "Move" : "Remove", "card", "cards", sectionMode == DeckSection.Sideboard ? "to deck" : "from deck");
cmb.addMoveAlternateItems(sectionMode == DeckSection.Sideboard ? "Remove" : "Move", "card", "cards", sectionMode == DeckSection.Sideboard ? "from sideboard" : "to sideboard");
}

View File

@@ -116,12 +116,12 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Draft", "card", "cards", null);
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
// no valid remove options
}

View File

@@ -118,12 +118,12 @@ public final class CEditorLimited extends ACEditorBase<PaperCard, DeckGroup> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to deck");
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to sideboard");
}

View File

@@ -184,13 +184,13 @@ public final class CEditorQuest extends ACEditorBase<PaperCard, Deck> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems(sideboardMode ? "Move" : "Add", "card", "cards", sideboardMode ? "to sideboard" : "to deck");
cmb.addMoveAlternateItems(sideboardMode ? "Remove" : "Add", "card", "cards", sideboardMode ? "from deck" : "to sideboard");
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems(sideboardMode ? "Move" : "Remove", "card", "cards", sideboardMode ? "to deck" : "from deck");
cmb.addMoveAlternateItems(sideboardMode ? "Remove" : "Move", "card", "cards", sideboardMode ? "from sideboard" : "to sideboard");
}

View File

@@ -433,14 +433,14 @@ public final class CEditorQuestCardShop extends ACEditorBase<InventoryItem, Deck
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
if (!showingFullCatalog) {
cmb.addMoveItems("Buy", "item", "items", null);
}
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
if (!showingFullCatalog) {
cmb.addMoveItems("Sell", "card", "cards", null);
}

View File

@@ -108,12 +108,12 @@ public final class CEditorVariant extends ACEditorBase<PaperCard, Deck> {
}
@Override
public void buildAddContextMenu(ContextMenuBuilder cmb) {
protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to deck");
}
@Override
public void buildRemoveContextMenu(ContextMenuBuilder cmb) {
protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
cmb.addMoveItems("Move", "card", "cards", "to sideboard");
}

View File

@@ -0,0 +1,7 @@
package forge.gui.toolbox;
import javax.swing.JPopupMenu;
public interface ContextMenuBuilder {
void buildContextMenu(JPopupMenu menu);
}

View File

@@ -22,6 +22,7 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -46,6 +47,7 @@ import com.google.common.collect.Iterables;
import forge.Command;
import forge.gui.GuiUtils;
import forge.gui.toolbox.ContextMenuBuilder;
import forge.gui.toolbox.FComboBoxWrapper;
import forge.gui.toolbox.FLabel;
import forge.gui.toolbox.FSkin;
@@ -81,6 +83,8 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
private boolean alwaysNonUnique = false;
private boolean allowMultipleSelections = false;
private boolean hideFilters = false;
private Command itemActivateCommand;
private ContextMenuBuilder contextMenuBuilder;
private final Class<T> genericType;
private final ArrayList<ListSelectionListener> selectionListeners = new ArrayList<ListSelectionListener>();
@@ -974,4 +978,43 @@ public abstract class ItemManager<T extends InventoryItem> extends JPanel {
public Iterable<ListSelectionListener> getSelectionListeners() {
return selectionListeners;
}
public void setItemActivateCommand(Command itemActivateCommand0) {
this.itemActivateCommand = itemActivateCommand0;
}
public void activateSelectedItems() {
if (this.itemActivateCommand != null) {
this.itemActivateCommand.run();
}
}
public void setContextMenuBuilder(ContextMenuBuilder contextMenuBuilder0) {
this.contextMenuBuilder = contextMenuBuilder0;
}
public void showContextMenu(MouseEvent e) {
if (this.contextMenuBuilder == null) { return; }
//ensure the item manager has focus
this.focus();
//if item under the cursor is not selected, select it
int index = this.getTable().getIndexAtPoint(e.getPoint());
boolean needSelection = true;
for (Integer selectedIndex : this.getSelectedIndices()) {
if (selectedIndex == index) {
needSelection = false;
break;
}
}
if (needSelection) {
this.setSelectedIndex(index);
}
JPopupMenu menu = new JPopupMenu("ItemManagerContextMenu");
this.contextMenuBuilder.buildContextMenu(menu);
menu.show(e.getComponent(), e.getX(), e.getY());
}
}

View File

@@ -108,6 +108,18 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
}
}
});
this.table.addMouseListener(new FMouseAdapter() {
@Override
public void onLeftDoubleClick(MouseEvent e) {
if (e.isConsumed()) { return; } //don't activate if inline button double clicked
getItemManager().activateSelectedItems();
}
@Override
public void onRightClick(MouseEvent e) {
getItemManager().showContextMenu(e);
}
});
this.skin.setFont(FSkin.getFont(12));
this.table.setBorder(null);

View File

@@ -38,15 +38,17 @@ public abstract class ItemView<T extends InventoryItem> {
}
public void initialize() {
final JComponent comp = this.getComponent();
//hook incremental search functionality
final IncrementalSearch incrementalSearch = new IncrementalSearch();
this.getComponent().addFocusListener(new FocusAdapter() {
comp.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent arg0) {
incrementalSearch.cancel();
}
});
this.getComponent().addKeyListener(incrementalSearch);
comp.addKeyListener(incrementalSearch);
}
public ItemManager<T> getItemManager() {