001 /*
002 Copyright (C) 2003 Adam Olsen
003
004 This program is free software; you can redistribute it and/or modify
005 it under the terms of the GNU General Public License as published by
006 the Free Software Foundation; either version 1, or (at your option)
007 any later version.
008
009 This program is distributed in the hope that it will be useful,
010 but WITHOUT ANY WARRANTY; without even the implied warranty of
011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 GNU General Public License for more details.
013
014 You should have received a copy of the GNU General Public License
015 along with this program; if not, write to the Free Software
016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
017 */
018
019 package com.valhalla.jbother;
020
021 import java.awt.Container;
022 import java.awt.GridBagConstraints;
023 import java.awt.GridBagLayout;
024 import java.awt.event.ActionEvent;
025 import java.awt.event.ActionListener;
026 import java.util.ArrayList;
027 import java.util.Hashtable;
028 import java.util.Iterator;
029 import java.util.Locale;
030 import java.util.Map;
031 import java.util.ResourceBundle;
032
033 import javax.swing.*;
034
035 import org.jivesoftware.smack.PacketCollector;
036 import org.jivesoftware.smack.SmackConfiguration;
037 import org.jivesoftware.smack.filter.AndFilter;
038 import org.jivesoftware.smack.filter.PacketFilter;
039 import org.jivesoftware.smack.filter.PacketIDFilter;
040 import org.jivesoftware.smack.filter.PacketTypeFilter;
041 import org.jivesoftware.smack.packet.IQ;
042 import org.jivesoftware.smack.packet.Registration;
043
044 import com.valhalla.gui.DialogTracker;
045 import com.valhalla.gui.MJTextField;
046 import com.valhalla.gui.NMOptionDialog;
047 import com.valhalla.gui.Standard;
048 import com.valhalla.gui.WaitDialog;
049 import com.valhalla.gui.WaitDialogListener;
050
051 /**
052 * Displays a dynamic registration form A registration server is contacted and
053 * responds with the required fields that it needs in order for someone to
054 * register for it. This form will then dynamically display the required fields.
055 * Once the fields are filled out, this class will send the information back to
056 * the server.
057 *
058 * @author Adam Olsen
059 * @version 1.0
060 */
061 public class RegistrationForm extends JDialog {
062 protected ResourceBundle resources = ResourceBundle.getBundle(
063 "JBotherBundle", Locale.getDefault());
064
065 protected String server;
066
067 protected ArrayList fieldListFields = new ArrayList();
068
069 protected ArrayList fieldListNames = new ArrayList();
070
071 protected WaitDialog wait;
072
073 protected JLabel instructions = new JLabel(resources
074 .getString("pleaseFillIn"));
075
076 private String regKey = "";
077
078 private JPanel container = new JPanel();
079
080 private JButton okButton = new JButton(resources.getString("okButton")),
081 cancelButton = new JButton(resources.getString("cancelButton"));
082
083 private JPanel buttonPanel = new JPanel();
084
085 private JPanel inputPanel = new JPanel();
086
087 private Registration register = new Registration();
088
089 //this part is for laying out the rows for the dialog
090 private int row = 1;
091
092 private GridBagLayout grid = new GridBagLayout();
093
094 private GridBagConstraints c = new GridBagConstraints();
095
096 /**
097 * Default constructor
098 *
099 * @param server
100 * the server to register for
101 */
102 public RegistrationForm(JFrame parent,String server) {
103 super(parent,"Registration", false);
104
105 setTitle(resources.getString("registration"));
106 this.server = server;
107
108 instructions.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
109
110 container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
111 instructions.setAlignmentX(Container.CENTER_ALIGNMENT);
112 container.add(instructions);
113 container.setBorder(BorderFactory.createEmptyBorder(5, 25, 5, 25));
114
115 inputPanel.setLayout(grid);
116
117 setContentPane(container);
118
119 c.gridx = 0;
120 c.gridy = 0;
121 c.gridwidth = 1;
122
123 container.add(inputPanel);
124 //add the buttons
125 JPanel buttonPanel = new JPanel();
126 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
127 buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
128 buttonPanel.add(okButton);
129 buttonPanel.add(cancelButton);
130 DialogTracker.addDialog(this, true, true);
131
132 container.add(buttonPanel);
133 initializeListeners();
134 }
135
136 /**
137 * Sets up the different event listeners in the RegistrationForm
138 */
139 private void initializeListeners() {
140 cancelButton.addActionListener(new ActionListener() {
141 public void actionPerformed(ActionEvent e) {
142 closeHandler();
143 }
144 });
145
146 okButton.addActionListener(new ActionListener() {
147 public void actionPerformed(ActionEvent e) {
148 register();
149 }
150 });
151 }
152
153 /**
154 * Closes this dialog
155 */
156 public void closeHandler() {
157 DialogTracker.removeDialog(this);
158 }
159
160 /**
161 * Causes the registration thread to begin - sending the information in the
162 * form to the server
163 */
164 public void register() {
165 setVisible(false);
166
167 RegisterThread thread = new RegisterThread();
168
169 wait = new WaitDialog(this, thread, resources.getString("pleaseWait"));
170 wait.setVisible(true);
171
172 thread.start();
173 }
174
175 /**
176 * Contacts the server to find out which fields are needed
177 */
178 public void getRegistrationInfo() {
179
180 GetRegistrationFormThread thread = new GetRegistrationFormThread();
181 wait = new WaitDialog(this, thread, resources.getString("pleaseWait"));
182 wait.setVisible(true);
183
184 thread.start();
185 }
186
187 /**
188 * Capitalizes the first letter of a string
189 *
190 * @param text
191 * the text to capitalize
192 * @return the capitalized text
193 */
194 private String capitalize(String text) {
195 text = text.substring(0, 1).toUpperCase()
196 + text.substring(1, text.length());
197 return text;
198 }
199
200 /**
201 * Creates a <code>Label</code> and a <code>JTextField</code> next to it
202 * and places it in the registration form after the last If the label param
203 * is "password", it creates a <code>JPasswordField</code>
204 *
205 * @param label
206 * the text to put in the label
207 */
208 protected void createInputBox(String label, String value) {
209 JLabel labelBox = new JLabel(capitalize(label) + ": ");
210
211 fieldListNames.add(label);
212
213 c.gridy = row++;
214 c.gridx = 0;
215 c.anchor = GridBagConstraints.EAST;
216 grid.setConstraints(labelBox, c);
217 inputPanel.add(labelBox);
218
219 JTextField box = new MJTextField(15);
220 if (label.equals("password")) {
221 box = new JPasswordField(15);
222 box.setFont(labelBox.getFont());
223 }
224
225 if (value != null)
226 box.setText(value);
227 fieldListFields.add(box);
228
229 c.gridx = 1;
230 c.anchor = GridBagConstraints.WEST;
231 grid.setConstraints(box, c);
232 inputPanel.add(box);
233 }
234
235 /**
236 * Submits the registration information to the server
237 *
238 * @author Adam Olsen
239 * @version 1.0
240 */
241 class RegisterThread extends Thread implements WaitDialogListener {
242 private String errorMessage;
243
244 private boolean stopped = false;
245
246 public void cancel() {
247 stopped = true;
248 interrupt();
249 }
250
251 /**
252 * is called from the <code>Thread</code> enclosing this class
253 */
254 public void run() {
255 if (!BuddyList.getInstance().checkConnection()) {
256 BuddyList.getInstance().connectionError();
257 return;
258 }
259
260 register = new Registration();
261 register.setType(IQ.Type.SET);
262 register.setTo(server);
263
264 Hashtable map = new Hashtable();
265 map.put("key", regKey);
266
267 // set up the various attributes to be sent to the server
268 for (int i = 0; i < fieldListNames.size(); i++) {
269 String name = (String) fieldListNames.get(i);
270 JTextField field = (JTextField) fieldListFields.get(i);
271
272 map.put(name, field.getText());
273 }
274
275 // send the packet
276 register.setAttributes(map);
277 PacketFilter filter = new AndFilter(new PacketIDFilter(register
278 .getPacketID()), new PacketTypeFilter(IQ.class));
279
280 PacketCollector collector = BuddyList.getInstance().getConnection()
281 .createPacketCollector(filter);
282 BuddyList.getInstance().getConnection().sendPacket(register);
283
284 // collect the response
285 IQ result = (IQ) collector.nextResult(SmackConfiguration
286 .getPacketReplyTimeout());
287 wait.dispose();
288
289 if (stopped)
290 return;
291
292 if (result == null) {
293 errorMessage = resources.getString("unknownError");
294 } else if (result.getType() == IQ.Type.ERROR) {
295 errorMessage = result.getError().getMessage();
296 if (errorMessage == null)
297 errorMessage = resources.getString("unknownError");
298 }
299
300 // display the error message if there was one
301 // otherwise just close
302 SwingUtilities.invokeLater(new Runnable() {
303 public void run() {
304 if (errorMessage != null) {
305 Standard.warningMessage(null, resources
306 .getString("registration"), errorMessage);
307 } else {
308 NMOptionDialog.createMessageDialog(null, resources
309 .getString("registration"), resources
310 .getString("registrationSuccessful"));
311 }
312
313 DialogTracker.removeDialog(RegistrationForm.this);
314 }
315 });
316 }
317 }
318
319 /**
320 * Contacts the registration server and finds out what fields need to be
321 * sent back in order to register for the server
322 *
323 * @author Adam Olsen
324 * @version 1.0
325 */
326 class GetRegistrationFormThread extends Thread implements
327 WaitDialogListener {
328 private String errorMessage;
329
330 private boolean stopped = false;
331
332 public void cancel() {
333 stopped = true;
334 interrupt();
335 }
336
337 /**
338 * Called from the <code>Thread</code> enclosing this class
339 */
340 public void run() {
341 if (!BuddyList.getInstance().checkConnection()) {
342 BuddyList.getInstance().connectionError();
343 return;
344 }
345
346 register = new Registration();
347 register.setType(IQ.Type.GET);
348 register.setTo(server);
349 PacketFilter filter = new AndFilter(new PacketIDFilter(register
350 .getPacketID()), new PacketTypeFilter(IQ.class));
351
352 PacketCollector collector = BuddyList.getInstance().getConnection()
353 .createPacketCollector(filter);
354
355 // send the request
356 BuddyList.getInstance().getConnection().sendPacket(register);
357
358 // collect the response
359 IQ result = (IQ) collector.nextResult(SmackConfiguration
360 .getPacketReplyTimeout());
361
362 if (stopped)
363 return;
364
365 if (result == null) {
366 errorMessage = resources.getString("noResponse");
367 } else if (result.getType() == IQ.Type.ERROR) {
368 errorMessage = result.getError().getMessage();
369 if (errorMessage == null)
370 errorMessage = resources.getString("unknownError");
371 }
372
373 wait.setVisible(false);
374
375 // if there was no error, create the registration form and display
376 // it
377 if (errorMessage == null) {
378 register = (Registration) result;
379
380 instructions
381 .setText("<html><table width='300' border='0'><tr><td align='center'> "
382 + register.getInstructions()
383 + "</td></tr></table></html>");
384
385 Map map = register.getAttributes();
386 if (map != null) {
387 Iterator iterator = map.keySet().iterator();
388
389 // we iterate twice to ensure the username goes first
390 while (iterator.hasNext()) {
391 String key = (String) iterator.next();
392
393 // build the registration form
394 String value = (String) map.get(key);
395 if (key.equals("username"))
396 createInputBox(key, value);
397 }
398
399 iterator = map.keySet().iterator();
400
401 while (iterator.hasNext()) {
402 String key = (String) iterator.next();
403
404 // build the registration form
405 String value = (String) map.get(key);
406 if (key.equals("key"))
407 regKey = value; // this field does not need to be
408 // displayed
409 else if (!key.equals("instructions")
410 && !key.equals("username")
411 && !key.equals("registered"))
412 createInputBox(key, value);
413 }
414 }
415
416 }
417
418
419 // either display an error if there was one or
420 // display the registration dialog if there wasn't one
421 SwingUtilities.invokeLater(new Runnable() {
422 public void run() {
423 if (errorMessage != null) {
424 Standard.warningMessage(null, resources
425 .getString("registration"), errorMessage);
426 DialogTracker.removeDialog(RegistrationForm.this);
427 } else {
428 pack();
429
430 setLocationRelativeTo(null);
431 setVisible(true);
432 }
433 }
434 });
435 }
436 }
437 }