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    }