3 * http://www.robodesign.ro
5 * $Date: 2010-05-18 20:19:43 +0300 $
10 import java
.awt
.BorderLayout
;
11 import java
.awt
.Color
;
12 import java
.awt
.Component
;
13 import java
.awt
.Container
;
14 import java
.awt
.Dimension
;
15 import java
.awt
.GridBagConstraints
;
16 import java
.awt
.GridBagLayout
;
17 import java
.awt
.Insets
;
18 import java
.awt
.event
.ActionEvent
;
19 import java
.awt
.event
.ActionListener
;
20 import java
.awt
.event
.KeyAdapter
;
21 import java
.awt
.event
.KeyEvent
;
22 import java
.awt
.event
.KeyListener
;
23 import java
.awt
.event
.MouseAdapter
;
24 import java
.awt
.event
.MouseEvent
;
25 import java
.awt
.event
.MouseListener
;
26 import javax
.swing
.DefaultListModel
;
27 import javax
.swing
.JButton
;
28 import javax
.swing
.JFrame
;
29 import javax
.swing
.JLabel
;
30 import javax
.swing
.JList
;
31 import javax
.swing
.JOptionPane
;
32 import javax
.swing
.JPanel
;
33 import javax
.swing
.JScrollPane
;
34 import javax
.swing
.JSplitPane
;
35 import javax
.swing
.JTabbedPane
;
36 import javax
.swing
.JTextField
;
37 import javax
.swing
.ListSelectionModel
;
38 import javax
.swing
.border
.EmptyBorder
;
39 import javax
.swing
.event
.ChangeEvent
;
40 import javax
.swing
.event
.ChangeListener
;
41 import javax
.swing
.plaf
.basic
.BasicButtonUI
;
43 public class PaginaChat
extends JPanel
implements ActionListener
, ChangeListener
{
44 private appMain myApp
;
45 private JLabel infoClienti
;
46 private JLabel infoConexiune
;
47 private JButton btnNume
;
48 private JButton btnDeconectare
;
49 private JButton btnTrimite
;
50 private JList listaClienti
;
51 private JTextField msgField
;
52 private JButton btnTrimiteMesaj
;
53 private JTabbedPane chatTabs
;
54 private PanouMesaje mesajeServer
= null;
55 private JSplitPane tabServer
;
57 public PaginaChat (appMain rootApp
) {
58 super(new GridBagLayout());
62 infoConexiune
= new JLabel("Conectat la server:port.");
64 // Numele utilizatorului este afisat cu un buton ce permite utilizatorului
65 // sa-si schimbe numele daca este apasat.
66 btnNume
= new JButton("Nume:");
67 btnNume
.setToolTipText("Clic pentru schimbarea numelui tau");
68 btnNume
.setDefaultCapable(false);
69 btnNume
.setActionCommand("schimbareNume");
70 btnNume
.addActionListener(this);
72 // Deconectarea de la server.
73 btnDeconectare
= new JButton("Deconectare");
74 btnDeconectare
.setDefaultCapable(false);
75 btnDeconectare
.setActionCommand("deconectare");
76 btnDeconectare
.addActionListener(this);
78 // Trimitere de mesaje.
79 btnTrimite
= new JButton("Trimite");
80 btnTrimite
.setDefaultCapable(false);
81 btnTrimite
.setActionCommand("trimiteMesaj");
82 btnTrimite
.addActionListener(this);
84 msgField
= new JTextField();
85 msgField
.addKeyListener(fieldKeyListener
);
87 // lista de clienti conectati la server.
89 listaClienti
= new JList();
90 infoClienti
= new JLabel("Nici un client", JLabel
.CENTER
);
91 infoClienti
.setLabelFor(listaClienti
);
92 listaClienti
.setLayoutOrientation(JList
.VERTICAL
);
93 listaClienti
.setSelectionMode(ListSelectionModel
.SINGLE_SELECTION
);
94 listaClienti
.addMouseListener(listaClientiMouseListener
);
95 listaClienti
.addKeyListener(fieldKeyListener
);
97 JScrollPane scrollListaClienti
= new JScrollPane(listaClienti
);
99 listaClienti
.ensureIndexIsVisible(0);
101 // panoul cu lista de clienti.
102 JPanel panouClienti
= new JPanel(new GridBagLayout());
103 panouClienti
.setMinimumSize(new Dimension(100, 100));
105 GridBagConstraints c
= new GridBagConstraints();
107 c
.insets
= new Insets(5, 0, 5, 0);
108 c
.fill
= c
.HORIZONTAL
;
114 panouClienti
.add(infoClienti
, c
);
116 c
.insets
= new Insets(0, 0, 0, 0);
120 panouClienti
.add(scrollListaClienti
, c
);
122 // un split pane care separa mesajele de pe server si panoul cu lista de
124 tabServer
= new JSplitPane(JSplitPane
.HORIZONTAL_SPLIT
, true, null, panouClienti
);
125 tabServer
.setOneTouchExpandable(true);
126 tabServer
.setResizeWeight(0.85);
127 tabServer
.setName("#server");
129 JLabel tabServerLabel
= new JLabel("Server");
130 tabServerLabel
.setOpaque(false);
132 // taburile de chat: initial doar cu server. mai tarziu pot fi adaugate mai
133 // multe taburi, pentru discutiile private cu utilizatorii conectati.
134 chatTabs
= new JTabbedPane();
135 chatTabs
.addTab("#server", tabServer
);
136 chatTabs
.setSelectedIndex(0);
137 chatTabs
.setTabComponentAt(0, tabServerLabel
);
138 chatTabs
.addChangeListener(this);
140 // adaugam optiunile in interfata
141 c
.insets
= new Insets(12, 12, 0, 12);
143 c
.fill
= c
.HORIZONTAL
;
151 this.add(infoConexiune
, c
);
158 this.add(btnDeconectare
, c
);
160 c
.insets
= new Insets(12, 12, 5, 12);
166 c
.gridwidth
= c
.REMAINDER
;
167 c
.gridheight
= c
.RELATIVE
;
170 this.add(chatTabs
, c
);
172 // adaugam in interfata optiunile ce tin de schimbarea numelui si de
173 // trimiterea de mesaje.
174 JPanel userPanel
= new JPanel(new GridBagLayout());
176 c
.insets
= new Insets(0, 0, 0, 0);
185 userPanel
.add(btnNume
, c
);
187 c
.fill
= c
.HORIZONTAL
;
190 c
.gridwidth
= c
.RELATIVE
;
192 userPanel
.add(msgField
, c
);
199 userPanel
.add(btnTrimite
, c
);
201 c
.insets
= new Insets(0, 12, 12, 12);
202 c
.fill
= c
.HORIZONTAL
;
206 c
.gridwidth
= c
.REMAINDER
;
210 this.add(userPanel
, c
);
212 this.setMinimumSize(new Dimension(100, 100));
215 // fereastra ce permite utilizatorului sa-si schimbe numele
216 private void afisareSchimbareNume () {
217 String numeNou
= (String
) JOptionPane
.showInputDialog(myApp
.getMyFrame(), "Nume nou:", "Schimbare nume - ChatApp", JOptionPane
.PLAIN_MESSAGE
, null, null, myApp
.getNumeUtilizator());
218 if (numeNou
== null || numeNou
.isEmpty() || numeNou
.equals(myApp
.getNumeUtilizator())) {
222 numeNou
= numeNou
.trim();
223 if (!numeNou
.isEmpty()) {
224 numeNou
= numeNou
.replaceAll("/\\s+/", "-");
227 DefaultListModel model
= (DefaultListModel
) listaClienti
.getModel();
229 if (numeNou
.equals("#server") || numeNou
.equals(myApp
.getNumeUtilizator()) || model
.contains(numeNou
)) {
230 JOptionPane
.showMessageDialog(myApp
.getMyFrame(), "Noul nume este invalid.", "Eroare schimbare nume - ChatApp", JOptionPane
.ERROR_MESSAGE
);
231 if (!msgField
.isFocusOwner()) {
232 msgField
.requestFocusInWindow();
237 if (!myApp
.schimbareNume(numeNou
)) {
238 JOptionPane
.showMessageDialog(myApp
.getMyFrame(), "Numele tau nu a putut fi schimbat.", "Eroare schimbare nume - ChatApp", JOptionPane
.ERROR_MESSAGE
);
241 if (!msgField
.isFocusOwner()) {
242 msgField
.requestFocusInWindow();
246 // initializarea panoului chat, atunci cand utilizatorul se conecteaza la
247 // server. aceasta metoda actualizeaza elementele interfetei in functie de
248 // situatia curenta a conexiunii.
249 public void initializare () {
250 JFrame f
= myApp
.getMyFrame();
252 if (f
.getContentPane() == ((Container
) this)) {
256 listaClienti
.clearSelection();
257 listaClienti
.setModel(myApp
.getListaClienti());
258 listaClienti
.ensureIndexIsVisible(0);
259 msgField
.setText("");
261 chatTabs
.setSelectedIndex(0);
262 while (chatTabs
.getTabCount() > 1) {
266 // afisarea de mesaje trimise de catre server.
268 mesajeServer
= new PanouMesaje();
269 tabServer
.setLeftComponent((JScrollPane
) mesajeServer
);
271 actualizareStareConexiune();
273 f
.setContentPane((Container
) this);
274 f
.setMinimumSize(new Dimension(300, 300));
275 f
.setPreferredSize(new Dimension(550, 450));
277 f
.setLocationRelativeTo(null);
279 tabServer
.setDividerLocation(0.75);
281 myApp
.getRootPane().setDefaultButton(null);
283 if (!msgField
.isFocusOwner()) {
284 msgField
.requestFocusInWindow();
288 // seteaza/actualizeaza titlul JFrameului aplicatiei si alte texte din Pagina
290 private void actualizareStareConexiune () {
291 btnNume
.setText(myApp
.getNumeUtilizator() + ":");
293 if (myApp
.getServerConectat()) {
294 infoConexiune
.setText("Conectat la " + myApp
.getServerAdresa() + ":" + myApp
.getServerPort() + ".");
295 btnDeconectare
.setText("Deconectare");
296 btnNume
.setEnabled(true);
298 infoConexiune
.setText("Deconectat de la " + myApp
.getServerAdresa() + ":" + myApp
.getServerPort() + ".");
299 btnDeconectare
.setText("Iesire");
300 btnNume
.setEnabled(false);
303 int nr
= listaClienti
.getModel().getSize();
306 infoClienti
.setText("Nici un client");
307 } else if (nr
== 1) {
308 infoClienti
.setText("Un client");
310 infoClienti
.setText(nr
+ " clienti");
313 myApp
.getMyFrame().setTitle("ChatApp - " + myApp
.getNumeUtilizator() + " - " + myApp
.getServerAdresa() + ":" + myApp
.getServerPort());
315 actualizareTabActiv();
318 // event handler pentru butoanele din panou: schimbare nume, deconectare si
320 public void actionPerformed (ActionEvent ev
) {
321 Object src
= ev
.getSource();
322 String cmd
= ev
.getActionCommand();
325 System
.err
.println("PaginaChat.actionPerformed: cmd == null");
328 } else if (cmd
.equals("trimiteMesaj")) {
331 } else if (cmd
.equals("schimbareNume")) {
332 afisareSchimbareNume();
334 } else if (cmd
.equals("inchidereTab") && src
!= null && src
instanceof JButton
) {
335 JButton btn
= (JButton
) src
;
336 String nume
= btn
.getName();
341 int t
= chatTabs
.indexOfTab(nume
);
347 if (!msgField
.isFocusOwner()) {
348 msgField
.requestFocusInWindow();
351 } else if (cmd
.equals("deconectare")) {
352 myApp
.deconectareGUI();
356 // event handler pentru schimbarea de taburi.
357 public void stateChanged (ChangeEvent ev
) {
358 Object src
= ev
.getSource();
359 if (!(src
instanceof JTabbedPane
)) {
363 actualizareTabActiv();
365 if (msgField
.isEnabled() && !msgField
.isFocusOwner()) {
366 msgField
.requestFocusInWindow();
369 int t
= chatTabs
.getSelectedIndex();
371 String tab
= chatTabs
.getTitleAt(t
);
373 Component compot
= chatTabs
.getTabComponentAt(t
);
374 if (compot
== null) {
376 } else if (tab
.equals("#server") && compot
instanceof JLabel
) {
377 ((JLabel
)compot
).setForeground(Color
.BLACK
);
378 } else if (!tab
.equals("#server") && compot
instanceof JPanel
) {
379 Component eticheta
= ((JPanel
)compot
).getComponent(0);
380 if (eticheta
!= null && eticheta
instanceof JLabel
) {
381 ((JLabel
)eticheta
).setForeground(Color
.BLACK
);
387 // event handler pentru clickul in lista de utilizatori.
388 private MouseListener listaClientiMouseListener
= new MouseAdapter () {
389 public void mouseClicked (MouseEvent ev
) {
390 if (ev
.getClickCount() != 2) {
394 int c
= listaClienti
.locationToIndex(ev
.getPoint());
396 activareChatPrivat(c
);
401 // event handler pentru tastare in campul de text msgField si in listaClienti.
402 private KeyListener fieldKeyListener
= new KeyAdapter () {
403 public void keyPressed (KeyEvent ev
) {
404 if (ev
.getKeyCode() != KeyEvent
.VK_ENTER
) {
408 if (ev
.getSource() == listaClienti
) {
409 int i
= listaClienti
.getSelectedIndex();
411 activareChatPrivat(i
);
413 } else if (ev
.getSource() == msgField
) {
419 // in functie de tabul activ, aceasta metoda activeaza/dezactiveaza campul de
420 // text si butonul Trimite.
421 private void actualizareTabActiv () {
422 boolean allowSend
= true;
424 Component c
= chatTabs
.getSelectedComponent();
426 String nume
= c
.getName();
427 DefaultListModel model
= (DefaultListModel
) listaClienti
.getModel();
428 if (nume
== null || (!nume
.equals("#server") && !model
.contains(nume
))) {
435 if (myApp
.getServerConectat() && allowSend
) {
436 if (!btnTrimite
.isEnabled()) {
437 btnTrimite
.setEnabled(true);
439 if (!msgField
.isEnabled()) {
440 msgField
.setEnabled(true);
442 if (!msgField
.isEditable()) {
443 msgField
.setEditable(true);
446 if (btnTrimite
.isEnabled()) {
447 btnTrimite
.setEnabled(false);
449 if (msgField
.isEnabled()) {
450 msgField
.setEnabled(false);
452 if (msgField
.isEditable()) {
453 msgField
.setEditable(false);
458 // metoda permite initierea unui chat privat cu un utilizator, pe baza
459 // indexului in listaClienti.
460 private void activareChatPrivat (int c
) {
465 DefaultListModel model
= (DefaultListModel
) listaClienti
.getModel();
466 String nume
= (String
) model
.getElementAt(c
);
467 if (nume
== null || nume
.equals(myApp
.getNumeUtilizator())) {
471 int t
= chatTabs
.indexOfTab(nume
);
473 t
= adaugaChatPrivat(nume
);
477 chatTabs
.setSelectedIndex(t
);
478 if (msgField
.isEnabled() && !msgField
.isFocusOwner()) {
479 msgField
.requestFocusInWindow();
484 // aceasta metoda adauga un tab nou ce poate fi folosit pentru chat privat cu
486 private int adaugaChatPrivat (String nume
) {
487 int i
= chatTabs
.indexOfTab(nume
);
488 if (i
!= -1 || nume
== null || nume
.equals("#server") || nume
.equals(myApp
.getNumeUtilizator())) {
492 JScrollPane mesaje
= new PanouMesaje();
493 mesaje
.setName(nume
);
495 JLabel eticheta
= new JLabel(nume
);
496 eticheta
.setOpaque(false);
498 JButton btn
= new JButton("X");
499 btn
.setUI(new BasicButtonUI());
500 btn
.setContentAreaFilled(false);
501 btn
.setOpaque(false);
502 btn
.setMargin(new Insets(0,0,0,0));
503 btn
.setBorder(new EmptyBorder(new Insets(0,5,0,0)));
504 btn
.setToolTipText("Inchide discutia");
506 btn
.setActionCommand("inchidereTab");
507 btn
.addActionListener(this);
509 JPanel panou
= new JPanel(new BorderLayout());
510 panou
.setOpaque(false);
511 panou
.add(eticheta
, BorderLayout
.CENTER
);
512 panou
.add(btn
, BorderLayout
.EAST
);
514 chatTabs
.addTab(nume
, mesaje
);
516 i
= chatTabs
.indexOfTab(nume
);
518 chatTabs
.setTabComponentAt(i
, panou
);
520 System
.err
.println("PaginaChat.adaugaChatPrivat('" + nume
+ "') eroare: indexOfTab(nume) == -1");
526 // metoda permite adaugarea de mesaje in oricare tab
527 private void adaugaMesajInTab (String numeTab
, String msg
, String cssClass
) {
528 int t
= chatTabs
.indexOfTab(numeTab
);
529 int ts
= chatTabs
.getSelectedIndex();
531 System
.out
.println("PaginaChat.adaugaMesajInTab " + numeTab
+ " t " + t
+ " ts " + ts
+ " class " + cssClass
+ " msg " + msg
);
533 if (numeTab
.equals("#server")) {
534 mesajeServer
.adaugaMesaj(msg
, cssClass
);
540 Component compot
= chatTabs
.getTabComponentAt(t
);
541 if (compot
== null || !(compot
instanceof JLabel
)) {
544 ((JLabel
)compot
).setForeground(Color
.BLUE
);
548 if (cssClass
.equals("mesaj")) {
549 t
= adaugaChatPrivat(numeTab
);
558 Component compom
= chatTabs
.getComponentAt(t
);
559 if (compom
== null || !(compom
instanceof PanouMesaje
)) {
563 PanouMesaje panoum
= (PanouMesaje
) compom
;
564 panoum
.adaugaMesaj(msg
, cssClass
);
567 Component compot
= chatTabs
.getTabComponentAt(t
);
568 if (compot
== null || !(compot
instanceof JPanel
)) {
571 Component compoe
= ((JPanel
) compot
).getComponent(0);
572 if (compoe
!= null && compoe
instanceof JLabel
) {
573 ((JLabel
)compoe
).setForeground(Color
.BLUE
);
579 // metoda este chemata cand utilizatorul trimite un mesaj.
580 private void trimiteMesaj () {
581 String msg
= msgField
.getText();
582 if (msg
.trim().isEmpty()) {
586 DefaultListModel model
= (DefaultListModel
) listaClienti
.getModel();
587 String catre
= chatTabs
.getSelectedComponent().getName();
589 if (catre
== null || catre
.equals(myApp
.getNumeUtilizator())) {
591 } else if (catre
.equals("#server") || model
.contains(catre
)) {
592 myApp
.trimiteMesaj(catre
, msg
);
595 msgField
.setText("");
596 if (!msgField
.isFocusOwner()) {
597 msgField
.requestFocusInWindow();
601 public void ev_mesajTrimis (String catre
, String msg
) {
602 if (catre
== null || catre
.trim().isEmpty() || msg
== null || msg
.trim().isEmpty()) {
606 String msgf
= "<span class='nume'>" + htmlEscape(myApp
.getNumeUtilizator()) + "</span>: " + htmlEscape(msg
);
608 adaugaMesajInTab(catre
, msgf
, "mesaj");
611 // urmeaza o serie de metode invocate atunci cand un mesaj este primit de la
614 public void ev_conectareClient (String nume
) {
615 actualizareStareConexiune();
617 String msg
= "<span class='nume'>" + htmlEscape(nume
) + "</span> s-a conectat la server.";
619 adaugaMesajInTab("#server", msg
, "conectat");
620 adaugaMesajInTab(nume
, msg
, "conectat");
623 public void ev_deconectareClient (String nume
) {
624 actualizareStareConexiune();
626 if (nume
.equals("#server")) {
627 adaugaMesajInTab(nume
, "Serverul a inchis conexiunea.", "deconectat");
631 String msg
= "<span class='nume'>" + htmlEscape(nume
) + "</span> s-a deconectat de la server.";
632 adaugaMesajInTab("#server", msg
, "deconectat");
633 adaugaMesajInTab(nume
, msg
, "deconectat");
636 public void ev_schimbareNume (String numeVechi
, String numeNou
) {
637 if (numeNou
.equals(myApp
.getNumeUtilizator())) {
638 btnNume
.setText(numeNou
+ ":");
639 myApp
.getMyFrame().setTitle("ChatApp - " + myApp
.getNumeUtilizator() + " - " + myApp
.getServerAdresa() + ":" + myApp
.getServerPort());
642 String msg
= "<span class='nume'>" + htmlEscape(numeVechi
) + "</span> si-a schimbat numele in <span class='nume'>" + htmlEscape(numeNou
) + "</span>.";
643 adaugaMesajInTab("#server", msg
, "schimbareNume");
644 adaugaMesajInTab(numeVechi
, msg
, "schimbareNume");
646 int t
= chatTabs
.indexOfTab(numeVechi
);
647 int t2
= chatTabs
.indexOfTab(numeNou
);
649 adaugaMesajInTab(numeNou
, msg
, "schimbareNume");
652 if (t
!= -1 && t2
== -1) {
653 Component compom
= chatTabs
.getComponentAt(t
);
654 if (compom
== null || !(compom
instanceof PanouMesaje
)) {
658 ((PanouMesaje
) compom
).setName(numeNou
);
659 chatTabs
.setTitleAt(t
, numeNou
);
661 Component compot
= chatTabs
.getTabComponentAt(t
);
662 if (compot
== null || !(compot
instanceof JPanel
)) {
666 Component eticheta
= ((JPanel
) compot
).getComponent(0);
667 if (eticheta
!= null && eticheta
instanceof JLabel
) {
668 ((JLabel
) eticheta
).setText(numeNou
);
671 Component btn
= ((JPanel
) compot
).getComponent(1);
672 if (btn
!= null && btn
instanceof JButton
) {
673 ((JButton
) btn
).setName(numeNou
);
677 actualizareTabActiv();
680 public void ev_mesajPrimit (String dela
, String catre
, String msg
) {
681 if (dela
.equals("#server") || dela
.equals(myApp
.getNumeUtilizator())) {
682 System
.out
.println("PaginaChat.ev_mesajPrimit dela = " + dela
);
686 System
.out
.println("PaginaChat.ev_mesajPrimit dela " + dela
+ " catre " + catre
+ " msg " + msg
);
688 String msgf
= "<span class='nume'>" + htmlEscape(dela
) + "</span>: " + htmlEscape(msg
);
690 if (catre
.equals("#server")) {
691 adaugaMesajInTab(catre
, msgf
, "mesaj");
692 } else if (catre
.equals(myApp
.getNumeUtilizator())) {
693 adaugaMesajInTab(dela
, msgf
, "mesaj");
697 public void ev_listaClienti () {
698 actualizareStareConexiune();
701 private String
htmlEscape (String htmlStr
) {
702 return htmlStr
.replaceAll("<", "<").replaceAll(">", ">");