Base de données terminée + interface de la page de connexion et principale terminée
This commit is contained in:
parent
334fe1a14d
commit
7ae4d2ea04
49 changed files with 891 additions and 34 deletions
|
@ -1,10 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="lib/mysql-connector-java-5.0.5-bin.jar">
|
||||
<attributes>
|
||||
<attribute name="module" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
|
Binary file not shown.
BIN
chat/bin/controller/DataBase.class
Normal file
BIN
chat/bin/controller/DataBase.class
Normal file
Binary file not shown.
Binary file not shown.
BIN
chat/bin/gui/FenetreAcc$1.class
Normal file
BIN
chat/bin/gui/FenetreAcc$1.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreAcc.class
Normal file
BIN
chat/bin/gui/FenetreAcc.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreAccueil.class
Normal file
BIN
chat/bin/gui/FenetreAccueil.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$1.class
Normal file
BIN
chat/bin/gui/FenetreMenu$1.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$2.class
Normal file
BIN
chat/bin/gui/FenetreMenu$2.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$3$1.class
Normal file
BIN
chat/bin/gui/FenetreMenu$3$1.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$3$2.class
Normal file
BIN
chat/bin/gui/FenetreMenu$3$2.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$3.class
Normal file
BIN
chat/bin/gui/FenetreMenu$3.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu$4.class
Normal file
BIN
chat/bin/gui/FenetreMenu$4.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/FenetreMenu.class
Normal file
BIN
chat/bin/gui/FenetreMenu.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/Onglet.class
Normal file
BIN
chat/bin/gui/Onglet.class
Normal file
Binary file not shown.
BIN
chat/bin/gui/Room.class
Normal file
BIN
chat/bin/gui/Room.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
chat/bin/model/MessageDeconnexion.class
Normal file
BIN
chat/bin/model/MessageDeconnexion.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
chat/lib/mysql-connector-java-5.0.5-bin.jar
Normal file
BIN
chat/lib/mysql-connector-java-5.0.5-bin.jar
Normal file
Binary file not shown.
|
@ -3,6 +3,7 @@ package controller;
|
|||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import model.*;
|
||||
import network.*;
|
||||
|
@ -14,6 +15,11 @@ public class Agent {
|
|||
private TCPChat TCPSend;
|
||||
private TCPServer server;
|
||||
private ListeContacts list;
|
||||
private InetAddress localAddress;
|
||||
private InetAddress broadcast;
|
||||
private ArrayList<TCPChat> listTCP;
|
||||
private DataBase db;
|
||||
|
||||
|
||||
|
||||
public Agent(InetAddress address, int portIn, int portOut) throws IOException {
|
||||
|
@ -21,15 +27,19 @@ public class Agent {
|
|||
this.BIn = new UDPInput(user.getAddress(), portIn);
|
||||
this.BOut = new UDPOutput(user, portOut);
|
||||
this.server = new TCPServer(user.getPort(), user.getAddress());
|
||||
this.TCPSend = new TCPChat(user);
|
||||
//this.TCPSend = new TCPChat(user);
|
||||
this.list = ListeContacts.getInstance();
|
||||
this.localAddress=Tools.getAdress()[0];
|
||||
this.broadcast= Tools.getAdress()[1];
|
||||
this.db = DataBase.getInstance();
|
||||
this.listTCP = new ArrayList<TCPChat>();
|
||||
BIn.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Envoi sur 5001 et reçoit sur 5000
|
||||
public void testSendBroadcast() throws IOException, InterruptedException {
|
||||
BIn.start();
|
||||
MessagePseudo msg = new MessagePseudo(this.user.getAddress(), Tools.getLocalIp(), user.getPort(), 14000, 1, "Michel");
|
||||
BOut.send(msg, user.getAddress(), user.getPort());
|
||||
Thread.sleep(10);
|
||||
|
@ -63,20 +73,125 @@ public class Agent {
|
|||
|
||||
}
|
||||
|
||||
public void handleMessage(MessagePseudo msg) {
|
||||
if(!list.pseudoExist(msg.getPseudo())) {
|
||||
Contact newUser = new Contact(msg.getPseudo(), msg.getAddressSrc(), msg.getPortSrc());
|
||||
list.addContact(newUser);
|
||||
/*type 0 : premier message de broadcast
|
||||
* type, 1 : deuxieme message de broadcast avec pseudo
|
||||
* type 2 : Message de déconnexion
|
||||
*/
|
||||
|
||||
public void handleMessage(Message msg) throws IOException {
|
||||
switch(msg.getTypeMessage()) {
|
||||
case 0 :
|
||||
MessagePseudo msgPresentation = new MessagePseudo(this.localAddress, msg.getAddressSrc(), this.user.getPort(), msg.getPortSrc(), 1, this.user.getPseudo());
|
||||
BOut.send(msgPresentation, msg.getAddressSrc(), msg.getPortSrc());
|
||||
|
||||
case 1 :
|
||||
MessagePseudo msgPseudo = (MessagePseudo) msg;
|
||||
if(!list.pseudoExist(msgPseudo.getPseudo())) {
|
||||
Contact newUser = new Contact(msgPseudo.getPseudo(), msgPseudo.getAddressSrc(), msgPseudo.getPortSrc());
|
||||
list.addContact(newUser);
|
||||
}
|
||||
/*case 2 :
|
||||
MessageDeconnexion messageDeconnexion = (MessageDeconnexion) msg;
|
||||
if(list.pseudoExist(messageDeconnexion.getPseudo())){
|
||||
Contact contact = list.findContact(messageDeconnexion.getPseudo());
|
||||
list.deleteContact(contact);
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void choisirPseudo(String pseudo) {
|
||||
public boolean connect(String pseudo) throws IOException, InterruptedException {
|
||||
MessagePseudo msg_connexion = new MessagePseudo(this.localAddress, this.broadcast, this.user.getPort(), 25000, 0, "");
|
||||
BOut.send(msg_connexion, this.broadcast, 25000);
|
||||
Thread.sleep(5000);
|
||||
ArrayList<MessagePseudo> msg_recus = BIn.getListMessage();
|
||||
for(int i =0; i<msg_recus.size(); i++) {
|
||||
handleMessage(msg_recus.get(i));
|
||||
}
|
||||
boolean pseudoOK = choisirPseudo(pseudo);
|
||||
list.addContact(user);
|
||||
if(pseudoOK){
|
||||
int id = db.addUser(pseudo);
|
||||
this.user.setId(id);
|
||||
System.out.println("Connexion réussie avec le pseudo : "+pseudo);
|
||||
}else {
|
||||
System.out.println("Echec de la connexion, veuillez choisir un autre pseudo");
|
||||
}
|
||||
return pseudoOK;
|
||||
}
|
||||
|
||||
public boolean choisirPseudo(String pseudo) {
|
||||
if(!list.pseudoExist(pseudo)){
|
||||
user.setPseudo(pseudo);
|
||||
System.out.println("Pseudo set : "+pseudo);
|
||||
return true;
|
||||
}else {
|
||||
System.out.println("Pseudo déjà utilisé");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void deconnexion() throws IOException {
|
||||
MessageDeconnexion msgDeconnexion = new MessageDeconnexion(this.localAddress, this.broadcast, this.user.getPort(), 25000, 3, user.getPseudo());
|
||||
BOut.send(msgDeconnexion, this.broadcast, this.user.getPort());
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public boolean changerPseudo(String pseudo) {
|
||||
boolean changeOK = choisirPseudo(pseudo);
|
||||
if(changeOK){
|
||||
System.out.println("Pseudo changé à : "+pseudo);
|
||||
db.updatePseudo(this.user.getId(), pseudo);
|
||||
return true;
|
||||
}else {
|
||||
System.out.println("Veuillez choisir un autre pseudo");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean chatExists(int destID) {
|
||||
boolean chatExists = false;
|
||||
for(TCPChat tcp : listTCP) {
|
||||
if(tcp.getDestID()==destID) {
|
||||
chatExists = true;
|
||||
}
|
||||
}
|
||||
return chatExists;
|
||||
}
|
||||
|
||||
public void createChat (int destId, String destPseudo) throws IOException {
|
||||
boolean chatExists = chatExists(destId);
|
||||
if(!chatExists) {
|
||||
for(Contact user : list.getListe()) {
|
||||
if(user.getPseudo().equals(destPseudo)) {
|
||||
TCPChat connexionTCP = new TCPChat(user, destId);
|
||||
listTCP.add(connexionTCP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Contact getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setUser(Contact user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ListeContacts getList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setList(ListeContacts list) {
|
||||
this.list = list;
|
||||
}
|
||||
}
|
||||
|
|
129
chat/src/controller/DataBase.java
Normal file
129
chat/src/controller/DataBase.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
package controller;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
public class DataBase {
|
||||
|
||||
//Connexion serveur GEI
|
||||
//login : tp_servlet_018
|
||||
//password : Taey2Aje
|
||||
//Plus d'infs connexion sur moodle
|
||||
|
||||
private static DataBase instance = null;
|
||||
|
||||
public Connection connexion;
|
||||
|
||||
private DataBase() {
|
||||
try {
|
||||
Class.forName("com.mysql.jdbc.Driver");
|
||||
}catch (ClassNotFoundException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
connexion = DriverManager.getConnection("jdbc:mysql://srv-bdens.insa-toulouse.fr:3306/tp_servlet_018?useSSL=false", "tp_servlet_018", "Taey2Aje");
|
||||
//connexion = DriverManager.getConnection("jdbc:mysql://localhost/test?characterEncoding=utf8", "root","root");
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static DataBase getInstance() {
|
||||
synchronized (DataBase.class) {
|
||||
DataBase db = instance;
|
||||
if(db == null) {
|
||||
db = new DataBase();
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
|
||||
//retourne l'id associé au user ajouté
|
||||
public int addUser(String pseudo) {
|
||||
String query = "INSERT INTO users (`pseudo`) VALUES (?)";
|
||||
PreparedStatement pStat = null;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setString(1, pseudo);
|
||||
pStat.executeUpdate();
|
||||
}catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
query = "SELECT * FROM users WHERE pseudo=?";
|
||||
int id =0;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setString(1, pseudo);
|
||||
ResultSet resId = pStat.executeQuery();
|
||||
if(resId.first()) {
|
||||
id = resId.getInt("id");
|
||||
}
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getPseudoFromId(int id) {
|
||||
String pseudo = null;
|
||||
String query = "SELECT * FROM users WHERE id=?";
|
||||
PreparedStatement pStat = null;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setInt(1, id);
|
||||
ResultSet resPseudo = pStat.executeQuery();
|
||||
if(resPseudo.first()) {
|
||||
pseudo = resPseudo.getString("pseudo");
|
||||
}
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
public void deleteFromId(int id) {
|
||||
String query = "DELETE FROM `users` WHERE `id` = ?";
|
||||
PreparedStatement pStat = null;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setInt(1, id);
|
||||
pStat.executeUpdate();
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updatePseudo(int id, String pseudo) {
|
||||
String query = "UPDATE `users` SET `pseudo`=? WHERE id=?";
|
||||
PreparedStatement pStat = null;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setString(1, pseudo);
|
||||
pStat.setInt(2, id);
|
||||
pStat.executeUpdate();
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void newChatTable (int id1, int id2) {
|
||||
int idSrc = id1;
|
||||
int idDest = id2;
|
||||
if(id1>id2) {
|
||||
idSrc = id2;
|
||||
idDest = id1;
|
||||
}
|
||||
String nameTable = idSrc+"_"+idDest;
|
||||
//String query = "CREATE TABLE `"+nameTable+"`(\n"+"`id` int "=? WHERE id=?";
|
||||
/*PreparedStatement pStat = null;
|
||||
try {
|
||||
pStat = connexion.prepareStatement(query);
|
||||
pStat.setString(1, pseudo);
|
||||
pStat.setInt(2, id);
|
||||
pStat.executeUpdate();
|
||||
}catch(SQLException e) {
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
|
@ -6,7 +6,8 @@ import network.Tools;
|
|||
|
||||
public class Test {
|
||||
public static void main(String args[]) throws IOException, InterruptedException {
|
||||
Agent agent1 = new Agent(Tools.getLocalIp(), 18000, 18001);
|
||||
agent1.testSendTCP();
|
||||
Agent agent1 = new Agent(Tools.getAdress()[1], 22001, 22000);
|
||||
agent1.testSendBroadcast();
|
||||
//Tools.printInterfaces();
|
||||
}
|
||||
}
|
||||
|
|
125
chat/src/gui/FenetreAcc.java
Normal file
125
chat/src/gui/FenetreAcc.java
Normal file
|
@ -0,0 +1,125 @@
|
|||
package gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.io.IOException;
|
||||
|
||||
import controller.*;
|
||||
import network.Tools;
|
||||
|
||||
public class FenetreAcc implements ActionListener {
|
||||
JFrame frame;
|
||||
JPanel panel;
|
||||
JTextField pseudofield;
|
||||
JLabel Text;
|
||||
JButton Connexion;
|
||||
|
||||
/*
|
||||
* Constructeur d'une fenetre d'affichage pour la connexion d'un utilisateur.
|
||||
* Cette fenetre sera munie d'un bouton de connexion et d'une zone de saisie de pseudo.
|
||||
*/
|
||||
public FenetreAcc() {
|
||||
// TODO Auto-generated constructor stub
|
||||
//creer une instance JFrame
|
||||
frame = new JFrame("Fenetre accueil");
|
||||
//sortir quand l’utilisateur ferme le frame
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
// fixer les dimensions de la fenetre
|
||||
frame.setSize(new Dimension(120, 40));
|
||||
//Creer le JPanel
|
||||
panel = new JPanel(new GridLayout(3,1));
|
||||
//Ajouter les elements
|
||||
this.addWidgets();
|
||||
//Set the default button.
|
||||
frame.getRootPane().setDefaultButton(Connexion);
|
||||
//Ajouter le panel a la window
|
||||
frame.getContentPane().add(panel, BorderLayout.CENTER);
|
||||
//L'utilisateur ne pourra pas aggrandir la fenetre
|
||||
this.frame.setResizable(false);
|
||||
//Afficher la fenetre
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private void addWidgets() {
|
||||
// Créer Zone d'insertion de texte pour le pseudo
|
||||
this.pseudofield = new JTextField(2);
|
||||
// creation d'un label qui contiendra un txt au centre
|
||||
this.Text = new JLabel("Type your user name", SwingConstants.CENTER);
|
||||
//Ajout d'un bouton Connexion
|
||||
this.Connexion = new JButton("Connexion");
|
||||
//On associe au bouton Connexion des actions a realiser
|
||||
this.Connexion.addActionListener(this);
|
||||
// On ajouter les differents elements au panel
|
||||
panel.add(pseudofield);
|
||||
panel.add(Text);
|
||||
panel.add(Connexion);
|
||||
//ajouter un effet de bord transparent au composant Jlabel
|
||||
Text.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
// on recupere le texte entree dans la zone de saisie
|
||||
String pseudo = pseudofield.getText();
|
||||
// On crée un objet de type ChatApp
|
||||
Agent agent;
|
||||
boolean connexion;
|
||||
|
||||
try {
|
||||
agent = new Agent(Tools.getLocalIp(), 25000, 25001);
|
||||
// on tente une connexion avec ce pseudo
|
||||
connexion = agent.connect(pseudo);
|
||||
// Dans les deux cas de figures (reussite ou echec) on affiche un pop-up pour expliquer la situation
|
||||
if(connexion) {
|
||||
// La connexion a reussi
|
||||
JOptionPane.showMessageDialog(frame, "Bonjour " + pseudo) ;
|
||||
frame.dispose();
|
||||
// on lance une nouvelle fenetre de type View_Menu
|
||||
FenetreMenu fenetreCourante= new FenetreMenu(agent);
|
||||
}
|
||||
else {
|
||||
// La connexion a echoue, il est possible de rentrer un nouveau pseudo
|
||||
JOptionPane.showMessageDialog(frame, "Echec de Connexion , ce pseudo est deja pris !");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("Création thread impossible");
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("connect impossible");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void createAndShowGUI() {
|
||||
// Etre certain d'avoir une joli fenetre
|
||||
JFrame.setDefaultLookAndFeelDecorated(true);
|
||||
// On crée une fentre d'acceuil
|
||||
FenetreAcc fenetre = new FenetreAcc();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
//Schedule a job for the event-dispatching thread:
|
||||
//creating and showing this application's GUI.
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGUI();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
54
chat/src/gui/FenetreAccueil.java
Normal file
54
chat/src/gui/FenetreAccueil.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
package gui;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
||||
import model.Contact;
|
||||
import model.ListeContacts;
|
||||
|
||||
public class FenetreAccueil extends JFrame{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JList<String> contacts;
|
||||
private JTabbedPane tab;
|
||||
private JComboBox<String> status;
|
||||
public static DefaultListModel<ListeContacts> listeUtilisateurs = new DefaultListModel<ListeContacts>();
|
||||
private Contact user;
|
||||
|
||||
|
||||
public FenetreAccueil(Contact c) {
|
||||
this.user = c;
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
public void init(){
|
||||
setTitle("Application Chat");
|
||||
setSize(300, 550);
|
||||
|
||||
try {
|
||||
= new ListeContacts();
|
||||
if(listeContacts.length()){
|
||||
contacts = new JList<String>(listeContacts);
|
||||
//discussion = new JList<String>(liste2);
|
||||
//nbRoom=liste2.length;
|
||||
}else{
|
||||
contacts = new JList<String>();
|
||||
//discussion = new JList<String>();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
}
|
||||
|
||||
tab = new JTabbedPane(JTabbedPane.BOTTOM);
|
||||
status = new JComboBox<String>(new String[]{
|
||||
"connecté",
|
||||
"déconnecté"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -4,15 +4,21 @@ import java.awt.EventQueue;
|
|||
|
||||
import javax.swing.*;
|
||||
|
||||
import controller.Agent;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class FenetreChat extends JFrame{
|
||||
|
||||
|
||||
private String title = "Fenetre Chat";
|
||||
private JPanel contentPane;
|
||||
private JTextArea txtOutput = new JTextArea();
|
||||
private JTextField txtMessage = new JTextField();
|
||||
private JButton btnSend = new JButton("Envoyer");
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
/*public static void main(String[] args) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
|
@ -23,12 +29,13 @@ public class FenetreChat extends JFrame{
|
|||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Create the application.
|
||||
*/
|
||||
public FenetreChat() {
|
||||
public FenetreChat(Agent agent, String s) {
|
||||
this.setTitle(title);
|
||||
initialize2();
|
||||
}
|
||||
|
||||
|
@ -36,10 +43,22 @@ public class FenetreChat extends JFrame{
|
|||
* Initialize the contents of the frame.
|
||||
*/
|
||||
private void initialize2() {
|
||||
contentPane = new JPanel();
|
||||
setContentPane(contentPane);
|
||||
setTitle("Chat Window");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
this.setAlwaysOnTop(true);
|
||||
contentPane = (JPanel)this.getContentPane();
|
||||
JScrollPane sclPane = new JScrollPane(txtOutput);
|
||||
contentPane.add(sclPane, BorderLayout.CENTER);
|
||||
JPanel southPanel = new JPanel(new BorderLayout());
|
||||
southPanel.add(this.txtMessage, BorderLayout.CENTER);
|
||||
southPanel.add(this.btnSend, BorderLayout.EAST);
|
||||
contentPane.add(southPanel, BorderLayout.SOUTH);
|
||||
|
||||
this.txtOutput.setBackground(new Color(220,220,220));
|
||||
this.txtOutput.setEditable(false);
|
||||
this.setSize(500,400);
|
||||
this.setVisible(true);
|
||||
this.txtMessage.requestFocus();
|
||||
|
||||
/*setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(400, 300);
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
|
@ -49,9 +68,10 @@ public class FenetreChat extends JFrame{
|
|||
panel.add(label);
|
||||
panel.add(tf);
|
||||
panel.add(send);
|
||||
contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
|
||||
JTextArea ta = new JTextArea();
|
||||
contentPane.add(BorderLayout.SOUTH, panel);
|
||||
contentPane.add(BorderLayout.CENTER, ta);
|
||||
contentPane.add(ta);
|
||||
contentPane.add(panel);*/
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -38,14 +38,11 @@ public class FenetreLogin extends JFrame{
|
|||
* Initialize the contents of the frame.
|
||||
*/
|
||||
private void initialize() {
|
||||
contentPane = new JPanel();
|
||||
contentPane = new JPanel(new GridBagLayout());
|
||||
setContentPane(contentPane);
|
||||
setTitle("Login Frame");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setSize(400, 300);
|
||||
|
||||
JTextField pseudo = new JTextField(4);
|
||||
JLabel txt = new JLabel("Pseudo", SwingConstants.LEFT);
|
||||
setSize(597, 412);
|
||||
JButton connect = new JButton("Connect");
|
||||
connect.addActionListener(new ActionListener(){
|
||||
|
||||
|
@ -66,11 +63,25 @@ public class FenetreLogin extends JFrame{
|
|||
converterPanel.add(convertTemp);
|
||||
converterPanel.add(fahrenheitLabel);
|
||||
*/
|
||||
txt.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
|
||||
|
||||
GridBagConstraints gbcConnect = new GridBagConstraints();
|
||||
gbcConnect.insets = new Insets(0, 0, 5, 0);
|
||||
gbcConnect.gridx = 4;
|
||||
gbcConnect.gridy = 0;
|
||||
|
||||
contentPane.add(pseudo);
|
||||
contentPane.add(txt);
|
||||
contentPane.add(connect);
|
||||
JTextField pseudo = new JTextField(10);
|
||||
|
||||
GridBagConstraints gbcPseudo = new GridBagConstraints();
|
||||
gbcPseudo.insets = new Insets(0, 0, 5, 5);
|
||||
|
||||
gbcPseudo.gridx = 0;
|
||||
gbcPseudo.gridy = 0;
|
||||
gbcPseudo.ipadx = 75;
|
||||
gbcPseudo.ipady = 75;
|
||||
gbcPseudo.gridwidth = 4;
|
||||
|
||||
contentPane.add(pseudo, gbcPseudo);
|
||||
contentPane.add(connect, gbcConnect);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
190
chat/src/gui/FenetreMenu.java
Normal file
190
chat/src/gui/FenetreMenu.java
Normal file
|
@ -0,0 +1,190 @@
|
|||
package gui;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.SystemColor;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import controller.Agent;
|
||||
import model.Contact;
|
||||
|
||||
public class FenetreMenu {
|
||||
JFrame frame;
|
||||
JPanel panel;
|
||||
JMenuBar menu;
|
||||
Agent agent;
|
||||
JLabel jlabel;
|
||||
JLabel texte;
|
||||
JLabel liste;
|
||||
WindowAdapter wa ;
|
||||
|
||||
public FenetreMenu(Agent agent) {
|
||||
this.agent = agent;
|
||||
frame = new JFrame("Fenêtre menu");
|
||||
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
|
||||
frame.setSize(new Dimension(100, 100));
|
||||
|
||||
wa = new WindowAdapter(){
|
||||
public void windowClosing(WindowEvent e){
|
||||
int reponse = showConfirmDialog();
|
||||
if (reponse==0){
|
||||
try {
|
||||
// on deconnecte l'app avant de quitter
|
||||
// Tout les utilisateurs sont donc prevenus du depart
|
||||
agent.deconnexion();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
frame.dispose();
|
||||
}
|
||||
}};
|
||||
|
||||
|
||||
frame.addWindowListener(wa);
|
||||
menu = new JMenuBar();
|
||||
//Creation d'un JPanel
|
||||
panel = new JPanel(new GridLayout(3,1));
|
||||
panel.setForeground(SystemColor.menuText);
|
||||
// Ajouter tout les elements a la fenetre
|
||||
this.addWidgets();
|
||||
// ajouter le panel a la fenetre
|
||||
frame.getContentPane().add(panel, BorderLayout.CENTER);
|
||||
// Afficher la fenetre
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
static int showConfirmDialog() {
|
||||
return JOptionPane.showConfirmDialog(
|
||||
null,
|
||||
"Are you sure you wanna quit?",
|
||||
"Quitter",
|
||||
JOptionPane.YES_NO_OPTION);
|
||||
}
|
||||
|
||||
private void addWidgets() {
|
||||
jlabel = new JLabel(new ImageIcon("/Users/momof/eclipse-workspace/chat/src/images/panda.png"), JLabel.CENTER);
|
||||
texte = new JLabel("Bienvenue sur ce magnifique chat " + agent.getUser().getPseudo());
|
||||
texte.setFont(new Font("Century Schoolbook", Font.PLAIN, 40));
|
||||
texte.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
liste = new JLabel("Active users", JLabel.LEFT);
|
||||
|
||||
JMenu contenu = new JMenu("Actions");
|
||||
contenu.setForeground(Color.BLUE);
|
||||
contenu.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
//JMenuItem usersActifs = new JMenuItem("Active users");
|
||||
JMenuItem modifierPseudo = new JMenuItem("Modify your pseudo");
|
||||
JMenuItem deco = new JMenuItem("Deconnection");
|
||||
|
||||
//contenu.add(usersActifs);
|
||||
contenu.add(modifierPseudo);
|
||||
contenu.add(deco);
|
||||
|
||||
|
||||
menu.add(contenu);
|
||||
frame.setJMenuBar(menu);
|
||||
|
||||
/*liste déroulante des utilsateurs actifs,
|
||||
* cliquer dessus pour créer une fenêtre de chat*/
|
||||
JTextArea ta = new JTextArea(20,20);
|
||||
ta.insert("Active users\n",0);
|
||||
JScrollPane scrollPane = new JScrollPane(ta);
|
||||
|
||||
String users = agent.getList().actifUsers();
|
||||
Vector<String> v = new Vector<String>();
|
||||
for(String pseudo : users.split("\n")) {
|
||||
v.add(pseudo);
|
||||
}
|
||||
|
||||
JComboBox cb = new JComboBox(v);
|
||||
cb.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
Object selected = cb.getSelectedItem();
|
||||
new FenetreChat(agent, selected.toString());
|
||||
|
||||
}
|
||||
});
|
||||
panel.add(BorderLayout.CENTER, jlabel);
|
||||
panel.add(BorderLayout.SOUTH , texte );
|
||||
panel.add(BorderLayout.WEST, cb);
|
||||
|
||||
/*actions pour modifier le pseudo*/
|
||||
modifierPseudo.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JLabel Text = new JLabel("Enter your new pseudo", SwingConstants.CENTER);
|
||||
JTextField field = new JTextField(2);
|
||||
JButton cancel = new JButton("Cancel");
|
||||
cancel.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
frame.dispose();
|
||||
new FenetreMenu(agent);
|
||||
}});
|
||||
JButton ok = new JButton("Continue");
|
||||
frame.getRootPane().setDefaultButton(ok);
|
||||
ok.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String newPseudo = field.getText();
|
||||
if(agent.changerPseudo(newPseudo)) {
|
||||
JOptionPane.showMessageDialog(frame, "Your new pseudo is "+newPseudo);
|
||||
frame.dispose();
|
||||
new FenetreMenu(agent);
|
||||
}else {
|
||||
JOptionPane.showMessageDialog(frame, "Pseudo already, use choose another one");
|
||||
};
|
||||
}
|
||||
});
|
||||
JPanel panel1 = new JPanel(new GridLayout(4,1));
|
||||
panel1.add(cancel);
|
||||
panel1.add(Text);
|
||||
panel1.add(field);
|
||||
panel1.add(ok);
|
||||
frame.getContentPane().removeAll();
|
||||
frame.getContentPane().add(panel1,BorderLayout.CENTER);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
deco.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
agent.deconnexion();
|
||||
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
|
||||
} catch (IOException e1) {
|
||||
System.out.println("Deconnexion impossible");
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
//panel.add(BorderLayout.NORTH, menu);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
31
chat/src/gui/Onglet.java
Normal file
31
chat/src/gui/Onglet.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
package gui;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
public class Onglet extends javax.swing.JTabbedPane {
|
||||
private static final long serialVersionUID = 1365462L;
|
||||
|
||||
Onglet me;
|
||||
|
||||
public Onglet() {
|
||||
super();
|
||||
me = this;
|
||||
}
|
||||
|
||||
public void addTab(String title, Component component,int endroit) {
|
||||
super.addTab(title, component); //on ajoute une Tab à JTabbedPane
|
||||
super.setTabComponentAt(endroit, new CloseTabPanel(title)); //on applique le closeTabPanel a l'element "endroit"
|
||||
}
|
||||
|
||||
//fonction qui permet d'afficher le bouton close
|
||||
public void afficheIconAt(int endroit){
|
||||
((CloseTabPanel)moi.getTabComponentAt(endroit)).afficheIcon(true);
|
||||
}
|
||||
//fonction qui permet d'enlever le bouton close
|
||||
public void cacheIconAt(int endroit){
|
||||
((CloseTabPanel)moi.getTabComponentAt(endroit)).afficheIcon(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
25
chat/src/gui/Room.java
Normal file
25
chat/src/gui/Room.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
package gui;
|
||||
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
public class Room extends JTextArea{
|
||||
private String nom;
|
||||
|
||||
public Room(){
|
||||
super(25, 20);
|
||||
this.nom ="room";
|
||||
}
|
||||
public Room(String nom){
|
||||
super(25, 20);
|
||||
this.nom= nom;
|
||||
}
|
||||
|
||||
public String getNom() {
|
||||
return nom;
|
||||
}
|
||||
public void setNom(String nom) {
|
||||
this.nom = nom;
|
||||
}
|
||||
|
||||
|
||||
}
|
BIN
chat/src/gui/panda.png
Normal file
BIN
chat/src/gui/panda.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
BIN
chat/src/images/panda.png
Normal file
BIN
chat/src/images/panda.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
|
@ -8,6 +8,7 @@ public class Contact {
|
|||
private String pseudo;
|
||||
private String status;
|
||||
private int port;
|
||||
private int id;
|
||||
|
||||
private InetAddress address;
|
||||
|
||||
|
@ -50,4 +51,12 @@ public class Contact {
|
|||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public class ListeContacts {
|
|||
|
||||
private static final ListeContacts instance = new ListeContacts();
|
||||
|
||||
private ListeContacts() {
|
||||
public ListeContacts() {
|
||||
this.listeContact = new ArrayList<Contact>();
|
||||
}
|
||||
|
||||
|
@ -56,4 +56,41 @@ public class ListeContacts {
|
|||
listeContact.remove(contact);
|
||||
}
|
||||
}
|
||||
|
||||
public int length() {
|
||||
int n = 0;
|
||||
while(!listeContact.isEmpty()) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public Contact findContact(String pseudo) {
|
||||
Contact contact = null;
|
||||
for(Contact c : listeContact) {
|
||||
if(c.getPseudo().equals(pseudo)){
|
||||
c = contact;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return contact;
|
||||
}
|
||||
|
||||
|
||||
public String actifUsers() {
|
||||
String users = "";
|
||||
for(Contact c : this.listeContact) {
|
||||
users += (c.getPseudo()+"\n");
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
public ArrayList<Contact> getListe() {
|
||||
return listeContact;
|
||||
}
|
||||
|
||||
public void setListeContact(ArrayList<Contact> listeContact) {
|
||||
this.listeContact = listeContact;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
26
chat/src/model/MessageDeconnexion.java
Normal file
26
chat/src/model/MessageDeconnexion.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package model;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class MessageDeconnexion extends Message{
|
||||
private String msg;
|
||||
private String pseudo;
|
||||
|
||||
public MessageDeconnexion(InetAddress addressSrc, InetAddress addressDest, int portSrc, int portDest, int typeMessage, String pseudo) {
|
||||
super(addressSrc, addressDest, portSrc, portDest, typeMessage);
|
||||
this.pseudo = pseudo;
|
||||
this.msg = "Deconnexion";
|
||||
}
|
||||
|
||||
public String getPseudo() {
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
public void setPseudo(String pseudo) {
|
||||
this.pseudo = pseudo;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
module chat {
|
||||
requires java.desktop;
|
||||
requires java.sql;
|
||||
requires mysql.connector.java;
|
||||
}
|
|
@ -14,6 +14,7 @@ public class TCPChat extends Thread{
|
|||
|
||||
private ArrayList<MessageChat> listeMessagesRecu;
|
||||
private Socket socket;
|
||||
private int destID;
|
||||
|
||||
|
||||
//connexion faite par un autre user
|
||||
|
@ -24,9 +25,10 @@ public class TCPChat extends Thread{
|
|||
}
|
||||
|
||||
//connexion faite par le user
|
||||
public TCPChat(Contact user) throws IOException {
|
||||
this.socket = new Socket(user.getAddress(), user.getPort());
|
||||
public TCPChat(Contact destUser, int destID) throws IOException {
|
||||
this.socket = new Socket(destUser.getAddress(), destUser.getPort());
|
||||
listeMessagesRecu = new ArrayList<MessageChat>();
|
||||
this.destID = destID;
|
||||
this.start();
|
||||
}
|
||||
|
||||
|
@ -87,6 +89,14 @@ public class TCPChat extends Thread{
|
|||
public void setSocket(Socket socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
public int getDestID() {
|
||||
return destID;
|
||||
}
|
||||
|
||||
public void setDestID(int destID) {
|
||||
this.destID = destID;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package network;
|
||||
import java.net.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class Tools {
|
||||
|
||||
|
@ -13,5 +14,56 @@ public class Tools {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//Renvoie un tableau d'InetAdress le premier élement est l'adresse locale de la machine le deuxieme l'adresse de broadcast
|
||||
public static InetAddress[] getAdress() {
|
||||
Enumeration<NetworkInterface> interfaces = null;
|
||||
InetAddress localAdress = null;
|
||||
InetAddress broadcastAddress = null;
|
||||
InetAddress[] tab = {null,null};
|
||||
try {
|
||||
interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (interfaces.hasMoreElements())
|
||||
{
|
||||
NetworkInterface networkInterface = interfaces.nextElement();
|
||||
if (networkInterface.getName().equals("wlan3")){
|
||||
localAdress = networkInterface.getInterfaceAddresses().get(0).getAddress();
|
||||
tab[0] = localAdress;
|
||||
broadcastAddress = networkInterface.getInterfaceAddresses().get(0).getBroadcast();
|
||||
tab[1] = broadcastAddress;
|
||||
System.out.println("Found adress : " + localAdress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return tab;
|
||||
}
|
||||
|
||||
public static void printInterfaces() {
|
||||
Enumeration<NetworkInterface> interfaces = null;
|
||||
try {
|
||||
interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (interfaces.hasMoreElements())
|
||||
{
|
||||
NetworkInterface networkInterface = interfaces.nextElement();
|
||||
try {
|
||||
InetAddress adr = networkInterface.getInterfaceAddresses().get(0).getAddress();
|
||||
if(adr!=null) {
|
||||
System.out.println(networkInterface.getName() + adr );
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@ public class UDPInput extends Thread{
|
|||
this.messageReceived = new ArrayList<MessagePseudo>();
|
||||
}
|
||||
|
||||
public ArrayList<MessagePseudo> getListMessage (){
|
||||
return this.messageReceived;
|
||||
}
|
||||
|
||||
public MessagePseudo getMessage() {
|
||||
return this.messageReceived.remove(0);
|
||||
|
|
|
@ -30,9 +30,21 @@ public class UDPOutput {
|
|||
objectOutStream.close();
|
||||
buffer = byteOutStream.toByteArray();
|
||||
DatagramPacket packet = new DatagramPacket(buffer,buffer.length,msg.getAddressDest(),msg.getPortDest());
|
||||
this.socket.send(packet);
|
||||
this.socket.send(packet);
|
||||
System.out.println("Message envoyé, pseudo = "+msg.getPseudo()+" et num port destination = "+portSrc+"\n");
|
||||
}
|
||||
|
||||
public void send(MessageDeconnexion msg, InetAddress addressDest, int portSrc) throws IOException {
|
||||
byte[] buffer = "".getBytes();
|
||||
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
|
||||
ObjectOutputStream objectOutStream = new ObjectOutputStream(byteOutStream);
|
||||
objectOutStream.writeObject(msg);
|
||||
objectOutStream.close();
|
||||
buffer = byteOutStream.toByteArray();
|
||||
DatagramPacket packet = new DatagramPacket(buffer,buffer.length,msg.getAddressDest(),msg.getPortDest());
|
||||
this.socket.send(packet);
|
||||
System.out.println("Message envoyé, pseudo = "+msg.getMsg()+" et num port destination = "+portSrc+"\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue