KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > Chat


1 /* Chat
2  * Copyright (C) 1998-2004 Alexis de Bernis <alexis@bernis.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  */

19
20 import java.awt.*;
21 import java.awt.event.*;
22 import java.io.*;
23 import java.net.*;
24 import java.util.*;
25 import java.applet.*;
26 import org.chateverywhere.*;
27
28 public class Chat extends Applet implements ActionListener, FocusListener, ItemListener, KeyListener
29 {
30     private static String JavaDoc version = "Swing Applet / 1.0.0";
31     private TextArea main_text;
32     private TextField user_text, user_nick;
33     private Button cleartext, go_login;
34     private Label error_message, usernum_lbl, user_prompt;
35     private java.awt.List JavaDoc user_list;
36     private Socket com_sock;
37     private InetAddress server;
38     private String JavaDoc nick;
39     private Hashtable users;
40     private ChatComThread com_thread;
41     private Font fnt, ui_fnt;
42     private Choice usr_fontsize, usr_fontname;
43     private Label l_font;
44     private PopupMenu usr_popup;
45     private Hashtable pmsg_windows;
46     private boolean login_completed = false;
47     private Locale user_locale;
48     private InputStack input_stack;
49     private ResourceBundle captions;
50     private AudioClip bip_sound;
51
52     private Button option_menu_trigger;
53     private PopupMenu option_menu;
54     private CheckboxMenuItem do_notify_connection, do_auto_scrolling;
55     private CheckboxMenuItem do_bip_on_new_line, do_bip_as_sound_file;
56
57     private boolean tab_pressed = false;
58
59
60
61     /*****************************************************
62      * *
63      * Applet initialisation *
64      * *
65      *****************************************************/

66     public void start()
67     {
68         System.out.println("Starting ChatEverywhere, build 200402110945");
69
70         // New instanciations
71
pmsg_windows = new Hashtable();
72         input_stack = new InputStack();
73
74         // Various initialisations
75
check_locale();
76         set_applet_main_colors();
77         set_applet_font();
78         draw_splash_screen();
79         initialize_main_components();
80         draw_login_window();
81
82         // Check if the nick has been given as a parameter
83
if(getParameter("Nick") != null) {
84             user_nick.setText(getParameter("Nick"));
85             make_changements(getParameter("Nick"));
86         }
87     }
88
89     /********************** Locales **********************/
90     private void check_locale()
91     {
92         if(getParameter("Language") != null &&
93            getParameter("Country") != null)
94             user_locale = new Locale(getParameter("Language"), getParameter("Country"));
95         else
96             user_locale = Locale.getDefault();
97     
98 // System.out.println("System locale is " + Locale.getDefault());
99
// System.out.println("User locale is " + user_locale);
100

101         captions = ResourceBundle.getBundle("org.chateverywhere.resources.Messages", user_locale);
102     }
103
104     /******* Applet foreground and background color ******/
105     private void set_applet_main_colors()
106     {
107         // Check for a background color
108
if(getParameter("BgColor") != null) {
109             Color bg_color = Color.decode(getParameter("BgColor"));
110             
111             if(bg_color != null)
112                 setBackground(bg_color);
113         }
114
115         // Check for a foreground color
116
if(getParameter("FgColor") != null) {
117             Color fg_color = Color.decode(getParameter("FgColor"));
118             
119             if(fg_color != null)
120                 setForeground(fg_color);
121         }
122     }
123
124     /******************** Working fonts ******************/
125     private void set_applet_font()
126     {
127         String JavaDoc ui_fnt_name = "Arial";
128         String JavaDoc fnt_name = "Courier";
129         
130         if(getParameter("UIFontName") != null)
131             ui_fnt_name = getParameter("UIFontName");
132         
133         if(getParameter("TextFontName") != null)
134             fnt_name = getParameter("TextFontName");
135
136         ui_fnt = new Font(ui_fnt_name, Font.PLAIN, 12);
137         fnt = new Font(fnt_name, Font.PLAIN, 12);
138     }
139
140
141     /*****************************************************
142      * *
143      * User interface *
144      * *
145      *****************************************************/

146     /************** Components initialisation ************/
147     private void initialize_main_components()
148     {
149         int i;
150         Color a_color;
151
152         main_text = new TextArea("",20,60,TextArea.SCROLLBARS_VERTICAL_ONLY);
153             main_text.setEditable(false);
154             main_text.setFont(fnt);
155             main_text.setLocale(user_locale);
156         user_text = new TextField(80);
157             user_text.setFont(ui_fnt);
158             user_text.setLocale(user_locale);
159             user_text.addKeyListener(this);
160             user_text.addFocusListener(this);
161         usernum_lbl = new Label(captions.getString("MSG_USERS")+": ", Label.CENTER);
162             usernum_lbl.setVisible(false);
163         user_prompt = new Label(captions.getString("MSG_TYPE_HERE"), Label.LEFT);
164         cleartext = new Button(captions.getString("MSG_CLEAR"));
165             cleartext.addActionListener(this);
166         user_list = new java.awt.List JavaDoc(8);
167             user_list.setFont(ui_fnt);
168             user_list.setLocale(user_locale);
169             user_list.setVisible(false);
170             user_list.addItemListener(this);
171         usr_fontsize = new Choice();
172             for(i = 10; i <= 24; i++) {
173                 usr_fontsize.add(Integer.toString(i));
174             }
175             usr_fontsize.setFont(ui_fnt);
176             usr_fontsize.select("12");
177             usr_fontsize.addItemListener(this);
178         usr_fontname = new Choice();
179             usr_fontname.add("Arial");
180             usr_fontname.add("Courier");
181             usr_fontname.setFont(ui_fnt);
182             usr_fontname.select("Courier");
183             usr_fontname.addItemListener(this);
184         l_font = new Label(captions.getString("MSG_FONT")+" : ", Label.RIGHT);
185             l_font.setFont(ui_fnt);
186         usr_popup = new PopupMenu(captions.getString("MSG_ACTION"));
187             usr_popup.setFont(ui_fnt);
188             usr_popup.add("msg");
189             usr_popup.add("stats");
190             usr_popup.add("ignore");
191             usr_popup.add("unignore");
192             usr_popup.add("kick");
193             usr_popup.add("ban");
194             usr_popup.add("unban");
195             usr_popup.addActionListener(this);
196
197             do_auto_scrolling = new CheckboxMenuItem(
198              captions.getString("MSG_AUTO_SCROLLING"), true);
199             do_notify_connection = new CheckboxMenuItem(
200              captions.getString("MSG_NOTIFY_CONNECT"), false);
201             do_bip_on_new_line = new CheckboxMenuItem(
202              captions.getString("MSG_BIP_ON_TEXT"), false);
203             do_bip_as_sound_file = new CheckboxMenuItem(
204              captions.getString("MSG_BIP_AS_SOUND_FILE"),false);
205             option_menu = new PopupMenu();
206                 option_menu.add(do_auto_scrolling);
207                 option_menu.add(do_bip_on_new_line);
208                 option_menu.add(do_bip_as_sound_file);
209                 option_menu.add(do_notify_connection);
210             option_menu_trigger = new Button( // I don't want to set
211
captions.getString("MSG_OPTIONS")); // a MenuBar for that
212
option_menu_trigger.setFont(ui_fnt);
213                 option_menu_trigger.add(option_menu);
214                 option_menu_trigger.addActionListener(this);
215
216         // Check for a users zone background color
217
if(getParameter("UsersBgColor") != null) {
218             a_color = Color.decode(getParameter("UsersBgColor"));
219             if(a_color != null)
220                 user_list.setBackground(a_color);
221         }
222
223         // Check for a users zone foreground color
224
if(getParameter("UsersFgColor") != null) {
225             a_color = Color.decode(getParameter("UsersFgColor"));
226             if(a_color != null)
227                 user_list.setForeground(a_color);
228         }
229
230         // Check for a main text zone background color
231
if(getParameter("TextBgColor") != null) {
232             a_color = Color.decode(getParameter("TextBgColor"));
233             if(a_color != null)
234                 main_text.setBackground(a_color);
235         }
236
237         // Check for a main text zone foreground color
238
if(getParameter("TextFgColor") != null) {
239             a_color = Color.decode(getParameter("TextFgColor"));
240             if(a_color != null)
241                 main_text.setForeground(a_color);
242         }
243
244         // Check for an input zone background color
245
if(getParameter("InputBgColor") != null) {
246             a_color = Color.decode(getParameter("InputBgColor"));
247             if(a_color != null)
248                 user_text.setBackground(a_color);
249         }
250
251         // Check for an input zone foreground color
252
if(getParameter("InputFgColor") != null) {
253             a_color = Color.decode(getParameter("InputFgColor"));
254             if(a_color != null)
255                 user_text.setForeground(a_color);
256         }
257     }
258
259     /*************** draw the splash screen **************/
260     private void draw_splash_screen()
261     {
262         Label welcome, connecting;
263
264         setLayout(new BorderLayout());
265         
266         welcome = new Label(captions.getString("MSG_WELCOME"), Label.CENTER);
267             welcome.setFont(new Font(ui_fnt.getName(), Font.BOLD, ui_fnt.getSize()+2));
268         connecting = new Label(captions.getString("MSG_LOADING"), Label.CENTER);
269             connecting.setFont(new Font(ui_fnt.getName(), Font.ITALIC, ui_fnt.getSize()));
270         
271         add("North", welcome);
272         add("Center", connecting);
273
274         validate();
275         repaint();
276     }
277
278
279     /******************** Login window *******************/
280     private void draw_login_window()
281     {
282         Color a_color;
283         Label splash, info;
284         Panel login_panel, nick_panel, list_panel;
285         Rectangle bounds;
286
287         removeAll();
288         setLayout(new BorderLayout());
289
290         // Initialize the components
291
user_nick = new TextField(14);
292             user_nick.setFont(ui_fnt);
293             user_nick.setLocale(user_locale);
294             user_nick.addActionListener(this);
295         go_login = new Button(" "+captions.getString("MSG_GO")+" ! ");
296             go_login.setFont(ui_fnt);
297             go_login.addActionListener(this);
298         error_message = new Label(" ");
299             error_message.setFont(ui_fnt);
300         splash = new Label(captions.getString("MSG_WELCOME"), Label.CENTER);
301             splash.setFont(new Font(ui_fnt.getName(), Font.BOLD, ui_fnt.getSize()+2));
302         nick_panel = new Panel();
303             nick_panel.add(new Label(captions.getString("MSG_NICK")+" :"));
304             nick_panel.add(user_nick);
305             nick_panel.add(go_login);
306             nick_panel.setVisible(false);
307         list_panel = new Panel();
308             list_panel.add(user_list);
309         login_panel = new Panel(new GridLayout(5, 1));
310             login_panel.add(splash);
311             login_panel.add(new Label(""));
312             login_panel.add(nick_panel);
313             login_panel.add(error_message);
314             login_panel.add(new Label(""));
315
316         // Check for a login zone background color
317
if(getParameter("LoginBgColor") != null) {
318             a_color = Color.decode(getParameter("LoginBgColor"));
319             if(a_color != null)
320                 user_nick.setBackground(a_color);
321         }
322
323         // Check for a login zone foreground color
324
if(getParameter("LoginFgColor") != null) {
325             a_color = Color.decode(getParameter("LoginFgColor"));
326             if(a_color != null)
327                 user_nick.setForeground(a_color);
328         }
329
330         // draw the panel
331
add("North", login_panel);
332         add("Center", list_panel);
333         add("South", usernum_lbl);
334
335         // do the layout
336
validate();
337
338         // Retrieve the server user list
339
if(make_connection(false) == true) {
340             refresh_user_list();
341             error_message.setText(captions.getString("MSG_SERVER_UP"));
342             user_list.setVisible(true);
343             usernum_lbl.setVisible(true);
344             nick_panel.setVisible(true);
345             repaint();
346             user_nick.requestFocus();
347         }
348     }
349
350     /**************** draw the main window ***************/
351     private void change_ui()
352     {
353         Panel cmd_panel, cmd_font_panel, cmd_but_panel;
354
355         removeAll();
356
357         setLayout(new BorderLayout());
358         user_list.add(usr_popup);
359         usernum_lbl.setAlignment(Label.RIGHT);
360
361         cmd_but_panel = new Panel(new FlowLayout(FlowLayout.CENTER, 10, 3));
362             cmd_but_panel.add(option_menu_trigger);
363             cmd_but_panel.add(cleartext);
364         cmd_font_panel = new Panel(new FlowLayout(FlowLayout.CENTER, 10, 3));
365             cmd_font_panel.add(l_font);
366             cmd_font_panel.add(usr_fontname);
367             cmd_font_panel.add(usr_fontsize);
368         cmd_panel = new Panel(new BorderLayout(0, 10));
369             cmd_panel.add("West", cmd_but_panel);
370             cmd_panel.add("Center", cmd_font_panel);
371             cmd_panel.add("East", usernum_lbl);
372
373         add("North", cmd_panel);
374         add("Center", main_text);
375         add("East", user_list);
376         add("South", user_prompt);
377         add("South", user_text);
378         validate();
379         user_text.requestFocus();
380   
381         refresh_user_list();
382     }
383
384     /******** refresh the display of the user list *******/
385     private void refresh_user_list()
386     {
387         Enumeration users_nicks = users.keys();
388         int count=0;
389
390         user_list.removeAll();
391         while(users_nicks.hasMoreElements()) {
392             count++;
393             user_list.add((String JavaDoc) users_nicks.nextElement());
394         }
395         usernum_lbl.setText(captions.getString("MSG_USERS")+": " + Integer.toString(count));
396     }
397
398     /******* return the Frame object of the applet *******/
399     private Frame get_my_frame()
400     {
401         Frame result = null;
402         Container c = this;
403
404         while(result == null && c != null) {
405             if(c instanceof Frame)
406                 result = (Frame) c;
407
408             c = c.getParent();
409         }
410         return result;
411     }
412
413     /********** print a notification to the user *********/
414     private void notify_user(String JavaDoc title, String JavaDoc msg)
415     {
416         final Dialog d = new Dialog(get_my_frame(), title, false);
417         Button ok_b;
418         Panel but_p;
419
420         ok_b = new Button(captions.getString("MSG_OK"));
421             ok_b.addActionListener(new ActionListener() {
422                 public void actionPerformed(ActionEvent evt) {
423                     d.dispose();
424                 }
425             });
426
427         but_p = new Panel(new FlowLayout(FlowLayout.CENTER));
428             but_p.add(ok_b);
429
430         d.setLayout(new GridLayout(2, 1));
431         d.add(new Label(" " + msg + " ", Label.CENTER)); // Provide some margins
432
d.add(but_p);
433         d.setForeground(getForeground());
434         d.setBackground(getBackground());
435         
436         d.pack();
437         center_window(d);
438         d.setVisible(true);
439     }
440
441     /******************** plays a beep *******************/
442     private void bip()
443     {
444
445         if(do_bip_as_sound_file.getState()) {
446             /* We must play a sound file */
447             if(bip_sound == null) /* Load the bip on demand */
448                 bip_sound = Applet.newAudioClip(getClass().getResource(
449                  "org/chateverywhere/resources/sounds/beep.au"));
450             
451             bip_sound.play();
452
453             return;
454         }
455
456
457         /* Else, we just play a system bip */
458
459         try {
460             java.awt.Toolkit.getDefaultToolkit().beep();
461         } catch(Exception JavaDoc e) {
462             System.out.println("Bip!");
463         }
464     }
465
466
467
468
469
470
471
472     /*****************************************************
473      * *
474      * Internal Events *
475      * *
476      *****************************************************/

477     /****************** request UI change ****************/
478     private boolean make_changements(String JavaDoc nick_txt)
479     {
480         nick = nick_txt.trim();
481         if(!make_connection(true))
482             return(false);
483     
484         launch_threads();
485         change_ui();
486         login_completed = true;
487
488         /* Start a private message if that was requested by the
489          * user in a parameter (ex: click on a name in a web user list)
490          */

491         if(getParameter("StartChatWith") != null) {
492             ChatPrivate child;
493             String JavaDoc d_nick = getParameter("StartChatWith");
494             
495             if((child = ((ChatPrivate) pmsg_windows.get(d_nick))) == null)
496                 child = create_private_window(d_nick);
497             else
498                 child.toFront();
499         }
500
501         return true;
502     }
503
504     /**************** connect to the server **************/
505     private boolean make_connection(boolean complete_login)
506     {
507         BufferedReader com_from_server;
508         BufferedWriter com_for_server;
509         String JavaDoc received;
510         int port = 5656;
511
512         error_message.setText(captions.getString("MSG_CONNECTING"));
513         error_message.repaint();
514
515         // Try to request more permissions in case we are signed
516
try {
517             netscape.security.PrivilegeManager.enablePrivilege("UniversalConnect");
518         } catch (Exception JavaDoc ex) {
519             System.out.println(captions.getString("MSG_NO_PRIV_NS"));
520         }
521         try {
522             com.ms.security.PolicyEngine.checkPermission(com.ms.security.PermissionID.NETIO);
523             com.ms.security.PolicyEngine.assertPermission(com.ms.security.PermissionID.NETIO);
524         } catch (Exception JavaDoc ex) {
525             System.out.println(captions.getString("MSG_NO_PRIV_IE"));
526         }
527
528         /* Get the server to connect to
529          * WARNING : unsigned applet can not connect on another server
530          * than the one where the web page is
531          *
532          * Some code copied from Eirc (eirc.sourceforge.net) thanks !
533          */

534         try {
535             if(getParameter("ServerHost") != null) {
536                 InetAddress [] addresses = InetAddress.getAllByName(getParameter("ServerHost"));
537
538                 /* Choose a random ip address in all the possibles */
539                 server = addresses[(int) Math.floor(Math.random() * addresses.length)];
540             } else {
541                 server=InetAddress.getByName(getCodeBase().getHost());
542             }
543         } catch(UnknownHostException e) {
544             System.out.println(e);
545             error_message.setText(captions.getString("MSG_NOT_FOUND"));
546             error_message.repaint();
547             return(false);
548         } catch(SecurityException JavaDoc e) {
549             System.out.println(e);
550             error_message.setText(captions.getString("MSG_NOT_SIGNED"));
551             error_message.repaint();
552             return(false);
553         }
554
555         /* Get the port number to connect to (default : 5656) */
556         if(getParameter("ServerPort") != null)
557             port = Integer.parseInt(getParameter("ServerPort"));
558
559         System.out.println(captions.getString("MSG_CONN")+" " + server + ":" + port);
560
561         try
562         {
563             com_sock=new Socket(server, port);
564             
565             com_from_server = new BufferedReader(new InputStreamReader(com_sock.getInputStream()));
566             com_for_server = new BufferedWriter(new OutputStreamWriter(com_sock.getOutputStream()));
567
568             // Do we want to really login ?
569
if(complete_login == true) {
570
571                 // Send some client informations (capabilities)
572
// might be better elsewhere (once login is completed)
573
String JavaDoc ref;
574                 String JavaDoc lng;
575                 ref = getCodeBase().toString(); /* getDocumentBase ? */
576                 lng = user_locale.toString();
577                 com_for_server.write("CLIENT <|> CAPABILITIES <|> " + version
578                  + " <|> " + ref + " <|> " + lng + " <|> CLIENT\n");
579
580                 com_for_server.write("CLIENT <|> LOGIN <|> "+nick+" <|> CLIENT\n");
581                 com_for_server.flush();
582                 received=com_from_server.readLine();
583                 
584                 // Answer analysis : may be LOGIN OK (fine), ERROR (bad login)
585
// or AUTH (we have to provide a password
586
// Trick : the code is quite ugly, so I should fix that later, but here
587
// is how it works : I just intercept the server's answer. If no auth is
588
// asked, nothing is done and it is going on as usual. Else, the function
589
// will provide the auth and then get back here as if we just tried to login.
590
received = check_auth(received, com_for_server, com_from_server);
591
592
593                 if(!received.equals("SERVER <|> LOGIN OK <|> SERVER"))
594                 {
595                     received = received.substring(received.indexOf("<|>") + 3);
596                     received = received.substring(received.indexOf("<|>") + 3);
597                     received = received.substring(0, received.indexOf("<|>"));
598                     error_message.setText(captions.getString("MSG_ERROR") +
599                     " : " + received);
600                     error_message.repaint();
601                     return(false);
602                 }
603             }
604
605             com_for_server.write("CLIENT <|> USERS <|> CLIENT\n");
606             com_for_server.flush();
607             received = com_from_server.readLine();
608             if(!received.startsWith("SERVER <|> USERS <|> ")) {
609                 if(!received.startsWith("SERVER <|> MSG <|> "))
610                     return(false);
611
612                 // This is the motd
613
while(!received.startsWith("SERVER <|> USERS <|> ")) {
614                     received = received.substring(received.indexOf("<|>")+4).trim();
615                     received = received.substring(received.indexOf("<|>")+4).trim();
616                     disp_message("** " + received.substring(0, received.indexOf("<|>")) + "\n");
617                     received = com_from_server.readLine();
618                 }
619             }
620
621             received = received.substring(received.indexOf("<|>") + 4).trim();
622             
623             // We just wanted some infos, closing connection
624
if(complete_login = false)
625                 com_sock.close();
626             
627             return(make_user_list(received));
628         }catch(Exception JavaDoc e)
629         {
630             System.out.println(e);
631             error_message.setText(captions.getString("MSG_SRV_DOWN"));
632             error_message.repaint();
633             return(false);
634         }
635     }
636
637     /*********** launch communication threads ************/
638     private boolean launch_threads()
639     {
640         com_thread=new ChatComThread(this,server,com_sock);
641         com_thread.start();
642
643         return(true);
644     }
645
646     /*************** the applet must stop ****************/
647     public void stop()
648     {
649         if(login_completed) {
650             Enumeration children = pmsg_windows.elements();
651
652             while(children.hasMoreElements())
653                 ((ChatPrivate) children.nextElement()).child_terminate();
654
655             com_thread.send_msg("CLIENT <|> QUIT <|> Quit : client left the page <|> CLIENT");
656         }
657     }
658
659     /************** must we authenticate ? ***************/
660     private String JavaDoc check_auth(String JavaDoc server_answer, BufferedWriter for_server, BufferedReader from_server)
661     {
662         String JavaDoc command;
663         String JavaDoc challenge;
664
665         command = server_answer.substring(server_answer.indexOf("<|>") + 3);
666         command = command.substring(0, command.indexOf("<|>")).trim();
667         if(command.equals("AUTH")) {
668             org.chateverywhere.InputDialog pass_win;
669             org.chateverywhere.MD5 hasher;
670             String JavaDoc password, p_hash, f_hash;
671
672             challenge = server_answer.substring(server_answer.indexOf("<|>") + 3);
673             challenge = challenge.substring(challenge.indexOf("<|>") + 3);
674             challenge = challenge.substring(0, challenge.indexOf("<|>")).trim();
675             
676             pass_win = new org.chateverywhere.InputDialog(get_my_frame(),
677              captions.getString("MSG_NICK_PROTECTED"),
678              captions.getString("MSG_ASK_PASSWORD"),
679              getForeground(), getBackground(), get_fginput_color(), get_bginput_color());
680
681             if(pass_win.is_data_ok() == false) {
682                 String JavaDoc ans;
683
684                 ans = "SERVER <|> ERROR <|> ";
685                 ans = ans + captions.getString("MSG_AUTH_FAILED");
686                 ans = ans + " <|> SERVER";
687                 return ans;
688             }
689             
690             password = pass_win.get_data();
691             pass_win = null;
692
693             hasher = new org.chateverywhere.MD5();
694             hasher.Update(password);
695             p_hash = hasher.asHex();
696             hasher.Init();
697             hasher.Update(p_hash + challenge);
698             f_hash = hasher.asHex();
699
700
701             try {
702                 for_server.write("CLIENT <|> AUTH <|> " + f_hash + " <|> CLIENT\n");
703                 for_server.flush();
704                 return from_server.readLine();
705             } catch(Exception JavaDoc e) {}
706         }
707
708         return server_answer;
709     }
710
711     /********** choice in the contextual menu ************/
712     private void popupmenu_selected(String JavaDoc command)
713     {
714         if(command.equals("msg")) {
715             ChatPrivate child;
716             String JavaDoc d_nick = user_list.getSelectedItem();
717             
718             if((child = ((ChatPrivate) pmsg_windows.get(d_nick))) == null)
719                 child = create_private_window(d_nick);
720             else
721                 child.toFront();
722
723         } else if(command.equals("stats")) {
724             com_thread.send_msg("CLIENT <|> STATS <|> " + user_list.getSelectedItem() + " <|> CLIENT");
725
726         } else if(command.equals("ignore")) {
727             com_thread.send_msg("CLIENT <|> IGNORE <|> " + user_list.getSelectedItem() + " <|> CLIENT");
728
729         } else if(command.equals("unignore")) {
730             com_thread.send_msg("CLIENT <|> UNIGNORE <|> " + user_list.getSelectedItem() + " <|> CLIENT");
731
732         } else if(command.equals("kick")) {
733             com_thread.send_msg("CLIENT <|> KICK <|> " + user_list.getSelectedItem() + " <|> CLIENT");
734
735         } else if(command.equals("ban")) {
736             com_thread.send_msg("CLIENT <|> BAN <|> " + user_list.getSelectedItem() + " <|> CLIENT");
737
738         } else if(command.equals("unban")) {
739             com_thread.send_msg("CLIENT <|> UNBAN <|> " + user_list.getSelectedItem() + " <|> CLIENT");
740
741         }
742     }
743
744
745
746
747
748
749
750     /*****************************************************
751      * *
752      * Chat Events *
753      * *
754      *****************************************************/

755     /**************** display a new message **************/
756     public void disp_message(String JavaDoc msg)
757     {
758         main_text.append(msg);
759
760         // Scroll the main window to the bottom
761
// FIXME : put a better value than 30000
762
if(login_completed && do_auto_scrolling.getState())
763             main_text.setCaretPosition(30000);
764
765         if(login_completed && do_bip_on_new_line.getState())
766             bip();
767     }
768
769     /****************** a new user joined ****************/
770     public void add_user(String JavaDoc name)
771     {
772         users.put(name,name);
773         user_list.add(name);
774         disp_message("**** " + name + " " + captions.getString("MSG_NEW_USER") + "\n");
775         usernum_lbl.setText(captions.getString("MSG_USERS")+": " + Integer.toString(user_list.getItemCount()));
776
777         if(do_notify_connection.getState())
778             notify_user(captions.getString("MSG_NEW_CONNECTION"),
779              name + " " + captions.getString("MSG_NEW_USER"));
780     }
781
782     /******************* a user has quit *****************/
783     public void remove_user(String JavaDoc name, String JavaDoc byemsg)
784     {
785         int count = user_list.getItemCount();
786         ChatPrivate child;
787
788         users.remove(name);
789         for(int i = 0;i < count;i++) {
790             if(user_list.getItem(i).equals(name)) {
791                 user_list.remove(i);
792                 break;
793             }
794         }
795         disp_message("**** "+name+" "+captions.getString("MSG_USER_QUIT")+" (" + byemsg +")\n");
796         usernum_lbl.setText("Users: " + Integer.toString(user_list.getItemCount()));
797         
798         // Were we private chatting with him ?
799
if((child = (ChatPrivate) pmsg_windows.get(name)) != null)
800             child.correspondant_has_quit(byemsg);
801     }
802
803     /************ new USERS message received *************/
804     private boolean make_user_list(String JavaDoc received)
805     {
806         users = new Hashtable();
807
808         received = received.substring(received.indexOf("<|>")+4);
809         while(!received.startsWith("SERVER")) {
810             String JavaDoc cur = received.substring(0,received.indexOf("<|>")).trim();
811             received = received.substring(received.indexOf("<|>") + 4);
812
813             if(!cur.equals(""));
814                 users.put(cur,cur);
815         }
816         return(true);
817     }
818
819
820
821
822
823
824
825     /*****************************************************
826      * *
827      * User input *
828      * *
829      *****************************************************/

830     /***** <Enter> key pressed in the user text zone *****/
831     private void send_user_text()
832     {
833         String JavaDoc temp, orig = user_text.getText();
834         int nlp;
835
836         temp = orig.trim();
837         if(temp.length() > 0) {
838             if(temp.startsWith("/")) {
839                 proceed_command(temp.substring(1));
840                 input_stack.add(temp);
841             } else {
842                 // Cut the message if multiple lines
843
while((nlp = orig.indexOf("\n")) != -1) {
844                     String JavaDoc n = orig.substring(0, nlp);
845                     com_thread.send_message(nick, n);
846                     disp_message("<" + nick + "> " + n + "\n");
847                     input_stack.add(n);
848                     orig = orig.substring(nlp + 1);
849                 }
850                 com_thread.send_message(nick, orig);
851                 disp_message("<" + nick + "> " + orig + "\n");
852                 input_stack.add(orig);
853             }
854         }
855         user_text.setText("");
856     }
857
858     /*********** the user has issued a command ***********/
859     public void proceed_command(String JavaDoc txt)
860     {
861         String JavaDoc com,com2;
862         
863         com2 = null;
864         
865         if(txt.indexOf(" ")==-1) {
866             com = txt.substring(0).toUpperCase();
867             com_thread.send_msg("CLIENT <|> " + com + " <|> CLIENT");
868         } else {
869             com=txt.substring(0,txt.indexOf(" ")).toUpperCase();
870             txt=txt.substring(txt.indexOf(" ")+1);
871             if(txt.indexOf(" ") == -1) {
872                 com_thread.send_msg("CLIENT <|> "+ com +" <|> "+ txt +" <|> CLIENT");
873             } else {
874                 com2=txt.substring(0,txt.indexOf(" "));
875                 txt=txt.substring(txt.indexOf(" ")+1);
876                 com_thread.send_msg("CLIENT <|> " + com + " <|> " + com2 + " <|> " + txt + " <|> CLIENT");
877             }
878
879             /* If it's a private message, print it to the sender */
880             if(com.equals("MSG") && com2 != null)
881                 disp_message(">" + com2 + "< " + txt + "\n");
882         }
883
884
885         /* If it's quit, we stop */
886         if(com.equals("QUIT"))
887             user_text.setEnabled(false);
888
889     }
890
891     /*********** auto nick completion with TAB ***********/
892     private void nick_completion()
893     {
894         String JavaDoc to_complete, candidate, orig, nouv;
895         int cp, sp;
896         Enumeration all_nicks = users.keys();
897         Vector possible_nicks = new Vector();
898
899
900         // Take the part of input to complete
901
cp = user_text.getCaretPosition();
902         orig = user_text.getText();
903         to_complete = orig.substring(0, cp);
904         if((sp = to_complete.lastIndexOf(" ")) != -1)
905             to_complete = to_complete.substring(sp + 1);
906
907         if(to_complete.equals(""))
908             return;
909
910         // Take the possibles choices
911
while(all_nicks.hasMoreElements()) {
912             candidate = (String JavaDoc) all_nicks.nextElement();
913             if(candidate.toLowerCase().startsWith(to_complete.toLowerCase()))
914                 possible_nicks.addElement(candidate);
915         }
916
917         // No candidates
918
if(possible_nicks.size() == 0)
919             return;
920
921         // Several candidates
922
if(possible_nicks.size() > 1) {
923             all_nicks = possible_nicks.elements();
924             candidate = all_nicks.nextElement() + " ";
925             while(all_nicks.hasMoreElements())
926                 candidate = candidate + all_nicks.nextElement() + " ";
927
928             disp_message("++ "+captions.getString("MSG_POSS_NICKS")+" : " + candidate + "\n");
929             return;
930         }
931
932         // do completion
933
candidate = (String JavaDoc) possible_nicks.firstElement();
934         if(sp == -1)
935             candidate = candidate + ": ";
936         orig = orig.substring(0, cp - to_complete.length()) + candidate + orig.substring(cp);
937         user_text.setText(orig);
938         user_text.setCaretPosition(cp - to_complete.length() + candidate.length());
939     }
940
941
942
943
944
945
946
947
948     /*****************************************************
949      * *
950      * Private chat in separate windows *
951      * *
952      *****************************************************/

953     /************** new private chat window **************/
954     public ChatPrivate create_private_window(String JavaDoc d_nick)
955     {
956         ChatPrivate child;
957
958         child = new ChatPrivate(this, d_nick);
959         pmsg_windows.put(d_nick, child);
960
961         return child;
962     }
963
964     /*************** display a private msg ***************/
965     public void disp_private_msg(String JavaDoc d_nick, String JavaDoc msg)
966     {
967         ChatPrivate child = (ChatPrivate) pmsg_windows.get(d_nick);
968
969         if(child == null)
970             child = create_private_window(d_nick);
971
972         child.disp_pmsg(msg);
973     }
974
975     /************** send a private message ***************/
976     public void send_pmsg(String JavaDoc to, String JavaDoc msg)
977     {
978         com_thread.send_msg("CLIENT <|> MSG <|> " + to + " <|> " + msg + " <|> CLIENT");
979     }
980
981     /************ the window has been closed *************/
982     public void pchat_closed(String JavaDoc p_nick)
983     {
984         pmsg_windows.remove(p_nick);
985     }
986
987
988
989
990
991     /*****************************************************
992      * *
993      * Event Handlers *
994      * *
995      *****************************************************/

996     /**************** click on a button ******************/
997     public void actionPerformed(ActionEvent evt)
998     {
999         Object JavaDoc src = evt.getSource();
1000        
1001// System.out.println("Event received from " + src);
1002

1003        if(src.equals(user_nick) || src.equals(go_login)) {
1004            make_changements(user_nick.getText());
1005        }
1006
1007        if(src.equals(cleartext))
1008            main_text.setText("");
1009
1010        if(src.equals(usr_popup)) {
1011            popupmenu_selected(evt.getActionCommand());
1012        }
1013
1014        if(src.equals(option_menu_trigger)) {
1015            // getHeight() is not supported by MS JVM
1016
option_menu.show(option_menu_trigger, 0, option_menu_trigger.getSize().height);
1017        }
1018    }
1019
1020
1021    /******************** Keys input *********************/
1022    public void keyPressed(KeyEvent e) {
1023        int k_code = e.getKeyCode();
1024        
1025        if(k_code == KeyEvent.VK_ENTER) {
1026            send_user_text();
1027        } else if(k_code == KeyEvent.VK_TAB) {
1028            tab_pressed = true;
1029            nick_completion();
1030        } else if(k_code == KeyEvent.VK_UP) {
1031            String JavaDoc n = input_stack.up();
1032
1033            user_text.setText(n);
1034            user_text.setCaretPosition(n.length() + 1);
1035        } else if(k_code == KeyEvent.VK_DOWN) {
1036            String JavaDoc n = input_stack.down();
1037
1038            if(n != null) {
1039                user_text.setText(n);
1040                user_text.setCaretPosition(n.length() + 1);
1041            }
1042        }
1043    }
1044
1045    /************ combo box (choice) changed *************/
1046    public void itemStateChanged(ItemEvent evt)
1047    {
1048        Object JavaDoc src = evt.getSource();
1049        
1050        if((src.equals(usr_fontsize) || src.equals(usr_fontname)) &&
1051            evt.getStateChange() == evt.SELECTED) {
1052            Enumeration children;
1053
1054            fnt = new Font(usr_fontname.getSelectedItem(), Font.PLAIN,
1055                           Integer.parseInt(usr_fontsize.getSelectedItem()));
1056            main_text.setFont(fnt);
1057            validate();
1058
1059            // Tells children windows to do so
1060
children = pmsg_windows.elements();
1061            while(children.hasMoreElements())
1062                ((ChatPrivate) children.nextElement()).change_font(fnt);
1063        }
1064
1065        /* display a popup menu when a user clicks on a name in the list */
1066        /* FIXME : we have a bug in here if the user moves the scrollbar of
1067         * the user list down, since we only use a computation on the element
1068         * index to place the pop up. I do not see any useful method in the actual
1069         * API that would allow me to correct that...
1070         * temporary fix: make sure popup does not appear too low
1071         */

1072        if(src.equals(user_list) && evt.getStateChange() == evt.SELECTED && login_completed) {
1073            // Display the popup menu where the user just clicked
1074
int item_number = Integer.parseInt(evt.getItem().toString());
1075
1076            // FIXME : rule of thumb for the click position
1077
int pos_y = item_number * 17 + 12;
1078            if(pos_y > user_list.getSize().height)
1079                pos_y = 3 * user_list.getSize().height / 4;
1080            usr_popup.show(user_list, 30, pos_y);
1081        }
1082    }
1083
1084    /***** keep the focus on user_txt if TAB pressed *****/
1085    public void focusLost(FocusEvent e)
1086    {
1087        if(tab_pressed) {
1088            user_text.requestFocus();
1089            tab_pressed = false;
1090        }
1091    }
1092
1093
1094    /**************** unused event handlers **************/
1095    public void keyReleased(KeyEvent e) {}
1096    public void keyTyped(KeyEvent e) {}
1097    public void focusGained(FocusEvent e) {}
1098
1099
1100
1101
1102
1103
1104
1105    /*****************************************************
1106     * *
1107     * Utilities *
1108     * *
1109     *****************************************************/

1110    /*************** center on the screen ****************/
1111    public void center_window(Window win)
1112    {
1113        Dimension screen;
1114        Dimension w = win.getSize();
1115        
1116// try {
1117
screen = this.getToolkit().getScreenSize();
1118// } catch(Exception e) {
1119
// getToolkit() can cause a security exception on IE
1120
// screen = new Dimension(800, 600);
1121
// }
1122

1123        /* Center the dialog on the screen */
1124        win.setBounds(screen.width/2 - w.width/2,
1125                      screen.height/2 - w.height/2,
1126                      w.width, w.height);
1127    }
1128
1129
1130
1131
1132
1133
1134
1135    /*****************************************************
1136     * *
1137     * Accessors *
1138     * *
1139     *****************************************************/

1140    /******************** applet fonts *******************/
1141    public Font get_txt_font() { return fnt; }
1142    public Font get_ui_font() { return ui_fnt; }
1143
1144    /******************* applet colors *******************/
1145    public Color get_fginput_color() { return user_text.getForeground(); }
1146    public Color get_bginput_color() { return user_text.getBackground(); }
1147    public Color get_fgtext_color() { return main_text.getForeground(); }
1148    public Color get_bgtext_color() { return main_text.getBackground(); }
1149
1150    /********************* user nick *********************/
1151    public String JavaDoc get_my_nick() { return nick; }
1152
1153    /****************** resource bundle ******************/
1154    public ResourceBundle get_translated_messages() { return captions; }
1155    
1156    /*********** applet parameters information ***********/
1157    public String JavaDoc[][] getParameterInfo()
1158    {
1159        String JavaDoc[][] pinfo = {
1160            { "BgColor", "#000000-#FFFFFF", "Background color of the applet (optional)"},
1161            { "FgColor", "#000000-#FFFFFF", "Foreground color of the applet (optional)"},
1162            { "UsersBgColor", "#000000-#FFFFFF", "Background color of the user list (optional)"},
1163            { "UsersFgColor", "#000000-#FFFFFF", "Foreground color of the user list (optional)"},
1164            { "TextBgColor", "#000000-#FFFFFF", "Background color of the text area (optional)"},
1165            { "TextFgColor", "#000000-#FFFFFF", "Foreground color of the text area (optional)"},
1166            { "InputBgColor", "#000000-#FFFFFF", "Background color of the input area (optional)"},
1167            { "InputFgColor", "#000000-#FFFFFF", "Foreground color of the input area (optional)"},
1168            { "LoginBgColor", "#000000-#FFFFFF", "Background color of the login area (nick text field) (optional)"},
1169            { "LoginFgColor", "#000000-#FFFFFF", "Foreground color of the login area (nick text field) (optional)"},
1170            { "UIFontName", "text", "Font to apply to the user interface components"},
1171            { "TextFontName", "text", "Font to apply to the text zones"},
1172            { "Nick", "text", "Nick of the user (optional)"},
1173            { "ServerPort", "1-65535", "Number of the port the server listens to"},
1174            { "ServerHost", "host.domain.tld", "Adress of the server to connect to"},
1175            { "StartChatWith", "nick", "Start a private chat upon connecting"}
1176        };
1177        return pinfo;
1178    }
1179}
1180
Popular Tags