View Javadoc

1   /*
2   @See License.txt@
3    */
4   
5   package spellcast.ui;
6   
7   import java.awt.BorderLayout;
8   import java.awt.Dimension;
9   import java.awt.GridBagConstraints;
10  import java.awt.GridBagLayout;
11  import java.awt.Insets;
12  import java.awt.event.ActionEvent;
13  import java.awt.event.ActionListener;
14  import java.beans.PropertyChangeListener;
15  import java.net.InetAddress;
16  import java.util.Iterator;
17  import javax.swing.BorderFactory;
18  import javax.swing.JButton;
19  import javax.swing.JComboBox;
20  import javax.swing.JDialog;
21  import javax.swing.JFrame;
22  import javax.swing.JLabel;
23  import javax.swing.JPanel;
24  import javax.swing.JScrollPane;
25  import javax.swing.JTable;
26  import javax.swing.JTextField;
27  import javax.swing.ListSelectionModel;
28  import javax.swing.ScrollPaneConstants;
29  import javax.swing.SwingUtilities;
30  import javax.swing.event.DocumentEvent;
31  import javax.swing.event.DocumentListener;
32  import javax.swing.event.ListSelectionEvent;
33  import javax.swing.event.ListSelectionListener;
34  import javax.swing.event.SwingPropertyChangeSupport;
35  import javax.swing.table.DefaultTableCellRenderer;
36  import org.apache.log4j.Logger;
37  import spellcast.model.PropertyUpdater;
38  import spellcast.net.ServerStatus;
39  
40  /***
41   * The Connection Dialog allows the user to select a spellcast server to connect to.
42   * <p>
43   * A JText field is displayed with the label "Server Address" into which a manual address
44   * can be entered.  Pressing enter in the manual address will attempt to connect to the
45   * address specified.
46   * <p>
47   * A JList displays all "Available Local Servers" and displays the name of the game,
48   * the number of players and the ip address of the server in the list.  Clicking on a server 
49   * in the list will fill in the manual ip address field with the ip address of the selected server.
50   * Double clicking on the item will connect to the address of the selected item.
51   * <p>
52   * In the South area are three buttons for "Connect", "Create" and "Cancel".
53   * <p>
54   * This class will fire CONNECT_PROP and SHOW_NEW_GAME_DIALOG_PROP property change events.
55   *
56   * @author Barrie Treloar
57   */
58  public class ConnectionDialog
59      extends JDialog
60      implements PropertyUpdater, UIProperties {
61      private JButton join;
62      private JButton create;
63      private JButton cancel;
64      private JComboBox profileList;
65      private JTextField serverAddress;
66      private ServerListTableModel serverList;
67      private JTable availableServers;
68      private AvailableServerListUpdater updater;
69  
70      private SwingPropertyChangeSupport propertySupport;
71  
72      private static final Logger logger = Logger.getLogger("client.connect");
73  
74      public ConnectionDialog() {
75          super((JFrame) null, "Connect to Spellcast Server", false);
76  
77          propertySupport = new SwingPropertyChangeSupport(this);
78  
79          createSouthPanel();
80          createCenterPanel();
81          createEventListeners();
82          pack();
83  
84          updater = new AvailableServerListUpdater(serverList);
85      }
86  
87      public void addPropertyChangeListener(PropertyChangeListener listener) {
88          propertySupport.addPropertyChangeListener(listener);
89      }
90  
91      public void removePropertyChangeListener(PropertyChangeListener listener) {
92          propertySupport.removePropertyChangeListener(listener);
93      }
94  
95      /***
96       * Start the server list updater
97       */
98      private void start() {
99          updater.start();
100     }
101 
102     /***
103      * Stop the server list updater.
104      */
105     private void stop() {
106         updater.stop();
107     }
108 
109     public void setVisible(boolean isVisible) {
110         super.setVisible(isVisible);
111         if (isVisible) {
112             SwingUtilities.invokeLater(new Runnable() {
113                 public void run() {
114                     java.util.List profiles = WizardProfiles.loadProfiles();
115                     WizardProfile defaultProfile = WizardProfiles.loadDefaultProfile();
116                     profileList.removeAllItems();
117                     Iterator profileIterator = profiles.listIterator();
118                     while (profileIterator.hasNext()) {
119                         profileList.addItem(profileIterator.next());
120                     }
121                     profileList.setSelectedItem(defaultProfile);
122 
123                     availableServers.getSelectionModel().clearSelection();
124                     serverList.clear();
125 
126                     serverAddress.setText("");
127                     join.setEnabled(false);
128                 }
129             });
130             start();
131         }
132         else {
133             stop();
134         }
135     }
136 
137     private void createSouthPanel() {
138         JPanel p = new JPanel();
139         GridBagLayout gridbag = new GridBagLayout();
140         p.setLayout(gridbag);
141         GridBagConstraints c = new GridBagConstraints();
142         // Common constraints
143         c.insets = new Insets(4, 4, 4, 4);
144         c.fill = GridBagConstraints.HORIZONTAL;
145 
146         c.weightx = 1.0;
147         JLabel empty = new JLabel(" ");
148         gridbag.setConstraints(empty, c);
149         p.add(empty);
150 
151         c.weightx = 0.0;
152         join = new JButton("Join");
153         join.setEnabled(false);
154         join.setDefaultCapable(true);
155         join.addActionListener(new ActionListener() {
156             public void actionPerformed(ActionEvent e) {
157                 join();
158             }
159         });
160         getRootPane().setDefaultButton(join);
161         gridbag.setConstraints(join, c);
162         p.add(join);
163 
164         create = new JButton("Create");
165         create.addActionListener(new ActionListener() {
166             public void actionPerformed(ActionEvent e) {
167                 propertySupport.firePropertyChange(SHOW_NEW_GAME_DIALOG_PROP, null, null);
168                 setVisible(false);
169             }
170         });
171         gridbag.setConstraints(create, c);
172         p.add(create);
173 
174         cancel = new JButton("Cancel");
175         cancel.addActionListener(new ActionListener() {
176             public void actionPerformed(ActionEvent e) {
177                 setVisible(false);
178             }
179         });
180         gridbag.setConstraints(cancel, c);
181         p.add(cancel);
182 
183         getContentPane().add(p, BorderLayout.SOUTH);
184     }
185 
186     private void createCenterPanel() {
187         JPanel p = new JPanel();
188         p.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
189 
190         GridBagLayout gridbag = new GridBagLayout();
191         p.setLayout(gridbag);
192         GridBagConstraints c = new GridBagConstraints();
193         // Common constraints
194         c.insets = new Insets(4, 4, 4, 4);
195 
196         c.anchor = GridBagConstraints.WEST;
197         JLabel profileLabel = new JLabel("Wizard Profile");
198         gridbag.setConstraints(profileLabel, c);
199         p.add(profileLabel);
200 
201         c.gridwidth = GridBagConstraints.REMAINDER;
202         profileList = new JComboBox();
203         profileList.setEditable(false);
204         gridbag.setConstraints(profileList, c);
205         p.add(profileList);
206 
207         c.gridwidth = 1;
208         JLabel serverAddressLabel = new JLabel("Server Address");
209         gridbag.setConstraints(serverAddressLabel, c);
210         p.add(serverAddressLabel);
211 
212         c.gridwidth = GridBagConstraints.REMAINDER;
213         serverAddress = new JTextField(12);
214         serverAddress.addActionListener(new ActionListener() {
215             public void actionPerformed(ActionEvent e) {
216                 join();
217             }
218         });
219         gridbag.setConstraints(serverAddress, c);
220         p.add(serverAddress);
221         serverAddressLabel.setLabelFor(serverAddress);
222 
223         JLabel availableServersLabel = new JLabel("Available Local Servers");
224         gridbag.setConstraints(availableServersLabel, c);
225         p.add(availableServersLabel);
226 
227         serverList = new ServerListTableModel();
228         availableServers = new JTable(serverList);
229         availableServers.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
230         availableServers.setCellSelectionEnabled(false);
231         availableServers.setColumnSelectionAllowed(false);
232         availableServers.setRowSelectionAllowed(true);
233         availableServers.getTableHeader().setReorderingAllowed(false);
234         availableServers.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
235         availableServers
236             .getSelectionModel()
237             .addListSelectionListener(new ListSelectionListener() {
238             public void valueChanged(ListSelectionEvent e) {
239                 int selectedRow = availableServers.getSelectedRow();
240                 if (selectedRow >= 0) {
241                     ServerStatus s = serverList.get(selectedRow);
242                     serverAddress.setText(
243                         s.getServerIPAddress().getHostAddress() + ":" + s.getPort());
244                 }
245             }
246         });
247         availableServers.setShowGrid(true);
248         availableServers.setPreferredScrollableViewportSize(new Dimension(350, 75));
249         availableServers
250             .setDefaultRenderer(InetAddress.class, new DefaultTableCellRenderer() {
251             public void setValue(Object value) {
252                 setText(((InetAddress) value).getHostAddress());
253             }
254         });
255         availableServers.setDefaultRenderer(
256             Number.class,
257             new DefaultTableCellRenderer());
258 
259         c.anchor = GridBagConstraints.CENTER;
260         c.fill = GridBagConstraints.BOTH;
261         c.weightx = 1.0;
262         c.weighty = 1.0;
263         JScrollPane availableServersScrollPane =
264             new JScrollPane(
265                 availableServers,
266                 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
267                 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
268         availableServersScrollPane.setColumnHeaderView(
269             availableServers.getTableHeader());
270         gridbag.setConstraints(availableServersScrollPane, c);
271         p.add(availableServersScrollPane);
272 
273         getContentPane().add(p, BorderLayout.CENTER);
274     }
275 
276     private void createEventListeners() {
277         serverAddress.getDocument().addDocumentListener(new DocumentListener() {
278             public void insertUpdate(DocumentEvent e) {
279                 join.setEnabled(true);
280             }
281 
282             public void removeUpdate(DocumentEvent e) {
283                 if (serverAddress.getText().trim().equals("")) {
284                     join.setEnabled(false);
285                 }
286                 else {
287                     join.setEnabled(true);
288                 }
289             }
290 
291             public void changedUpdate(DocumentEvent e) {
292                 if (serverAddress.getText().trim().equals("")) {
293                     join.setEnabled(false);
294                 }
295                 else {
296                     join.setEnabled(true);
297                 }
298             }
299         });
300     }
301 
302     private void join() {
303         WizardProfile wp = (WizardProfile) profileList.getSelectedItem();
304         if (wp != null) {
305             setVisible(false);
306             ConnectToServerEvent evt =
307                 new ConnectToServerEvent(
308                     serverAddress.getText().trim(),
309                     wp.wizardName,
310                     wp.gender);
311             propertySupport.firePropertyChange(CONNECT_PROP, null, evt);
312         }
313     }
314 }