Debug output added.
[ChatApp.git] / ChatApp / PaginaChat.java
blob752c6682373c2ed122a3e04b7f1485a8933a8a68
1 /*
2 * © 2010 ROBO Design
3 * http://www.robodesign.ro
5 * $Date: 2010-05-18 20:19:43 +0300 $
6 */
8 package ChatApp;
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());
60 myApp = rootApp;
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;
109 c.anchor = c.CENTER;
110 c.gridx = 0;
111 c.gridy = 0;
112 c.weightx = 1;
113 c.weighty = 0;
114 panouClienti.add(infoClienti, c);
116 c.insets = new Insets(0, 0, 0, 0);
117 c.fill = c.BOTH;
118 c.gridy = 1;
119 c.weighty = 1;
120 panouClienti.add(scrollListaClienti, c);
122 // un split pane care separa mesajele de pe server si panoul cu lista de
123 // clienti.
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;
144 c.anchor = c.WEST;
145 c.gridx = 0;
146 c.gridy = 0;
147 c.gridwidth = 1;
148 c.gridheight = 1;
149 c.weightx = 1;
150 c.weighty = 0;
151 this.add(infoConexiune, c);
153 c.fill = c.NONE;
154 c.anchor = c.EAST;
155 c.gridx = 2;
156 c.gridwidth = 1;
157 c.weightx = 0;
158 this.add(btnDeconectare, c);
160 c.insets = new Insets(12, 12, 5, 12);
162 c.fill = c.BOTH;
163 c.anchor = c.CENTER;
164 c.gridx = 0;
165 c.gridy = 2;
166 c.gridwidth = c.REMAINDER;
167 c.gridheight = c.RELATIVE;
168 c.weightx = 1;
169 c.weighty = 1;
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);
177 c.fill = c.NONE;
178 c.anchor = c.WEST;
179 c.gridx = 0;
180 c.gridy = 1;
181 c.gridwidth = 1;
182 c.gridheight = 1;
183 c.weightx = 0;
184 c.weighty = 0;
185 userPanel.add(btnNume, c);
187 c.fill = c.HORIZONTAL;
188 c.anchor = c.CENTER;
189 c.gridx = 1;
190 c.gridwidth = c.RELATIVE;
191 c.weightx = 1;
192 userPanel.add(msgField, c);
194 c.fill = c.NONE;
195 c.anchor = c.EAST;
196 c.gridx = 2;
197 c.gridwidth = 1;
198 c.weightx = 0;
199 userPanel.add(btnTrimite, c);
201 c.insets = new Insets(0, 12, 12, 12);
202 c.fill = c.HORIZONTAL;
203 c.anchor = c.CENTER;
204 c.gridx = 0;
205 c.gridy = 3;
206 c.gridwidth = c.REMAINDER;
207 c.gridheight = 1;
208 c.weightx = 1;
209 c.weighty = 0;
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())) {
219 return;
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();
234 return;
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)) {
253 return;
256 listaClienti.clearSelection();
257 listaClienti.setModel(myApp.getListaClienti());
258 listaClienti.ensureIndexIsVisible(0);
259 msgField.setText("");
261 chatTabs.setSelectedIndex(0);
262 while (chatTabs.getTabCount() > 1) {
263 chatTabs.remove(1);
266 // afisarea de mesaje trimise de catre server.
267 mesajeServer = null;
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));
276 f.pack();
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
289 // Chat.
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);
297 } else {
298 infoConexiune.setText("Deconectat de la " + myApp.getServerAdresa() + ":" + myApp.getServerPort() + ".");
299 btnDeconectare.setText("Iesire");
300 btnNume.setEnabled(false);
303 int nr = listaClienti.getModel().getSize();
305 if (nr == 0) {
306 infoClienti.setText("Nici un client");
307 } else if (nr == 1) {
308 infoClienti.setText("Un client");
309 } else {
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
319 // trimitere mesaj.
320 public void actionPerformed (ActionEvent ev) {
321 Object src = ev.getSource();
322 String cmd = ev.getActionCommand();
324 if (cmd == null) {
325 System.err.println("PaginaChat.actionPerformed: cmd == null");
326 return;
328 } else if (cmd.equals("trimiteMesaj")) {
329 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();
337 if (nume == null) {
338 return;
341 int t = chatTabs.indexOfTab(nume);
342 if (t == -1) {
343 return;
345 chatTabs.remove(t);
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)) {
360 return;
363 actualizareTabActiv();
365 if (msgField.isEnabled() && !msgField.isFocusOwner()) {
366 msgField.requestFocusInWindow();
369 int t = chatTabs.getSelectedIndex();
370 if (t != -1) {
371 String tab = chatTabs.getTitleAt(t);
373 Component compot = chatTabs.getTabComponentAt(t);
374 if (compot == null) {
375 return;
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) {
391 return;
394 int c = listaClienti.locationToIndex(ev.getPoint());
395 if (c != -1) {
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) {
405 return;
408 if (ev.getSource() == listaClienti) {
409 int i = listaClienti.getSelectedIndex();
410 if (i != -1) {
411 activareChatPrivat(i);
413 } else if (ev.getSource() == msgField) {
414 trimiteMesaj();
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();
425 if (c != null) {
426 String nume = c.getName();
427 DefaultListModel model = (DefaultListModel) listaClienti.getModel();
428 if (nume == null || (!nume.equals("#server") && !model.contains(nume))) {
429 allowSend = false;
431 } else {
432 allowSend = false;
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);
445 } else {
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) {
461 if (c < 0) {
462 return;
465 DefaultListModel model = (DefaultListModel) listaClienti.getModel();
466 String nume = (String) model.getElementAt(c);
467 if (nume == null || nume.equals(myApp.getNumeUtilizator())) {
468 return;
471 int t = chatTabs.indexOfTab(nume);
472 if (t == -1) {
473 t = adaugaChatPrivat(nume);
476 if (t != -1) {
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
485 // un utilizator.
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())) {
489 return -1;
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");
505 btn.setName(nume);
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);
517 if (i != -1) {
518 chatTabs.setTabComponentAt(i, panou);
519 } else {
520 System.err.println("PaginaChat.adaugaChatPrivat('" + nume + "') eroare: indexOfTab(nume) == -1");
523 return i;
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);
535 if (t == -1) {
536 return;
539 if (ts != t) {
540 Component compot = chatTabs.getTabComponentAt(t);
541 if (compot == null || !(compot instanceof JLabel)) {
542 return;
544 ((JLabel)compot).setForeground(Color.BLUE);
546 } else {
547 if (t == -1) {
548 if (cssClass.equals("mesaj")) {
549 t = adaugaChatPrivat(numeTab);
550 if (t == -1) {
551 return;
553 } else {
554 return;
558 Component compom = chatTabs.getComponentAt(t);
559 if (compom == null || !(compom instanceof PanouMesaje)) {
560 return;
563 PanouMesaje panoum = (PanouMesaje) compom;
564 panoum.adaugaMesaj(msg, cssClass);
566 if (ts != t) {
567 Component compot = chatTabs.getTabComponentAt(t);
568 if (compot == null || !(compot instanceof JPanel)) {
569 return;
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()) {
583 return;
586 DefaultListModel model = (DefaultListModel) listaClienti.getModel();
587 String catre = chatTabs.getSelectedComponent().getName();
589 if (catre == null || catre.equals(myApp.getNumeUtilizator())) {
590 return;
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()) {
603 return;
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
612 // server.
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");
628 return;
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);
648 if (t2 != -1) {
649 adaugaMesajInTab(numeNou, msg, "schimbareNume");
652 if (t != -1 && t2 == -1) {
653 Component compom = chatTabs.getComponentAt(t);
654 if (compom == null || !(compom instanceof PanouMesaje)) {
655 return;
658 ((PanouMesaje) compom).setName(numeNou);
659 chatTabs.setTitleAt(t, numeNou);
661 Component compot = chatTabs.getTabComponentAt(t);
662 if (compot == null || !(compot instanceof JPanel)) {
663 return;
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);
683 return;
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("<", "&lt;").replaceAll(">", "&gt;");