package net.sf.colossus.gui; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.SwingUtilities; import net.sf.colossus.game.Creature; import net.sf.colossus.game.Legion; import net.sf.colossus.game.SummonInfo; import net.sf.colossus.guiutil.KDialog; import net.sf.colossus.guiutil.SaveWindow; import net.sf.colossus.variant.CreatureType; /** * Allows a player to summon an angel or archangel (or any other summonable, * whatever it is in certain variants). * * When selection is done, now the dialog makes the client send the SummonInfo * result to server (empty one if window simply closed). * * @author David Ripton * @author Romain Dolbeau * @author Clemens Katzer */ final public class SummonAngel { private static final Logger LOGGER = Logger.getLogger(SummonAngel.class .getName()); private final ClientGUI gui; private final Legion legion; private final List<Legion> possibleDonors; public SummonAngel(ClientGUI gui, Legion legion, List<Legion> possibleDonors) { this.gui = gui; this.legion = legion; this.possibleDonors = possibleDonors; if (possibleDonors.size() < 1) { LOGGER .severe("SummonAngel constructor still gets empty donor list???"); sendSummonInfoToServer(new SummonInfo()); return; } if (SwingUtilities.isEventDispatchThread()) { createDialog(); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { createDialog(); } }); } } private void createDialog() { new SummonAngelDialog(this, gui, legion, possibleDonors); } public void sendSummonInfoToServer(SummonInfo summonInfo) { gui.getClient().doSummon(summonInfo); } final class SummonAngelDialog extends KDialog { private static final String BASE_SUMMON_STRING = ": Summon Angel into Legion "; private final SummonAngel saInstance; private final Legion target; private final List<Chit> sumChitList = new ArrayList<Chit>(); private final JButton cancelButton; private final SaveWindow saveWindow; private final Map<Chit, Legion> chitToDonor = new HashMap<Chit, Legion>(); public SummonAngelDialog(SummonAngel saInst, ClientGUI gui, Legion legion, List<Legion> possibleDonors) { super(gui.getBoard().getFrame(), gui.getOwningPlayer().getName() + BASE_SUMMON_STRING + legion, false); this.saInstance = saInst; this.target = legion; addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { cleanup(null, null); } }); Container contentPane = getContentPane(); contentPane .setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); pack(); setBackground(Color.lightGray); int scale = 4 * Scale.get(); contentPane.add(Box.createRigidArea(new Dimension(0, scale / 4))); Box txtBox = new Box(BoxLayout.X_AXIS); txtBox.add(Box.createRigidArea(new Dimension(8, scale / 8))); txtBox.add(new JLabel("The following legions contain summonable " + "creatures (they have a red border): ")); txtBox.add(Box.createHorizontalGlue()); contentPane.add(txtBox); contentPane.add(Box.createRigidArea(new Dimension(0, scale / 4))); sumChitList.clear(); SortedSet<Legion> sortedDonors = new TreeSet<Legion>( Legion.ORDER_TITAN_THEN_POINTS_THEN_MARKER); sortedDonors.addAll(possibleDonors); for (Legion donor : sortedDonors) { Box box = new Box(BoxLayout.X_AXIS); Marker marker = new Marker(legion, scale, donor.getLongMarkerId()); box.add(Box.createRigidArea(new Dimension(scale / 8, 0))); box.add(marker); box.add(Box.createRigidArea(new Dimension(scale / 4, 0))); for (Creature creature : donor.getCreatures()) { final CreatureType type = creature.getType(); String name = type.getName(); if (type.isTitan()) { name = legion.getPlayer().getTitanBasename(); } else if (name.equals("Angel")) { name = legion.getPlayer().getAngelBasename(); } final Chit chit = Chit.newCreatureChit(scale, name); box.add(chit); if (type.isSummonable()) { chit.setBorder(true); chit.setBorderColor(Color.red); chit.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (!chit.isDead()) { Legion donor = chitToDonor.get(chit); cleanup(donor, type); } } }); sumChitList.add(chit); chitToDonor.put(chit, donor); } } box.add(Box.createHorizontalGlue()); contentPane.add(box); contentPane.add(Box .createRigidArea(new Dimension(0, scale / 8))); } txtBox = new Box(BoxLayout.X_AXIS); txtBox.add(Box.createRigidArea(new Dimension(scale / 8, 0))); txtBox.add(Box.createHorizontalGlue()); txtBox.add(new JLabel("Click a summonable to summon it to your " + "legion, or Cancel to not summon anything.")); txtBox.add(Box.createHorizontalGlue()); contentPane.add(txtBox); contentPane.add(Box.createRigidArea(new Dimension(0, scale / 4))); cancelButton = new JButton("Cancel"); cancelButton.setMnemonic(KeyEvent.VK_C); cancelButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { cleanup(null, null); } }); Box btnBox = new Box(BoxLayout.X_AXIS); btnBox.add(Box.createHorizontalGlue()); btnBox.add(cancelButton); btnBox.add(Box.createHorizontalGlue()); contentPane.add(btnBox); contentPane.add(Box.createRigidArea(new Dimension(0, scale / 4))); pack(); saveWindow = new SaveWindow(gui.getOptions(), "SummonAngel"); Point location = saveWindow.loadLocation(); if (location == null) { centerOnScreen(); } else { setLocation(location); } setVisible(true); repaint(); } // TODO Now that the SummonInfo object should never be null, // we could make returning null being the signal for canceling // a summoning, and then this could be part of the move phase, // instead of the "do it now or never" style as it is now. private void cleanup(Legion donor, CreatureType angel) { LOGGER.log(Level.FINEST, "SummonAngel.cleanup " + donor + " " + angel); SummonInfo summonInfo; if (donor != null && angel != null) { summonInfo = new SummonInfo(target, donor, angel); } else { // Default constructor creates an info with the flag // "noSummoningWanted" set to true summonInfo = new SummonInfo(); } saInstance.sendSummonInfoToServer(summonInfo); dispose(); } } }