Added connector click events

git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@94 72836036-5685-4462-b002-a69064685172
This commit is contained in:
Bennet Gerlach 2011-05-03 20:39:21 +02:00
parent e7613bfd93
commit 344d63598a
6 changed files with 392 additions and 308 deletions

View file

@ -140,6 +140,22 @@ public class JRummikub {
} }
}); });
view.getTablePanel().getLeftConnectorClickEvent()
.add(new IListener1<StoneSet>() {
@Override
public void handle(StoneSet s) {
System.out.println("Left connector clicked on " + s);
}
});
view.getTablePanel().getRightConnectorClickEvent()
.add(new IListener1<StoneSet>() {
@Override
public void handle(StoneSet s) {
System.out.println("Right connector clicked on " + s);
}
});
view.getTablePanel().getStoneCollectionPanel().getStoneClickEvent() view.getTablePanel().getStoneCollectionPanel().getStoneClickEvent()
.add(new IListener2<Stone, Boolean>() { .add(new IListener2<Stone, Boolean>() {
@Override @Override
@ -149,6 +165,7 @@ public class JRummikub {
} }
}); });
view.getTablePanel().getStoneCollectionPanel().getRangeClickEvent() view.getTablePanel().getStoneCollectionPanel().getRangeClickEvent()
.add(new IListener2<Stone, Boolean>() { .add(new IListener2<Stone, Boolean>() {
@Override @Override

View file

@ -1,6 +1,6 @@
package jrummikub.model; package jrummikub.model;
/** Class specifing possible StoneColors */ /** Class specifying possible StoneColors */
public enum StoneColor { public enum StoneColor {
BLACK, ORANGE, BLUE, RED BLACK, ORANGE, BLUE, RED
} }

View file

@ -4,48 +4,65 @@ import java.util.Map;
import jrummikub.model.Position; import jrummikub.model.Position;
import jrummikub.model.StoneSet; import jrummikub.model.StoneSet;
import jrummikub.util.Event1;
/** /**
* The view of the table, where the stone sets lie * The view of the table, where the stone sets lie
*/ */
public interface ITablePanel extends IStonePanel, IClickable { public interface ITablePanel extends IStonePanel, IClickable {
/** /**
* Sets the player name on the left label * Sets the player name on the left label
* *
* @param playerName * @param playerName
* the name to set * the name to set
*/ */
public void setLeftPlayerName(String playerName); public void setLeftPlayerName(String playerName);
/** /**
* Sets the player name on the top label * Sets the player name on the top label
* *
* @param playerName * @param playerName
* the name to set * the name to set
*/ */
public void setTopPlayerName(String playerName); public void setTopPlayerName(String playerName);
/** /**
* Sets the player name on the right label * Sets the player name on the right label
* *
* @param playerName * @param playerName
* the name to set * the name to set
*/ */
public void setRightPlayerName(String playerName); public void setRightPlayerName(String playerName);
/** /**
* Sets the stone sets lying on the table * Sets the stone sets lying on the table
* *
* @param stoneSets * @param stoneSets
* set stone sets on the table * set stone sets on the table
*/ */
public void setStoneSets(Map<StoneSet, Position> stoneSets); public void setStoneSets(Map<StoneSet, Position> stoneSets);
/** /**
* Returns the stone collection (the panel showing the stones currently * Returns the stone collection (the panel showing the stones currently
* selected) * selected)
* *
* @return the stone collection * @return the stone collection
*/ */
IStoneCollectionPanel getStoneCollectionPanel(); public IStoneCollectionPanel getStoneCollectionPanel();
/**
* the left connector click event is emitted when the player clicks on a left
* connector of a stone set on the table .
*
* @return the event
*/
public Event1<StoneSet> getLeftConnectorClickEvent();
/**
* the right connector click event is emitted when the player clicks on a
* right connector of a stone set on the table .
*
* @return the event
*/
public Event1<StoneSet> getRightConnectorClickEvent();
} }

View file

@ -21,117 +21,127 @@ import jrummikub.view.IStonePanel;
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
abstract class AbstractStonePanel extends JPanel implements IStonePanel, abstract class AbstractStonePanel extends JPanel implements IStonePanel,
IClickable { IClickable {
private StonePainter stonePainter; private StonePainter stonePainter;
private Event1<Position> clickEvent = new Event1<Position>(); private Event1<Position> clickEvent = new Event1<Position>();
private Event2<Stone, Boolean> stoneClickEvent = new Event2<Stone, Boolean>(); private Event2<Stone, Boolean> stoneClickEvent = new Event2<Stone, Boolean>();
private Event2<Stone, Boolean> rangeClickEvent = new Event2<Stone, Boolean>(); private Event2<Stone, Boolean> rangeClickEvent = new Event2<Stone, Boolean>();
private Event2<Stone, Boolean> setClickEvent = new Event2<Stone, Boolean>(); private Event2<Stone, Boolean> setClickEvent = new Event2<Stone, Boolean>();
private Map<Stone, Position> stones = Collections.emptyMap(); private Map<Stone, Position> stones = Collections.emptyMap();
/** /**
* @return the stone painter * @return the stone painter
*/ */
protected StonePainter getStonePainter() { protected StonePainter getStonePainter() {
return stonePainter; return stonePainter;
} }
/** /**
* Create a new StonePanel with default scale factor * Create a new StonePanel with default scale factor
*/ */
public AbstractStonePanel() { public AbstractStonePanel() {
this(1); this(1);
} }
/** /**
* Create a new StonePanel with a given scale factor * Create a new StonePanel with a given scale factor
* *
* @param scale * @param scale
* the grid scale * the grid scale
*/ */
public AbstractStonePanel(float scale) { public AbstractStonePanel(float scale) {
super(true); // Set double buffered super(true); // Set double buffered
stonePainter = new StonePainter(scale); stonePainter = new StonePainter(scale);
addMouseListener(new MouseAdapter() { addMouseListener(new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { public void mouseClicked(MouseEvent e) {
Insets insets = getInsets(); Insets insets = getInsets();
Position pos = stonePainter.calculatePosition(e.getX() - insets.left, Position pos = stonePainter.calculatePosition(e.getX() - insets.left,
e.getY() - insets.top); e.getY() - insets.top);
Stone stone = getStoneAt(pos); Stone stone = getStoneAt(pos);
if (stone == null) { if (stone == null) {
clickEvent.emit(pos); if (!handleOtherClickEvent(pos))
return; clickEvent.emit(pos);
}
Event2<Stone, Boolean> event = stoneClickEvent; return;
}
if (e.isShiftDown()) Event2<Stone, Boolean> event = stoneClickEvent;
event = rangeClickEvent;
else if (e.getClickCount() >= 2)
event = setClickEvent;
event.emit(stone, e.isControlDown()); if (e.isShiftDown())
} event = rangeClickEvent;
}); else if (e.getClickCount() >= 2)
} event = setClickEvent;
private Stone getStoneAt(Position pos) { event.emit(stone, e.isControlDown());
for (Map.Entry<Stone, Position> entry : stones.entrySet()) { }
Stone stone = entry.getKey(); });
Position p = entry.getValue(); }
Rectangle2D rect = new Rectangle2D.Float(p.getX(), p.getY(),
stone.getWidth(), stone.getHeight());
if (rect.contains(pos.getX(), pos.getY())) /*
return stone; * *Overwrite this method* to signal if special zone was clicked
} *
* @return special zone clicked
*/
protected boolean handleOtherClickEvent(Position pos) {
return false;
}
return null; private Stone getStoneAt(Position pos) {
} for (Map.Entry<Stone, Position> entry : stones.entrySet()) {
Stone stone = entry.getKey();
Position p = entry.getValue();
Rectangle2D rect = new Rectangle2D.Float(p.getX(), p.getY(), 1, 1);
/** if (rect.contains(pos.getX(), pos.getY()))
* Sets the list of stones that can be clicked on return stone;
* }
* @param stones
* the stones and positions
*/
protected void setStones(Map<Stone, Position> stones) {
this.stones = stones;
}
/** return null;
* Returns the list of stones and positions currently set }
*
* @return the stones
*/
protected Map<Stone, Position> getStones() {
return stones;
}
@Override /**
public Event1<Position> getClickEvent() { * Sets the list of stones that can be clicked on
return clickEvent; *
} * @param stones
* the stones and positions
*/
protected void setStones(Map<Stone, Position> stones) {
this.stones = stones;
}
@Override /**
public Event2<Stone, Boolean> getStoneClickEvent() { * Returns the list of stones and positions currently set
return stoneClickEvent; *
} * @return the stones
*/
protected Map<Stone, Position> getStones() {
return stones;
}
@Override @Override
public Event2<Stone, Boolean> getRangeClickEvent() { public Event1<Position> getClickEvent() {
return rangeClickEvent; return clickEvent;
} }
@Override @Override
public Event2<Stone, Boolean> getSetClickEvent() { public Event2<Stone, Boolean> getStoneClickEvent() {
return setClickEvent; return stoneClickEvent;
} }
@Override
public Event2<Stone, Boolean> getRangeClickEvent() {
return rangeClickEvent;
}
@Override
public Event2<Stone, Boolean> getSetClickEvent() {
return setClickEvent;
}
} }

View file

@ -20,70 +20,70 @@ import jrummikub.view.IStoneCollectionPanel;
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
class StoneCollectionPanel extends AbstractStonePanel implements class StoneCollectionPanel extends AbstractStonePanel implements
IStoneCollectionPanel { IStoneCollectionPanel {
private final static int INSET = 7; private final static int INSET = 7;
private final static float STONE_SCALE = 1.1f; private final static float STONE_SCALE = 1.1f;
private Collection<Stone> selectedStones = Collections.emptyList(); private Collection<Stone> selectedStones = Collections.emptyList();
/** /**
* Creates a new StoneCollection instance * Creates a new StoneCollection instance
*/ */
StoneCollectionPanel() { StoneCollectionPanel() {
super(STONE_SCALE); super(STONE_SCALE);
setOpaque(false); setOpaque(false);
setVisible(false); setVisible(false);
setBorder(new EmptyBorder(INSET, INSET, INSET, INSET)); setBorder(new EmptyBorder(INSET, INSET, INSET, INSET));
} }
/** /**
* Sets the stones to be shown in the collection * Sets the stones to be shown in the collection
* *
* @param selectedStones * @param selectedStones
* the selected stones * the selected stones
*/ */
void setSelectedStones(Collection<Stone> selectedStones) { void setSelectedStones(Collection<Stone> selectedStones) {
this.selectedStones = selectedStones; this.selectedStones = selectedStones;
Map<Stone, Position> stones = new HashMap<Stone, Position>(); Map<Stone, Position> stones = new HashMap<Stone, Position>();
float x = 0; float x = 0;
for (Stone stone : selectedStones) { for (Stone stone : selectedStones) {
stones.put(stone, new Position(x, 0)); stones.put(stone, new Position(x, 0));
x += stone.getWidth(); x++;
} }
setStones(stones); setStones(stones);
if (selectedStones.isEmpty()) { if (selectedStones.isEmpty()) {
setVisible(false); setVisible(false);
} else { } else {
setSize(getStonePainter().getStoneWidth() * selectedStones.size() + 2 setSize(getStonePainter().getStoneWidth() * selectedStones.size() + 2
* INSET, getStonePainter().getStoneHeight() + 2 * INSET); * INSET, getStonePainter().getStoneHeight() + 2 * INSET);
setVisible(true); setVisible(true);
repaint(); repaint();
} }
} }
@Override @Override
public void paintComponent(Graphics g1) { public void paintComponent(Graphics g1) {
Insets insets = getInsets(); Insets insets = getInsets();
int x = insets.left, y = insets.top, width = getWidth() - insets.left int x = insets.left, y = insets.top, width = getWidth() - insets.left
- insets.right, height = getHeight() - insets.top - insets.bottom; - insets.right, height = getHeight() - insets.top - insets.bottom;
Graphics2D g = (Graphics2D) g1.create(x, y, width, height); Graphics2D g = (Graphics2D) g1.create(x, y, width, height);
if (!selectedStones.isEmpty()) { if (!selectedStones.isEmpty()) {
g1.setColor(new Color(0, 0, 0, 0.25f)); g1.setColor(new Color(0, 0, 0, 0.25f));
g1.fillRoundRect(0, 0, getWidth(), getHeight(), INSET, INSET); g1.fillRoundRect(0, 0, getWidth(), getHeight(), INSET, INSET);
float xpos = 0; float xpos = 0;
for (Stone stone : selectedStones) { for (Stone stone : selectedStones) {
getStonePainter().paintStone(g, stone, new Position(xpos, 0), false); getStonePainter().paintStone(g, stone, new Position(xpos, 0), false);
xpos++; xpos++;
} }
} }
} }
} }

View file

@ -8,6 +8,7 @@ import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter; import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent; import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener; import java.awt.event.ComponentListener;
import java.awt.geom.Rectangle2D;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -19,6 +20,7 @@ import javax.swing.JLabel;
import jrummikub.model.Position; import jrummikub.model.Position;
import jrummikub.model.Stone; import jrummikub.model.Stone;
import jrummikub.model.StoneSet; import jrummikub.model.StoneSet;
import jrummikub.util.Event1;
import jrummikub.view.IStoneCollectionPanel; import jrummikub.view.IStoneCollectionPanel;
import jrummikub.view.ITablePanel; import jrummikub.view.ITablePanel;
@ -27,159 +29,197 @@ import jrummikub.view.ITablePanel;
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
class TablePanel extends AbstractStonePanel implements ITablePanel { class TablePanel extends AbstractStonePanel implements ITablePanel {
private final static ImageIcon background = new ImageIcon( private final static ImageIcon background = new ImageIcon(
HandPanel.class.getResource("/jrummikub/resource/felt.png")); HandPanel.class.getResource("/jrummikub/resource/felt.png"));
private final static float DEFAULT_SCALE = 1; private final static float DEFAULT_SCALE = 1;
private final int COLLECTION_GAP = 5; private final static float CONNECTOR_WIDTH = 0.25f;
private final int COLLECTION_GAP = 5;
private JLabel leftPlayerLabel, topPlayerLabel, rightPlayerLabel; private JLabel leftPlayerLabel, topPlayerLabel, rightPlayerLabel;
private StoneCollectionPanel stoneCollection; private StoneCollectionPanel stoneCollection;
private Map<StoneSet, Position> stoneSets = Collections.emptyMap(); private Map<StoneSet, Position> stoneSets = Collections.emptyMap();
private Collection<Stone> selectedStones = Collections.emptyList(); private Collection<Stone> selectedStones = Collections.emptyList();
@Override private Event1<StoneSet> leftConnectorClickEvent = new Event1<StoneSet>();
public void setLeftPlayerName(String playerName) { private Event1<StoneSet> rightConnectorClickEvent = new Event1<StoneSet>();
leftPlayerLabel.setText(playerName);
}
@Override @Override
public void setTopPlayerName(String playerName) { public void setLeftPlayerName(String playerName) {
topPlayerLabel.setText(playerName); leftPlayerLabel.setText(playerName);
} }
@Override @Override
public void setRightPlayerName(String playerName) { public void setTopPlayerName(String playerName) {
rightPlayerLabel.setText(playerName); topPlayerLabel.setText(playerName);
} }
@Override @Override
public void setStoneSets(Map<StoneSet, Position> stoneSets) { public void setRightPlayerName(String playerName) {
Map<Stone, Position> stones = new HashMap<Stone, Position>(); rightPlayerLabel.setText(playerName);
}
for (Map.Entry<StoneSet, Position> entry : stoneSets.entrySet()) { @Override
float x = entry.getValue().getX(), y = entry.getValue().getY(); public Event1<StoneSet> getLeftConnectorClickEvent() {
return leftConnectorClickEvent;
}
for (Stone stone : entry.getKey()) { @Override
stones.put(stone, new Position(x, y)); public Event1<StoneSet> getRightConnectorClickEvent() {
x += stone.getWidth(); return rightConnectorClickEvent;
} }
}
setStones(stones); @Override
this.stoneSets = stoneSets; public void setStoneSets(Map<StoneSet, Position> stoneSets) {
Map<Stone, Position> stones = new HashMap<Stone, Position>();
repaint(); for (Map.Entry<StoneSet, Position> entry : stoneSets.entrySet()) {
} float x = entry.getValue().getX(), y = entry.getValue().getY();
@Override for (Stone stone : entry.getKey()) {
public IStoneCollectionPanel getStoneCollectionPanel() { stones.put(stone, new Position(x, y));
return stoneCollection; x++;
} }
}
/** setStones(stones);
* Sets the currently selected stones this.stoneSets = stoneSets;
*
* @param stones
* the selected stones
*/
void setSelectedStones(Collection<Stone> stones) {
selectedStones = stones;
stoneCollection.setSelectedStones(stones);
repaint();
}
private void rescale() { repaint();
Insets insets = getInsets(); }
int x = insets.left, y = insets.top, width = getWidth() - insets.left
- insets.right, height = getHeight() - insets.top - insets.bottom;
leftPlayerLabel.setBounds(x, y, width, height); @Override
topPlayerLabel.setBounds(x, y, width, height); public IStoneCollectionPanel getStoneCollectionPanel() {
rightPlayerLabel.setBounds(x, y, width, height); return stoneCollection;
}
stoneCollection.setLocation(x + width / 2 - stoneCollection.getWidth() / 2, /**
y + height - stoneCollection.getHeight() - COLLECTION_GAP); * Sets the currently selected stones
} *
* @param stones
* the selected stones
*/
void setSelectedStones(Collection<Stone> stones) {
selectedStones = stones;
stoneCollection.setSelectedStones(stones);
repaint();
}
/** private void rescale() {
* Creates a new Table instance Insets insets = getInsets();
*/ int x = insets.left, y = insets.top, width = getWidth() - insets.left
TablePanel() { - insets.right, height = getHeight() - insets.top - insets.bottom;
super(DEFAULT_SCALE);
setLayout(null); leftPlayerLabel.setBounds(x, y, width, height);
topPlayerLabel.setBounds(x, y, width, height);
rightPlayerLabel.setBounds(x, y, width, height);
leftPlayerLabel = new JLabel(); stoneCollection.setLocation(x + width / 2 - stoneCollection.getWidth() / 2,
leftPlayerLabel.setForeground(Color.WHITE); y + height - stoneCollection.getHeight() - COLLECTION_GAP);
leftPlayerLabel.setHorizontalAlignment(JLabel.LEFT); }
leftPlayerLabel.setHorizontalTextPosition(JLabel.LEFT);
add(leftPlayerLabel);
topPlayerLabel = new JLabel(); /**
topPlayerLabel.setHorizontalAlignment(JLabel.CENTER); * Creates a new Table instance
topPlayerLabel.setHorizontalTextPosition(JLabel.CENTER); */
topPlayerLabel.setVerticalAlignment(JLabel.TOP); TablePanel() {
topPlayerLabel.setVerticalTextPosition(JLabel.TOP); super(DEFAULT_SCALE);
topPlayerLabel.setForeground(Color.WHITE);
add(topPlayerLabel);
rightPlayerLabel = new JLabel(); setLayout(null);
rightPlayerLabel.setForeground(Color.WHITE);
rightPlayerLabel.setHorizontalAlignment(JLabel.RIGHT);
rightPlayerLabel.setHorizontalTextPosition(JLabel.RIGHT);
add(rightPlayerLabel);
stoneCollection = new StoneCollectionPanel(); leftPlayerLabel = new JLabel();
add(stoneCollection); leftPlayerLabel.setForeground(Color.WHITE);
leftPlayerLabel.setHorizontalAlignment(JLabel.LEFT);
leftPlayerLabel.setHorizontalTextPosition(JLabel.LEFT);
add(leftPlayerLabel);
ComponentListener rescaleListener = new ComponentAdapter() { topPlayerLabel = new JLabel();
@Override topPlayerLabel.setHorizontalAlignment(JLabel.CENTER);
public void componentResized(ComponentEvent e) { topPlayerLabel.setHorizontalTextPosition(JLabel.CENTER);
rescale(); topPlayerLabel.setVerticalAlignment(JLabel.TOP);
} topPlayerLabel.setVerticalTextPosition(JLabel.TOP);
}; topPlayerLabel.setForeground(Color.WHITE);
add(topPlayerLabel);
addComponentListener(rescaleListener); rightPlayerLabel = new JLabel();
stoneCollection.addComponentListener(rescaleListener); rightPlayerLabel.setForeground(Color.WHITE);
} rightPlayerLabel.setHorizontalAlignment(JLabel.RIGHT);
rightPlayerLabel.setHorizontalTextPosition(JLabel.RIGHT);
add(rightPlayerLabel);
private void paintStoneSet(Graphics2D g, StoneSet stoneSet, Position pos) { stoneCollection = new StoneCollectionPanel();
float x = pos.getX(); add(stoneCollection);
int width = getStonePainter().getStoneWidth(), height = getStonePainter()
.getStoneHeight();
g.setColor(new Color(0, 0, 0, 0.25f)); ComponentListener rescaleListener = new ComponentAdapter() {
g.fillRect((int) (x * width) - width / 4, (int) (pos.getY() * height), @Override
width / 4, height); public void componentResized(ComponentEvent e) {
rescale();
}
};
for (Stone stone : stoneSet) { addComponentListener(rescaleListener);
getStonePainter().paintStone(g, stone, new Position(x, pos.getY()), stoneCollection.addComponentListener(rescaleListener);
selectedStones.contains(stone)); }
x++;
}
g.setColor(new Color(0, 0, 0, 0.25f)); protected boolean handleOtherClickEvent(Position pos) {
g.fillRect((int) (x * width), (int) (pos.getY() * height), width / 4, for (Map.Entry<StoneSet, Position> entry : stoneSets.entrySet()) {
height); Position p = entry.getValue();
} StoneSet stoneSet = entry.getKey();
float x = p.getX(), y = p.getY();
@Override // left connector
protected void paintComponent(Graphics g1) { Rectangle2D rect = new Rectangle2D.Float(x - CONNECTOR_WIDTH, y,
Graphics2D g = (Graphics2D) g1; CONNECTOR_WIDTH, 1);
if (rect.contains(pos.getX(), pos.getY())) {
leftConnectorClickEvent.emit(stoneSet);
return true;
}
for (int x = 0; x < getWidth(); x += background.getIconWidth()) { // right connector
for (int y = 0; y < getHeight(); y += background.getIconHeight()) { rect = new Rectangle2D.Float(x + stoneSet.size(), y, CONNECTOR_WIDTH, 1);
background.paintIcon(this, g, x, y); if (rect.contains(pos.getX(), pos.getY())) {
} rightConnectorClickEvent.emit(stoneSet);
} return true;
}
}
return false;
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, private void paintStoneSet(Graphics2D g, StoneSet stoneSet, Position pos) {
RenderingHints.VALUE_ANTIALIAS_ON); float x = pos.getX();
int width = getStonePainter().getStoneWidth(), height = getStonePainter()
.getStoneHeight();
for (Map.Entry<StoneSet, Position> stoneSet : stoneSets.entrySet()) { g.setColor(new Color(0, 0, 0, 0.25f));
paintStoneSet(g, stoneSet.getKey(), stoneSet.getValue()); g.fillRect((int) (x * width - width * CONNECTOR_WIDTH),
} (int) (pos.getY() * height), (int) (width * CONNECTOR_WIDTH), height);
}
for (Stone stone : stoneSet) {
getStonePainter().paintStone(g, stone, new Position(x, pos.getY()),
selectedStones.contains(stone));
x++;
}
g.setColor(new Color(0, 0, 0, 0.25f));
g.fillRect((int) (x * width), (int) (pos.getY() * height),
(int) (width * CONNECTOR_WIDTH), height);
}
@Override
protected void paintComponent(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
for (int x = 0; x < getWidth(); x += background.getIconWidth()) {
for (int y = 0; y < getHeight(); y += background.getIconHeight()) {
background.paintIcon(this, g, x, y);
}
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Map.Entry<StoneSet, Position> entry : stoneSets.entrySet()) {
paintStoneSet(g, entry.getKey(), entry.getValue());
}
}
} }