No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChatWindowController.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. package app.insa.clav.UIControllers;
  2. import app.insa.clav.Core.DataBaseAccess;
  3. import app.insa.clav.Core.Model;
  4. import app.insa.clav.Core.Utilisateurs;
  5. import app.insa.clav.Messages.MessageChatTxt;
  6. import app.insa.clav.Messages.MessageDisplay;
  7. import app.insa.clav.Messages.MessageDisplayFile;
  8. import app.insa.clav.Reseau.TCPChatConnection;
  9. import com.jfoenix.controls.JFXButton;
  10. import javafx.application.Platform;
  11. import javafx.collections.FXCollections;
  12. import javafx.collections.ObservableList;
  13. import javafx.event.ActionEvent;
  14. import javafx.event.Event;
  15. import javafx.event.EventHandler;
  16. import javafx.fxml.FXML;
  17. import javafx.fxml.Initializable;
  18. import javafx.geometry.Insets;
  19. import javafx.geometry.Pos;
  20. import javafx.scene.control.*;
  21. import javafx.scene.control.Label;
  22. import javafx.scene.control.MenuItem;
  23. import javafx.scene.control.TextField;
  24. import javafx.scene.image.Image;
  25. import javafx.scene.image.ImageView;
  26. import javafx.scene.input.KeyCode;
  27. import javafx.scene.input.KeyEvent;
  28. import javafx.scene.layout.*;
  29. import javafx.scene.paint.Color;
  30. import javafx.scene.paint.Paint;
  31. import javafx.scene.text.TextAlignment;
  32. import javafx.stage.FileChooser;
  33. import javafx.stage.Stage;
  34. import javafx.stage.WindowEvent;
  35. import org.apache.commons.io.FilenameUtils;
  36. import javax.swing.*;
  37. import java.awt.*;
  38. import java.beans.PropertyChangeEvent;
  39. import java.beans.PropertyChangeListener;
  40. import java.io.File;
  41. import java.io.IOException;
  42. import java.net.MalformedURLException;
  43. import java.net.URL;
  44. import java.nio.file.Files;
  45. import java.nio.file.Path;
  46. import java.nio.file.StandardCopyOption;
  47. import java.text.SimpleDateFormat;
  48. import java.util.ArrayList;
  49. import java.util.Date;
  50. import java.util.ResourceBundle;
  51. public class ChatWindowController implements Initializable, PropertyChangeListener {
  52. @FXML
  53. private AnchorPane rootAnchor;
  54. private Model model;
  55. private TCPChatConnection tcpCo;
  56. private Utilisateurs remoteUser;
  57. @FXML
  58. private ListView<MessageDisplay> messageList;
  59. @FXML
  60. private ContextMenu contextMenu;
  61. @FXML
  62. private MenuItem dateMsg;
  63. @FXML
  64. private TextField messageInput;
  65. @FXML
  66. private JFXButton sendButton;
  67. @FXML
  68. private JFXButton pickFileButton;
  69. @FXML
  70. private JFXButton removeFileButton;
  71. @FXML
  72. private Label labelFile;
  73. private ObservableList<MessageDisplay> listMessages;
  74. private DataBaseAccess dbAccess;
  75. private int localUserId;
  76. private Image imageSource;
  77. private Image imageRemote;
  78. private File filePicked;
  79. private FileChooser fileChooser;
  80. public ChatWindowController(){
  81. this.model = Model.getInstance();
  82. model.addPropertyChangeListener(this,"newUserConnected");
  83. this.filePicked = null;
  84. }
  85. @Override
  86. public void initialize(URL location, ResourceBundle resources) {
  87. this.localUserId = model.user.getId();
  88. this.imageSource = new Image(getClass().getResourceAsStream("/logos/pinkDot.png"));
  89. this.imageRemote = new Image(getClass().getResourceAsStream("/logos/blueDot.png"));
  90. messageList.setCellFactory(param -> new ListCell<MessageDisplay>(){
  91. @Override
  92. protected void updateItem(MessageDisplay item, boolean empty) {
  93. super.updateItem(item, empty);
  94. if (empty || item==null) {
  95. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.TRANSPARENT.toString()),null,null)));
  96. setGraphic(null);
  97. setText(null);
  98. setPadding(new Insets(0,0,0,0));
  99. }else{
  100. if (item.getType() == 1) {
  101. if (item.getSourceId() == remoteUser.getId()) {
  102. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.AZURE.toString()), null, null)));
  103. ImageView img = new ImageView();
  104. img.setImage(imageRemote);
  105. setGraphic(img);
  106. setContentDisplay(ContentDisplay.RIGHT);
  107. setAlignment(Pos.CENTER_RIGHT);
  108. setTextAlignment(TextAlignment.RIGHT);
  109. setPadding(new Insets(10, 0, 10, param.getWidth() * 0.3));
  110. } else {
  111. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.CORNSILK.toString()), null, null)));
  112. ImageView img = new ImageView();
  113. img.setImage(imageSource);
  114. setGraphic(img);
  115. setContentDisplay(ContentDisplay.LEFT);
  116. setAlignment(Pos.CENTER_LEFT);
  117. setTextAlignment(TextAlignment.LEFT);
  118. setPadding(new Insets(10, param.getWidth() * 0.3, 10, 0));
  119. }
  120. setGraphicTextGap(5.0);
  121. setBorder(new Border(new BorderStroke(Paint.valueOf(Color.LIGHTGRAY.toString()), BorderStrokeStyle.DASHED, new CornerRadii(40.0), BorderStroke.THIN)));
  122. setMaxWidth(param.getPrefWidth() * 0.9);
  123. setPrefWidth(param.getPrefWidth() * 0.9);
  124. // allow wrapping
  125. setWrapText(true);
  126. setText(item.getPayload());
  127. }
  128. else if (item.getType() == 2){
  129. setText(null);
  130. Hyperlink hyperlink = new Hyperlink();
  131. MessageDisplayFile msgFile = (MessageDisplayFile) item;
  132. hyperlink.setText(msgFile.getPayload());
  133. hyperlink.setOnAction(new EventHandler<ActionEvent>() {
  134. @Override
  135. public void handle(ActionEvent e) {
  136. if (msgFile.getDBId() == -1){
  137. fileChooser = new FileChooser();
  138. fileChooser.setInitialFileName(msgFile.getPayload());
  139. File savedFile = fileChooser.showSaveDialog(rootAnchor.getScene().getWindow());
  140. Path original = Path.of(msgFile.getFile().toURI());
  141. Path dest = Path.of(savedFile.toURI());
  142. try {
  143. Files.copy(original,dest, StandardCopyOption.REPLACE_EXISTING);
  144. } catch (IOException ioException) {
  145. ioException.printStackTrace();
  146. }
  147. }
  148. else {
  149. fileChooser = new FileChooser();
  150. fileChooser.setInitialFileName(msgFile.getPayload());
  151. File savedFile = fileChooser.showSaveDialog(rootAnchor.getScene().getWindow());
  152. dbAccess.getFile(msgFile.getDBId(), savedFile, localUserId, remoteUser.getId());
  153. }
  154. }
  155. });
  156. HBox hbox = new HBox();
  157. hbox.setSpacing(2.0);
  158. if (item.getSourceId() == remoteUser.getId()) {
  159. hbox.setAlignment(Pos.CENTER_RIGHT);
  160. hbox.setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.TRANSPARENT.toString()), null, null)));
  161. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.AZURE.toString()), null, null)));
  162. ImageView img = new ImageView();
  163. img.setImage(imageRemote);
  164. hbox.getChildren().addAll(hyperlink, img);
  165. setGraphic(hbox);
  166. setContentDisplay(ContentDisplay.RIGHT);
  167. setAlignment(Pos.CENTER_RIGHT);
  168. setTextAlignment(TextAlignment.RIGHT);
  169. setPadding(new Insets(10, 0, 10, param.getWidth() * 0.3));
  170. } else {
  171. hbox.setAlignment(Pos.CENTER_LEFT);
  172. hbox.setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.TRANSPARENT.toString()), null, null)));
  173. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.CORNSILK.toString()), null, null)));
  174. ImageView img = new ImageView();
  175. img.setImage(imageSource);
  176. hbox.getChildren().addAll(img, hyperlink);
  177. setGraphic(hbox);
  178. setContentDisplay(ContentDisplay.LEFT);
  179. setAlignment(Pos.CENTER_LEFT);
  180. setTextAlignment(TextAlignment.LEFT);
  181. setPadding(new Insets(10, param.getWidth() * 0.3, 10, 0));
  182. }
  183. } else if (item.getType() == 3){
  184. setText(null);
  185. MessageDisplayFile msgFile = (MessageDisplayFile) item;
  186. Hyperlink hyperlink = new Hyperlink();
  187. hyperlink.setText(msgFile.getPayload());
  188. hyperlink.setOnAction(new EventHandler<ActionEvent>() {
  189. @Override
  190. public void handle(ActionEvent e) {
  191. fileChooser = new FileChooser();
  192. fileChooser.setInitialFileName(msgFile.getPayload());
  193. File savedFile = fileChooser.showSaveDialog(rootAnchor.getScene().getWindow());
  194. Path original = Path.of(msgFile.getFile().toURI());
  195. Path dest = Path.of(savedFile.toURI());
  196. try {
  197. Files.copy(original,dest, StandardCopyOption.REPLACE_EXISTING);
  198. } catch (IOException ioException) {
  199. ioException.printStackTrace();
  200. }
  201. }
  202. });
  203. Image imageFileSource = null;
  204. try {
  205. imageFileSource = new Image(msgFile.getFile().toURI().toURL().toExternalForm());
  206. } catch (MalformedURLException e) {
  207. e.printStackTrace();
  208. }
  209. ImageView imageFileView = new ImageView();
  210. imageFileView.setImage(imageFileSource);
  211. HBox hbox = new HBox();
  212. hbox.setSpacing(2.0);
  213. hbox.setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.TRANSPARENT.toString()), null, null)));
  214. VBox vbox = new VBox();
  215. vbox.setSpacing(5.0);
  216. vbox.setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.TRANSPARENT.toString()), null, null)));
  217. imageFileView.setPreserveRatio(true);
  218. imageFileView.fitWidthProperty().bind(messageList.widthProperty().multiply(0.5));
  219. imageFileView.fitHeightProperty().bind(hbox.heightProperty());
  220. vbox.setAlignment(Pos.TOP_CENTER);
  221. vbox.getChildren().addAll(imageFileView,hyperlink);
  222. vbox.setPrefWidth(messageList.getWidth() * 0.5);
  223. if (item.getSourceId() == remoteUser.getId()) {
  224. hbox.setAlignment(Pos.CENTER_RIGHT);setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.AZURE.toString()), null, null)));
  225. ImageView img = new ImageView();
  226. img.setImage(imageRemote);
  227. hbox.getChildren().addAll(vbox, img);
  228. setGraphic(hbox);
  229. setContentDisplay(ContentDisplay.RIGHT);
  230. setAlignment(Pos.CENTER_RIGHT);
  231. setTextAlignment(TextAlignment.RIGHT);
  232. setPadding(new Insets(10, 0, 10, param.getWidth() * 0.3));
  233. } else {
  234. hbox.setAlignment(Pos.CENTER_LEFT);
  235. setBackground(new Background(new BackgroundFill(Paint.valueOf(Color.CORNSILK.toString()), null, null)));
  236. ImageView img = new ImageView();
  237. img.setImage(imageSource);
  238. hbox.getChildren().addAll(img, vbox);
  239. setGraphic(hbox);
  240. setContentDisplay(ContentDisplay.LEFT);
  241. setAlignment(Pos.CENTER_LEFT);
  242. setTextAlignment(TextAlignment.LEFT);
  243. setPadding(new Insets(10, param.getWidth() * 0.3, 10, 0));
  244. }
  245. }
  246. }
  247. }
  248. });
  249. }
  250. /**
  251. * Returns the message history and puts it in the ListView
  252. */
  253. private void getHistory(){
  254. this.dbAccess = DataBaseAccess.getInstance();
  255. if (remoteUser == null) {
  256. System.out.println("\n\n\nATTTENNNNTIIONNN\n \n\n");
  257. }
  258. ArrayList<MessageDisplay> history = this.dbAccess.getMessageHistory(this.localUserId,remoteUser.getId());
  259. this.listMessages = FXCollections.observableList(history);
  260. this.messageList.setItems(this.listMessages);
  261. Platform.runLater(new Runnable() {
  262. @Override
  263. public void run() {
  264. int size = messageList.getItems().size();
  265. messageList.scrollTo(size - 1);
  266. Stage chatStage = (Stage) rootAnchor.getScene().getWindow();
  267. chatStage.setTitle("Chat room with " + remoteUser.getPseudo());
  268. }
  269. });
  270. }
  271. /** Sets the TcpCo attribute and adds propertyChangeListener for the TCPChatConnection
  272. * @param tcpCo
  273. */
  274. public void setTCPCo(TCPChatConnection tcpCo){
  275. this.tcpCo = tcpCo;
  276. tcpCo.addPropertyChangeListener(this);
  277. int remoteUserId = tcpCo.remoteUserId;
  278. this.remoteUser = model.getUserFromId(remoteUserId);
  279. this.getHistory();
  280. }
  281. @Override
  282. public void propertyChange(PropertyChangeEvent evt) {
  283. switch(evt.getPropertyName()){
  284. case "messageTextReceivedTCP" :
  285. MessageChatTxt msg = (MessageChatTxt) tcpCo.getMessageReceived();
  286. MessageDisplay msgDisp = new MessageDisplay(remoteUser.getId(), msg.date, msg.payload,1);
  287. Platform.runLater(new Runnable() {
  288. @Override
  289. public void run() {
  290. listMessages.add(msgDisp);
  291. int size = messageList.getItems().size();
  292. messageList.scrollTo(size - 1);
  293. }
  294. });
  295. break;
  296. case "connectionChatClosed":
  297. case "userDisconnected" :
  298. model.notifyCloseChat(tcpCo);
  299. Stage mainStage = (Stage) rootAnchor.getScene().getWindow();
  300. Platform.runLater(mainStage::close);
  301. break;
  302. case "newUserConnected" :
  303. if ((int) evt.getNewValue() == remoteUser.getId()) {
  304. this.remoteUser = model.getUserFromId(remoteUser.getId());
  305. Platform.runLater(new Runnable() {
  306. @Override
  307. public void run() {
  308. Stage chatStage = (Stage) rootAnchor.getScene().getWindow();
  309. chatStage.setTitle("Chat room with " + remoteUser.getPseudo());
  310. }
  311. });
  312. }
  313. break;
  314. case "fileReceived" :
  315. MessageDisplayFile msgFile = tcpCo.getMessageFileReceived();
  316. Platform.runLater(new Runnable() {
  317. @Override
  318. public void run() {
  319. listMessages.add(msgFile);
  320. int size = messageList.getItems().size();
  321. messageList.scrollTo(size - 1);
  322. }
  323. });
  324. }
  325. }
  326. /** Handler to send message
  327. * @param actionEvent
  328. */
  329. public void buttonSendMessageClicked(ActionEvent actionEvent) {
  330. this.sendButton.setDisable(true);
  331. String timeStamp = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss").format(new Date());
  332. String payload = this.messageInput.getText();
  333. if (!payload.equals("")) {
  334. MessageDisplay msg = new MessageDisplay(model.user.getId(),timeStamp,payload,1);
  335. this.listMessages.add(msg);
  336. this.messageInput.clear();
  337. this.tcpCo.sendMessageTxt(msg);
  338. this.dbAccess.addMessage(this.localUserId,this.remoteUser.getId(),msg);
  339. }
  340. //We send the File if the filed is not null
  341. if (this.filePicked != null){
  342. String ext = FilenameUtils.getExtension(this.filePicked.getPath());
  343. int type = 2;
  344. switch (ext) {
  345. case "png":
  346. case "gif":
  347. case "jpeg":
  348. case "svg":
  349. case "jpg":
  350. type = 3;
  351. break;
  352. }
  353. MessageDisplayFile msgFile = new MessageDisplayFile(model.user.getId(),timeStamp,this.filePicked.getName(),type,this.filePicked, ext, -1);
  354. this.listMessages.add(msgFile);
  355. this.tcpCo.sendMessageFile(msgFile);
  356. this.dbAccess.addMessage(this.localUserId,this.remoteUser.getId(),msgFile);
  357. this.filePicked = null;
  358. this.labelFile.setVisible(false);
  359. }
  360. this.sendButton.setDisable(false);
  361. int size = messageList.getItems().size();
  362. messageList.scrollTo(size - 1);
  363. }
  364. /**
  365. * Sets handler chen Window closed
  366. */
  367. public void setHandler() {
  368. Stage mainStage = (Stage) rootAnchor.getScene().getWindow();
  369. mainStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
  370. @Override
  371. public void handle(WindowEvent t) {
  372. tcpCo.sendCloseChat();
  373. model.notifyCloseChat(tcpCo);
  374. Platform.runLater(mainStage::close);
  375. }
  376. });
  377. mainStage.getScene().setOnKeyPressed(e -> {
  378. if (e.getCode() == KeyCode.ENTER) {
  379. System.out.println("Fire");
  380. this.sendButton.fire();
  381. }
  382. });
  383. }
  384. @FXML
  385. void showDate() {
  386. String dateMsg = messageList.getFocusModel().getFocusedItem().getDate();
  387. this.dateMsg.setText(dateMsg);
  388. }
  389. @FXML
  390. void pickFile(ActionEvent event) {
  391. File previousFile = this.filePicked;
  392. this.fileChooser = new FileChooser();
  393. this.filePicked = this.fileChooser.showOpenDialog(this.rootAnchor.getScene().getWindow());
  394. if (this.filePicked != null){
  395. if (filePicked.length() / (1024*1024) > 5){
  396. this.labelFile.setText("File too large, limit is 5Mb");
  397. this.labelFile.setVisible(true);
  398. this.filePicked = null;
  399. }
  400. else {
  401. this.labelFile.setText("File : " + this.filePicked.getName());
  402. this.labelFile.setVisible(true);
  403. }
  404. }
  405. else{
  406. this.filePicked = previousFile;
  407. }
  408. this.sendButton.requestFocus();
  409. }
  410. @FXML
  411. void removeFile(ActionEvent event) {
  412. this.labelFile.setVisible(false);
  413. this.filePicked = null;
  414. this.sendButton.requestFocus();
  415. }
  416. }