diff --git a/src/GUI/ApplicationMain.java b/src/GUI/ApplicationMain.java index 6c35fece617762f9bc54f63078cf3fc41c3c9dfc..9a912f67ecc72af48588caa62ae99f74759ba29c 100644 --- a/src/GUI/ApplicationMain.java +++ b/src/GUI/ApplicationMain.java @@ -36,6 +36,7 @@ public class ApplicationMain extends JPanel { content.add(paintGUI.getGlobal(), BorderLayout.WEST); content.add(chatScreen.panel2, BorderLayout.EAST); SwingUtilities.getRootPane(chatScreen.getSendButton()).setDefaultButton(chatScreen.getSendButton()); + frame.addWindowListener(new WindowAdapter() { @Override diff --git a/src/GUI/DrawingArea.java b/src/GUI/DrawingArea.java index 21069490ac09b3a85c3eb35b876440ee928f206a..a6bb2ad9ad79df1b386c4d3aef6decd14a106abb 100644 --- a/src/GUI/DrawingArea.java +++ b/src/GUI/DrawingArea.java @@ -16,9 +16,10 @@ import java.awt.geom.RectangularShape; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.io.Serializable; import java.rmi.RemoteException; -public class DrawingArea extends JPanel implements MouseMotionListener, MouseListener { +public class DrawingArea extends JPanel implements MouseMotionListener, MouseListener, Serializable { @@ -42,12 +43,14 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis private Color shapeColor;// = new Color(0, 0, 0); private Mode currentMode;// = Mode.FREEHAND; + /// Create a empty canvas /// + private BufferedImage image;// = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_ARGB); /// Drawing tool - private Graphics2D g2;// = (Graphics2D) image.getGraphics(); + private Graphics2D g2;// = (Graphics2D) image.getGraphics(); public DrawingArea(Client client) { this.client = client; @@ -64,7 +67,6 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis addMouseMotionListener(this); } - public Shape getDrawing() { return drawing; } @@ -73,6 +75,16 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis this.drawing = drawing; } + public Graphics2D getG2() { return g2; } + + + public void setG2(Graphics2D g2) { this.g2 = g2; } + + + public BufferedImage getImage() { return image; } + + public void setImage(BufferedImage image) { this.image = image; } + @Override public Dimension getPreferredSize() @@ -108,12 +120,7 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis Color borderColor = currentMode != Mode.ERASE ? shapeColor : Color.WHITE; g2.setColor(borderColor); g2.draw(drawing); - IDrawingController drawingController = client.getDrawingController(); - try { - drawingController.broadcastDrawing(client.getUserName(), drawing); - } catch (RemoteException ex) { - ex.printStackTrace(); - } + } } @@ -269,22 +276,23 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis @Override public void mouseReleased(MouseEvent e) { + IDrawingController drawingController = client.getDrawingController(); switch (currentMode) { case OVAL: case RECTANGLE: case CIRCLE: -/// Abort drawing if 2D has no width or height /// + /// Abort drawing if 2D has no width or height /// if (((RectangularShape) drawing).getWidth() == 0 || ((RectangularShape) drawing).getHeight() == 0) { break; } case FREEHAND: case LINE: -// Graphics2D g2 = (Graphics2D) image.getGraphics(); + // Graphics2D g2 = (Graphics2D) image.getGraphics(); g2.setColor(shapeColor); -/// Uncomment the line below to fill the shapes with color /// -// g2.fill(drawing); + /// Uncomment the line below to fill the shapes with color /// + // g2.fill(drawing); g2.draw(drawing); } @@ -292,9 +300,15 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setColor(shapeColor); -/// This repaint is needed if we want to fill the drawing shape with color + /// This repaint is needed if we want to fill the drawing shape with color repaint(); + try { + drawingController.broadcastDrawing(client.getUserName(), drawing, currentMode.toString(), shapeColor); + } catch (RemoteException ex) { + ex.printStackTrace(); + } + drawing = null; } @@ -310,8 +324,9 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis @Override public void mouseDragged(MouseEvent e) { - currentPoint = e.getPoint(); + IDrawingController drawingController = client.getDrawingController(); + currentPoint = e.getPoint(); int x = Math.min(startPoint.x, e.getX()); int y = Math.min(startPoint.y, e.getY()); int width = Math.abs(startPoint.x - e.getX()); @@ -365,6 +380,11 @@ public class DrawingArea extends JPanel implements MouseMotionListener, MouseLis } repaint(); + try { + drawingController.broadcastDraggingDrawing(client.getUserName(), drawing, currentMode.toString(), shapeColor); + } catch (RemoteException ex) { + ex.printStackTrace(); + } } @Override diff --git a/src/GUI/PaintGUI.java b/src/GUI/PaintGUI.java index 40a63589b23c67847eade7ad28d6ae306516d3fd..fd2a2e32da3b742db1af1aff285bddf04c241cf5 100644 --- a/src/GUI/PaintGUI.java +++ b/src/GUI/PaintGUI.java @@ -217,16 +217,16 @@ public class PaintGUI extends JPanel { - public void showGUI() { - frame = new JFrame("Shared Whiteboard System"); - JFrame.setDefaultLookAndFeelDecorated(true); - frame.setContentPane(global); - - frame.setSize(800, 600); - frame.setLocationRelativeTo( null ); - frame.setResizable(false); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setVisible(true); - } +// public void showGUI() { +// frame = new JFrame("Shared Whiteboard System"); +// JFrame.setDefaultLookAndFeelDecorated(true); +// frame.setContentPane(global); +// +// frame.setSize(800, 600); +// frame.setLocationRelativeTo( null ); +// frame.setResizable(false); +// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); +// frame.setVisible(true); +// } } \ No newline at end of file diff --git a/src/client/Client.java b/src/client/Client.java index 3edda911f8e581fa2eb7d576173e811ce6bb7abf..cd93feb311820062fe3e3922f4f6af564063425f 100644 --- a/src/client/Client.java +++ b/src/client/Client.java @@ -85,8 +85,7 @@ public class Client { Client client = new Client(args[0]); client.connect(); -// client.getChatScreen().showGUI(); -// client.getPaintGUI().showGUI(); +// client.getApplicationMain().getPaintGUI().getDrawingArea().setImage(client.drawingController.getCurrentImage()); client.getApplicationMain().createAndShowGUI(); } catch (Exception e) diff --git a/src/client/DrawingUpdate.java b/src/client/DrawingUpdate.java index 4b41c0285681b1674f9b35cc61336ca6d4451426..7dbee07e4b97c93d89f59196245e1e8254664c02 100644 --- a/src/client/DrawingUpdate.java +++ b/src/client/DrawingUpdate.java @@ -4,6 +4,10 @@ import GUI.DrawingArea; import remote.IDrawingUpdate; import java.awt.*; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RectangularShape; import java.io.Serializable; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; @@ -18,12 +22,45 @@ public class DrawingUpdate extends UnicastRemoteObject implements IDrawingUpdate } @Override - public boolean notifyDrawing(String fromClient, Shape drawing) throws RemoteException { - client.getApplicationMain().getPaintGUI().getDrawingArea().setDrawing(drawing); + public boolean notifyDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException { + Graphics2D g2 = client.getApplicationMain().getPaintGUI().getDrawingArea().getG2(); + switch (mode) { + case "OVAL": + case "RECTANGLE": + case "CIRCLE": + case "FREEHAND": + case "LINE": + g2.setColor(color); + g2.draw(drawing); + break; + default: + System.out.println("Erased"); + } + g2 = (Graphics2D) client.getApplicationMain().getPaintGUI().getDrawingArea().getImage().getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(color); client.getApplicationMain().getPaintGUI().getDrawingArea().repaint(); -// DrawingArea drawingArea = (DrawingArea) client.getChatScreen().getDrawingPanel().getComponent(1); -// drawingArea.setDrawing(drawing); -// drawingArea.repaint(); - return false; + return true; + } + + public boolean notifyDraggingDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException { + Graphics2D g2 = client.getApplicationMain().getPaintGUI().getDrawingArea().getG2(); + switch (mode) { + case "FREEHAND": + g2.setColor(color); + g2.draw(drawing); + break; + + case "ERASE": + g2.setColor(Color.WHITE); + g2.fill(drawing); + g2.draw(drawing); + break; + + default: + break; + } + client.getApplicationMain().getPaintGUI().getDrawingArea().repaint(); + return true; } } diff --git a/src/remote/IDrawingController.java b/src/remote/IDrawingController.java index 145cc49619dcab3c25de449b706221fff56ecab6..1c39d4e5cf0900d1cd15c0ed9042edc4ed08b836 100644 --- a/src/remote/IDrawingController.java +++ b/src/remote/IDrawingController.java @@ -1,6 +1,7 @@ package remote; import java.awt.*; +import java.awt.image.BufferedImage; import java.rmi.Remote; import java.rmi.RemoteException; @@ -15,7 +16,8 @@ import java.rmi.RemoteException; */ public interface IDrawingController extends Remote { - boolean broadcastDrawing(String fromClient, Shape drawing) throws RemoteException; - + boolean broadcastDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException; + boolean broadcastDraggingDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException; +// BufferedImage getCurrentImage() throws RemoteException; } diff --git a/src/remote/IDrawingUpdate.java b/src/remote/IDrawingUpdate.java index 3df14ff51b7f3bbb41069b15f36ea23627699439..fdfbd616a5f0da92156b1d480f31a9a628edb4b0 100644 --- a/src/remote/IDrawingUpdate.java +++ b/src/remote/IDrawingUpdate.java @@ -6,5 +6,6 @@ import java.rmi.Remote; import java.rmi.RemoteException; public interface IDrawingUpdate extends Remote, Serializable { - boolean notifyDrawing(String fromClient, Shape drawing) throws RemoteException; + boolean notifyDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException; + boolean notifyDraggingDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException; } diff --git a/src/server/ChatController.java b/src/server/ChatController.java index 8fbff1e4457c8c633893caad33f1ceeff7b6b49c..c667f7972a278d45903f71210ece4ff966c18a2f 100644 --- a/src/server/ChatController.java +++ b/src/server/ChatController.java @@ -6,14 +6,17 @@ import remote.IChatUpdate; import java.io.Serializable; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; +import java.util.ArrayList; public class ChatController extends UnicastRemoteObject implements IChatController, Serializable { private Server server; + private ArrayList<String> messages; public ChatController(Server server) throws RemoteException { this.server = server; + this.messages = new ArrayList<>(); } @Override diff --git a/src/server/DrawingController.java b/src/server/DrawingController.java index 1471e8a38a33c3fc1d496f36ffa306ad0f0a1888..2fb582de348d07447d99c25f52fd8821907836c6 100644 --- a/src/server/DrawingController.java +++ b/src/server/DrawingController.java @@ -3,32 +3,108 @@ package server; import remote.IDrawingController; import remote.IDrawingUpdate; +import javax.imageio.ImageIO; import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; +import java.util.ArrayList; public class DrawingController extends UnicastRemoteObject implements IDrawingController { + private final static int AREA_WIDTH = 600; + private final static int AREA_HEIGHT = 620; + private Server server; + private BufferedImage bufferedImage; +// private ImageCanvas image; + private Graphics2D g2; protected DrawingController(Server server) throws RemoteException { this.server = server; + this.bufferedImage = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_ARGB); + g2 = (Graphics2D) bufferedImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } @Override - public boolean broadcastDrawing(String fromClient, Shape drawing) throws RemoteException { + public boolean broadcastDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException { System.out.print("Broadcasting drawing to everyone..."); + // 1. Draw on server + g2.setColor(color); + g2.draw(drawing); + g2 = (Graphics2D) bufferedImage.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(color); + g2.drawImage(bufferedImage, 0,0, null); + + // 2. Broadcast to other clients IDrawingUpdate client; for( User u : server.users ) { - client = u.getIDrawingUpdate(); - client.notifyDrawing(fromClient, drawing); + if (!u.getUserName().equals(fromClient)) { + client = u.getIDrawingUpdate(); + client.notifyDrawing(fromClient, drawing, mode, color); + } } System.out.print("...DONE\n"); return true; } + + public boolean broadcastDraggingDrawing(String fromClient, Shape drawing, String mode, Color color) throws RemoteException { + System.out.print("Broadcasting dragging drawing to everyone..."); + + // 1. Draw on server +// g2.setColor(color); +// g2.draw(drawing); + + // 2. Broadcast to other clients + IDrawingUpdate client; + + for( User u : server.users ) + { + if (!u.getUserName().equals(fromClient)) { + client = u.getIDrawingUpdate(); + client.notifyDraggingDrawing(fromClient, drawing, mode, color); + } + } + + System.out.print("...DONE\n"); + + return true; + } + +// public ImageCanvas getCurrentImage() { +// return image; +// } +} + +class ImageCanvas implements Serializable { + transient ArrayList<BufferedImage> images; + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeInt(images.size()); // how many images are serialized? + for (BufferedImage eachImage : images) { + ImageIO.write(eachImage, "png", out); // png is lossless + } + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + final int imageCount = in.readInt(); + images = new ArrayList<BufferedImage>(imageCount); + for (int i=0; i<imageCount; i++) { + images.add(ImageIO.read(in)); + } + } } \ No newline at end of file