commit 3a4b3b4f074cf88e9cdf5fc3af3b05b3fc8bec3f Author: moreris Date: Tue Jan 8 11:28:41 2019 +0100 full final grafikchat, bääm, geht voll ab xD diff --git a/src/grafikchat/Start.java b/src/grafikchat/Start.java new file mode 100644 index 0000000..81080b9 --- /dev/null +++ b/src/grafikchat/Start.java @@ -0,0 +1,44 @@ +package grafikchat; + +import grafikchat.controller.ConnectController; +import grafikchat.controller.GrafikController; +import grafikchat.controller.ReceiveAdapter; +import grafikchat.model.ChatModel; +import grafikchat.view.ChatView; + +/** + * Start class, start chat application + * + * @author marian + */ +public class Start { + + public Start() + { + ChatView view = new ChatView(); + ChatModel model = new ChatModel(); + + view.getGvDrawPane().setModel(model); + + ConnectController controllerConnect = new ConnectController(model, view); + controllerConnect.registerEvents(); + + GrafikController controller = new GrafikController(view, model); + controller.registerEvents(); + + ReceiveAdapter rxAdapter = new ReceiveAdapter(view); + model.addObserver(rxAdapter); + + view.setTitle("Chat"); + view.setVisible(true); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) + { + Start start = new Start(); + } + +} diff --git a/src/grafikchat/controller/ConnectController.java b/src/grafikchat/controller/ConnectController.java new file mode 100644 index 0000000..9055175 --- /dev/null +++ b/src/grafikchat/controller/ConnectController.java @@ -0,0 +1,113 @@ +package grafikchat.controller; + +import grafikchat.model.ChatModel; +import grafikchat.ohmlogger.OhmLogger; +import grafikchat.view.ChatView; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.logging.Logger; +import javax.swing.JOptionPane; + +/** + * Handle events emitted from connect button + * + * @author marian + */ +public class ConnectController implements ActionListener +{ + private ChatModel model; + private ChatView view; + private static Logger logger = OhmLogger.getLogger(); + + /** + * Constructor, initialize variables + * @param model ChatModel + * @param view ChatView + */ + public ConnectController(ChatModel model, ChatView view) + { + this.model = model; + this.view = view; + } + + /** + * Register events for connect button and radio button to select between server and client mode. + */ + public void registerEvents() + { + this.view.getBtConnect().addActionListener(this); + this.view.getRbClient().addActionListener(this); + this.view.getRbServer().addActionListener(this); + } + + /** + * Event handler to take care of registered events + * @param ae occurred event + */ + @Override + public void actionPerformed(ActionEvent ae) + { + Object object = ae.getSource(); + + if (object == view.getBtConnect()) { + int port = -1; + + try { + port = Integer.parseInt(view.getTfPort().getText()); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(view, "Port entspricht keiner Zahl!"); + logger.severe(e.toString()); + return; + } + + if (view.getRbClient().isSelected() && (validIP(view.getTfIP().getText()) == false)) { + JOptionPane.showMessageDialog(view, "Ungültige IP-Adresse!"); + logger.severe("IP-Adresse ungültig"); + return; + } + + model.connectToPeer(view.getRbServer().isSelected(), view.getTfIP().getText(), port); + + view.getRbClient().setEnabled(false); + view.getRbServer().setEnabled(false); + view.getTfIP().setEnabled(false); + view.getTfPort().setEnabled(false); + } else { + view.getTfIP().setEnabled(view.getRbClient().isSelected()); + } + } + + /** + * Primitive check if the ip is valid (only IPv4) + * @param ip IP to check + * @return true if valid, false otherwise + */ + private boolean validIP (String ip) { + try { + if ( ip == null || ip.isEmpty() ) { + return false; + } + + String[] parts = ip.split( "\\." ); + if ( parts.length != 4 ) { + return false; + } + + for ( String s : parts ) { + int i = Integer.parseInt( s ); + if ( (i < 0) || (i > 255) ) { + return false; + } + } + if ( ip.endsWith(".") ) { + return false; + } + + return true; + } catch (NumberFormatException e) { + logger.severe(e.toString()); + return false; + } + } + +} diff --git a/src/grafikchat/controller/GrafikController.java b/src/grafikchat/controller/GrafikController.java new file mode 100644 index 0000000..fa3a8c8 --- /dev/null +++ b/src/grafikchat/controller/GrafikController.java @@ -0,0 +1,230 @@ +package grafikchat.controller; + +import grafikchat.model.ChatModel; +import grafikchat.view.ChatView; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.logging.Logger; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import grafikchat.model.Figures; +import grafikchat.model.TransceiverData; +import grafikchat.model.TransceiverDataEvent; +import grafikchat.ohmlogger.OhmLogger; + +/** + * Handle events from mouse and keyboard + * + * @author marian + */ +public class GrafikController implements MouseMotionListener, MouseListener, KeyListener +{ + private final ChatView view; + private final ChatModel model; + private boolean clicked; + private final static Logger logger = OhmLogger.getLogger(); + + /** + * Constructor + * @param view UI of zeichenprogramm + * @param model Model of zeichenprogramm + */ + public GrafikController(ChatView view, ChatModel model) + { + this.view = view; + this.model = model; + + this.clicked = false; + } + + /** + * Register events for mouse and keyboard + */ + public void registerEvents() + { + view.getGvDrawPane().addMouseMotionListener(this); + view.getGvDrawPane().addMouseListener(this); + view.getGvDrawPane().addKeyListener(this); + view.getGvDrawPane().setFocusable(true); + + view.addKeyListener(this); + view.setFocusable(true); + } + + @Override + public void mouseDragged(MouseEvent evt) + { + if (clicked) { + Point p = evt.getPoint(); + model.getIntern().addPoint(p); + model.sendMessage(new TransceiverData(TransceiverDataEvent.NEWPOINT, p)); + view.getGvDrawPane().drawPoint(true); + } + } + + @Override + public void mouseMoved(MouseEvent e) {} + + @Override + public void mouseClicked(MouseEvent e) {} + + @Override + public void mousePressed(MouseEvent e) + { + if (e.getButton() == MouseEvent.BUTTON1) { + logger.info("Mouse pressed"); + model.getIntern().newFigure(); + model.sendMessage(new TransceiverData(TransceiverDataEvent.NEWFIGURE, null)); + this.clicked = true; + } + } + + @Override + public void mouseReleased(MouseEvent e) + { + if (e.getButton() == MouseEvent.BUTTON1) { + logger.info("Mouse released"); + this.clicked = false; + } + } + + @Override + public void mouseEntered(MouseEvent e) {} + + @Override + public void mouseExited(MouseEvent e) {} + + /** + * Save current graphics to file + * @return True if successful, false otherwise + */ + public boolean saveToFile() + { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(model.getFilename())); + int returnVal = fc.showSaveDialog(view); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File f = fc.getSelectedFile(); + if(!f.exists()) { + try { + f.createNewFile(); + } catch (IOException e) { + JOptionPane.showMessageDialog(view, "Datei konnte nicht erstellt werden.", "Warnung", JOptionPane.WARNING_MESSAGE); + return false; + } + } + } else { + JOptionPane.showMessageDialog(view, "Es wurde keine Datei zum speichern ausgewählt.", "Warnung", JOptionPane.WARNING_MESSAGE); + return false; + } + model.setFilename(fc.getSelectedFile().getPath()); + + + try { + FileOutputStream fos = new FileOutputStream(model.getFilename()); + try (ObjectOutputStream oos = new ObjectOutputStream(fos)) { + ArrayList list = new ArrayList<>(); + list.add(model.getIntern()); + list.add(model.getExtern()); + oos.writeObject(list); + } + } catch (IOException e) { + JOptionPane.showMessageDialog(view, "Grafik konnte nicht gespeichert werden.", "Warning", JOptionPane.WARNING_MESSAGE); + } + + JOptionPane.showMessageDialog(view, "Grafik erfolgreich gespeichert.", "Information", JOptionPane.INFORMATION_MESSAGE); + + return true; + } + + /** + * Read graphics from file + * @return True if successful, false otherwise + */ + public boolean readFromFile() + { + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(model.getFilename())); + int returnVal = fc.showOpenDialog(view); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File f = fc.getSelectedFile(); + if(!f.exists()) { + try { + f.createNewFile(); + } catch (IOException e) { + JOptionPane.showMessageDialog(view, "Datei konnte nicht erstellt werden.", "Warnung", JOptionPane.WARNING_MESSAGE); + return false; + } + } + + String filepath = f.getPath(); + ArrayList d; + FileInputStream is; + + try { + is = new FileInputStream(filepath); + } catch (IOException e) { + JOptionPane.showMessageDialog(view, "Datei wurde nicht gefunden.", "Warnung", JOptionPane.WARNING_MESSAGE); + return false; + } + + try { + ObjectInputStream ois = new ObjectInputStream(is); + d = (ArrayList)ois.readObject(); + model.getIntern().setFigures(d.get(0).getFigures()); + model.getExtern().setFigures(d.get(1).getFigures()); + view.repaint(); + model.sendMessage(new TransceiverData(TransceiverDataEvent.REPAINT, d)); + } catch (ClassNotFoundException | IOException e) { + JOptionPane.showMessageDialog(view, "Leeres Adressbuch geöffnet.", "Warnung", JOptionPane.INFORMATION_MESSAGE); + } + + model.setFilename(filepath); + } + + return true; + } + + @Override + public void keyTyped(KeyEvent ke) + { + } + + @Override + public void keyPressed(KeyEvent ke) + { + } + + @Override + public void keyReleased(KeyEvent ke) + { + char c = ke.getKeyChar(); + switch (c) + { + case 's': + saveToFile(); + break; + case 'o': + readFromFile(); + break; + case 'p': + view.getGvDrawPane().doPrint(); + break; + } + } + + +} diff --git a/src/grafikchat/controller/ReceiveAdapter.java b/src/grafikchat/controller/ReceiveAdapter.java new file mode 100644 index 0000000..39ad074 --- /dev/null +++ b/src/grafikchat/controller/ReceiveAdapter.java @@ -0,0 +1,48 @@ +package grafikchat.controller; + +import grafikchat.model.ChatModel; +import grafikchat.model.TransceiverDataEvent; +import grafikchat.view.ChatView; +import java.util.Observable; +import java.util.Observer; + +/** + * Take care of received messages. Show to user in UI + * + * @author marian + */ +public class ReceiveAdapter implements Observer +{ + private ChatView view; + + /** + * Constructor, get reference to view + * @param view ChatView + */ + public ReceiveAdapter(ChatView view) + { + this.view = view; + } + + /** + * Incoming information from Observable + * @param obs Observable + * @param object Received message + */ + @Override + public void update(Observable obs, Object object) + { + TransceiverDataEvent mode = (TransceiverDataEvent)object; + + switch (mode) + { + case NEWPOINT: + view.getGvDrawPane().drawPoint(false); + break; + case REPAINT: + view.getGvDrawPane().repaint(); + break; + } + } + +} diff --git a/src/grafikchat/model/ChatModel.java b/src/grafikchat/model/ChatModel.java new file mode 100644 index 0000000..be45a30 --- /dev/null +++ b/src/grafikchat/model/ChatModel.java @@ -0,0 +1,159 @@ +package grafikchat.model; + +import grafikchat.ohmlogger.OhmLogger; +import java.awt.Point; +import java.util.ArrayList; +import java.util.Observable; +import java.util.Observer; +import java.util.logging.Logger; +import java.util.prefs.Preferences; + +/** + * Model of chat application. Handle communication + * + * @author marian + */ +public class ChatModel extends Observable implements Observer +{ + private boolean connected; + private boolean mode; + private boolean initialized; + private Transceiver trx; + private Figures intern; + private Figures extern; + + private final Preferences prefs; + private static Logger logger = OhmLogger.getLogger(); + + /** + * Constructor, initialize variables + */ + public ChatModel() + { + connected = false; + mode = false; + initialized = false; + trx = null; + + intern = new Figures(); + extern = new Figures(); + + prefs = Preferences.userNodeForPackage(this.getClass()); + } + + /** + * Get local drawn figure + * @return internal figure + */ + public Figures getIntern() + { + return intern; + } + + /** + * Get remote drawn figure + * @return extern figure + */ + public Figures getExtern() + { + return extern; + } + + /** + * Set new filename in preferences + * @param f + */ + public void setFilename(String f) + { + prefs.put("LAST_FILE", f); + } + + /** + * Get latest filename from preferences + * @return filename + */ + public String getFilename() + { + String last = prefs.get("LAST_FILE", ""); + System.out.println(last); + return last; + } + + /** + * Connect to peer + * @param mode true to use server mode, false to use client mode + * @param ip IP to connect to (not relevant in server mode) + * @param port Port to open or connect to (depending on selected mode) + */ + public void connectToPeer(boolean mode, String ip, int port) + { + if (initialized) { + logger.info("Chat already running"); + return; + } + + this.mode = mode; + + if (mode) { + logger.info("Running in server mode"); + trx = new Server(port); + } else { + logger.info("Running in client mode"); + trx = new Client(ip, port); + } + + trx.registerObserver(this); + trx.init(); + + initialized = true; + } + + /** + * Send message to peer + * @param d TransceiverData to transmit + */ + public void sendMessage(TransceiverData d) + { + if (!initialized) { + logger.warning("Chat not initialized"); + return; + } + + trx.sendMessage(d); + } + + /** + * Get received data from network + * @param obs Observable + * @param object Received object + */ + @Override + public void update(Observable obs, Object object) + { + TransceiverData d = (TransceiverData)object; + + if (object instanceof TransceiverData) { + switch (d.getEvent()) + { + case NEWFIGURE: + extern.newFigure(); + break; + case NEWPOINT: + extern.addPoint((Point)d.getObject()); + this.setChanged(); + this.notifyObservers(TransceiverDataEvent.NEWPOINT); + break; + case REPAINT: + ArrayList fig = (ArrayList)d.getObject(); + intern.setFigures(fig.get(0).getFigures()); + extern.setFigures(fig.get(1).getFigures()); + this.setChanged(); + this.notifyObservers(TransceiverDataEvent.REPAINT); + default: + logger.warning("Unknown TransceiverDataEvent"); + } + } else { + logger.warning("Received invalid object"); + } + } +} diff --git a/src/grafikchat/model/Client.java b/src/grafikchat/model/Client.java new file mode 100644 index 0000000..1a0faa4 --- /dev/null +++ b/src/grafikchat/model/Client.java @@ -0,0 +1,148 @@ +package grafikchat.model; + +import grafikchat.ohmlogger.OhmLogger; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.util.Observable; +import java.util.Observer; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * TCP Client + * + * @author marian + */ +public class Client extends Observable implements Runnable, Transceiver +{ + private Socket socket; + private ObjectInputStream reader; + private ObjectOutputStream writer; + private boolean ready; + private Thread thd; + private String ip; + private int port; + private static Logger logger = OhmLogger.getLogger(); + + /** + * Constructor, initialize variables + * @param ip IP to connect to + * @param port Port of remote server + */ + public Client(String ip, int port) + { + this.ip = ip; + this.port = port; + this.socket = null; + this.reader = null; + this.writer = null; + this.ready = false; + this.thd = null; + } + + /** + * Init client thread, if not already done + */ + @Override + public void init() + { + if (thd == null) { + thd = new Thread(this); + thd.start(); + } + } + + /** + * Add observer to client + * @param o Observer to add + */ + @Override + public void registerObserver(Observer o) + { + this.addObserver(o); + } + + /** + * Run the client in thread. + */ + @Override + public void run() + { + logger.info("Running client..."); + + while (true) + { + if (socket == null) { + try { + socket = new Socket(ip, port); + logger.info("Connected to server"); + } catch (IOException e) { + logger.severe(e.getMessage()); + socket = null; + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex); + } + continue; + } + + try { + reader = new ObjectInputStream(socket.getInputStream()); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + + try { + writer = new ObjectOutputStream(socket.getOutputStream()); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + + ready = true; + } + + if (ready) { + try { + //logger.info("Waiting for message"); + + Object o = reader.readObject(); + + if (o == null) { + logger.warning("Reached end of stream"); + ready = false; + continue; + } + + this.setChanged(); + this.notifyObservers(o); + } catch (ClassNotFoundException | IOException e) { + logger.severe(e.toString()); + return; + } + } + } + } + + /** + * Send message to server + * @param d TransceiverData to transmit + */ + @Override + public void sendMessage(TransceiverData d) + { + if (ready) { + try { + writer.writeObject(d); + } catch (IOException e) { + logger.severe(e.toString()); + } + } else { + logger.warning("Server not ready to send message. Connect first"); + } + } +} diff --git a/src/grafikchat/model/Figure.java b/src/grafikchat/model/Figure.java new file mode 100644 index 0000000..678aa4e --- /dev/null +++ b/src/grafikchat/model/Figure.java @@ -0,0 +1,43 @@ +package grafikchat.model; + +import java.awt.Point; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Figure drawn by user with mouse + * + * @author marian + */ +public class Figure implements Serializable +{ + private static final long serialVersionUID = 8582433437601788991L; + private final ArrayList points; + + /** + * Constructor, initialize figure + */ + public Figure() + { + points = new ArrayList<>(); + } + + /** + * Add point to figure + * @param p new point + */ + public void addPoint(Point p) + { + points.add(p); + } + + /** + * Get all points of figure + * @return all points + */ + public List getPoints() + { + return points; + } +} diff --git a/src/grafikchat/model/Figures.java b/src/grafikchat/model/Figures.java new file mode 100644 index 0000000..f40d94f --- /dev/null +++ b/src/grafikchat/model/Figures.java @@ -0,0 +1,107 @@ +package grafikchat.model; + +import java.awt.Point; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of a list of figures + * + * @author marian + */ +public class Figures implements Serializable +{ + private ArrayList
figureList; + private Figure lastFigure; + private Point lastPoint; + private Point secondToLastPoint; + private static final long serialVersionUID = 8582433437601788990L; + + + /** + * Constructor, initialize variables + */ + public Figures() + { + figureList = new ArrayList<>(); + lastFigure = null; + lastPoint = null; + secondToLastPoint = null; + } + + /** + * Add point to latest figure + * @param p new point to add + */ + public void addPoint(Point p) + { + lastFigure.addPoint(p); + secondToLastPoint = lastPoint; + lastPoint = p; + } + + /** + * Create new figure + */ + public void newFigure() + { + Figure f = new Figure(); + figureList.add(f); + lastFigure = f; + + lastPoint = null; + secondToLastPoint = null; + } + + /** + * Get the last two points of the latest figure + * @return last two points of latest figure + * @throws Exception if not yet available + */ + public List getLastTwoPoints() throws Exception + { + if (secondToLastPoint == null || lastPoint == null) { + throw new Exception("Not enough points available"); + } + + ArrayList p = new ArrayList<>(); + p.add(lastPoint); + p.add(secondToLastPoint); + + return p; + } + + /** + * Get latest figure + * @return latest figure + * @throws Exception if not yet available + */ + private List getFigure() throws Exception + { + if (lastFigure == null) { + throw new Exception("No figure available"); + } + + return lastFigure.getPoints(); + } + + /** + * Set new figures + * @param f + */ + public void setFigures(ArrayList
f) + { + figureList = f; + } + + /** + * Get all current figures + * @return + */ + public ArrayList
getFigures() + { + return figureList; + } + +} diff --git a/src/grafikchat/model/Server.java b/src/grafikchat/model/Server.java new file mode 100644 index 0000000..18e0876 --- /dev/null +++ b/src/grafikchat/model/Server.java @@ -0,0 +1,151 @@ +package grafikchat.model; + +import grafikchat.ohmlogger.OhmLogger; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Observable; +import java.util.Observer; +import java.util.logging.Logger; + +/** + * TCP Server + * + * @author marian + */ +public class Server extends Observable implements Runnable, Transceiver +{ + private int port; + private ServerSocket server; + private Socket client; + private static Logger logger = OhmLogger.getLogger(); + private ObjectInputStream reader; + private ObjectOutputStream writer; + private volatile boolean ready; + private Thread thd; + + /** + * Constructor, initialize variables + * @param port Port to listen on + */ + public Server(int port) + { + this.port = port; + this.server = null; + this.client = null; + this.reader = null; + this.writer = null; + this.ready = false; + this.thd = null; + } + + /** + * Init server if not already done + */ + @Override + public void init() + { + if (thd == null) { + thd = new Thread(this); + thd.start(); + } + } + + /** + * Add observer to server + * @param o Observer to add + */ + @Override + public void registerObserver(Observer o) + { + this.addObserver(o); + } + + /** + * Run server in thread + */ + @Override + public void run() + { + logger.info("Running server..."); + + while (true) + { + if (server == null) { + try { + server = new ServerSocket(port); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + + logger.info("Waiting for client to connect"); + try { + client = server.accept(); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + logger.info("Client connected"); + + try { + writer = new ObjectOutputStream(client.getOutputStream()); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + + try { + reader = new ObjectInputStream(client.getInputStream()); + } catch (IOException e) { + logger.severe(e.toString()); + return; + } + + ready = true; + + } + + if (ready) { + try { + //logger.info("Waiting for message"); + + Object o = reader.readObject(); + + if (o == null) { + logger.warning("Reached end of stream"); + ready = false; + continue; + } + + this.setChanged(); + this.notifyObservers(o); + } catch (ClassNotFoundException | IOException e) { + logger.severe(e.toString()); + return; + } + } + } + } + + /** + * Send message to client + * @param d TransceiverData to transmit + */ + @Override + public void sendMessage(TransceiverData d) + { + if (ready) { + try { + writer.writeObject(d); + } catch (IOException e) { + logger.severe(e.toString()); + } + } else { + logger.warning("Server not ready to send message. Connect first"); + } + } + +} diff --git a/src/grafikchat/model/Transceiver.java b/src/grafikchat/model/Transceiver.java new file mode 100644 index 0000000..8b952b4 --- /dev/null +++ b/src/grafikchat/model/Transceiver.java @@ -0,0 +1,28 @@ +package grafikchat.model; + +import java.util.Observer; + +/** + * Interface for server and client + * + * @author marian + */ +public interface Transceiver +{ + /** + * Initialize the transceiver + */ + public void init(); + + /** + * Send object + * @param d TransceiverData to send + */ + public void sendMessage(TransceiverData d); + + /** + * Register on transceiver + * @param o Object to register + */ + public void registerObserver(Observer o); +} diff --git a/src/grafikchat/model/TransceiverData.java b/src/grafikchat/model/TransceiverData.java new file mode 100644 index 0000000..4de91a9 --- /dev/null +++ b/src/grafikchat/model/TransceiverData.java @@ -0,0 +1,31 @@ +package grafikchat.model; + +import java.io.Serializable; + +/** + * DataPoint for communication between two sockets + * + * @author marian + */ +public class TransceiverData implements Serializable +{ + private final TransceiverDataEvent e; + private final Object o; + private static final long serialVersionUID = 8582433437601788989L; + + public TransceiverData(TransceiverDataEvent e, Object o) + { + this.e = e; + this.o = o; + } + + public TransceiverDataEvent getEvent() + { + return this.e; + } + + public Object getObject() + { + return this.o; + } +} \ No newline at end of file diff --git a/src/grafikchat/model/TransceiverDataEvent.java b/src/grafikchat/model/TransceiverDataEvent.java new file mode 100644 index 0000000..1107c14 --- /dev/null +++ b/src/grafikchat/model/TransceiverDataEvent.java @@ -0,0 +1,10 @@ +package grafikchat.model; + + + +public enum TransceiverDataEvent +{ + NEWPOINT, + NEWFIGURE, + REPAINT; +} diff --git a/src/grafikchat/ohmlogger/OhmFormatter.java b/src/grafikchat/ohmlogger/OhmFormatter.java new file mode 100644 index 0000000..b0dd876 --- /dev/null +++ b/src/grafikchat/ohmlogger/OhmFormatter.java @@ -0,0 +1,34 @@ +package grafikchat.ohmlogger; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.*; + +/** + * Formatter with custom format + * + * @author marian + */ +class OhmFormatter extends SimpleFormatter { + + private static final DateFormat df = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss.SSS"); + + /** + * Format message to specified format + * @param record Tecord to format + * @return Formatted string + */ + @Override + public String format(LogRecord record) { + StringBuilder builder; + builder = new StringBuilder(1000); + builder.append(df.format(new Date(record.getMillis()))).append(" | "); + builder.append(record.getLevel()).append(" | "); + builder.append(record.getSourceClassName()).append(" | "); + builder.append(record.getSourceMethodName()).append(" | "); + builder.append(formatMessage(record)).append(" |"); + builder.append("\n"); + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/grafikchat/ohmlogger/OhmLogger.java b/src/grafikchat/ohmlogger/OhmLogger.java new file mode 100644 index 0000000..336cfc9 --- /dev/null +++ b/src/grafikchat/ohmlogger/OhmLogger.java @@ -0,0 +1,44 @@ +package grafikchat.ohmlogger; + +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Logger with custom format + * + * @author marian + */ +public class OhmLogger +{ + private static Logger lg; + + /** + * Get logger object + * + * @return logger object + */ + public static Logger getLogger() + { + if (lg == null) { + lg = Logger.getLogger("OhmLogger"); + initLogger(); + } + + return lg; + } + + /** + * Initialize new logger and set custom formatter + */ + private static void initLogger() + { + ConsoleHandler ch = new ConsoleHandler(); + + ch.setFormatter(new OhmFormatter()); + lg.addHandler(ch); + lg.setUseParentHandlers(false); + lg.setLevel(Level.ALL); + } + +} diff --git a/src/grafikchat/view/ChatView.form b/src/grafikchat/view/ChatView.form new file mode 100644 index 0000000..c648195 --- /dev/null +++ b/src/grafikchat/view/ChatView.form @@ -0,0 +1,138 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/grafikchat/view/ChatView.java b/src/grafikchat/view/ChatView.java new file mode 100644 index 0000000..a5ea4c3 --- /dev/null +++ b/src/grafikchat/view/ChatView.java @@ -0,0 +1,218 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package grafikchat.view; + +/** + * + * @author marian + */ +public class ChatView extends javax.swing.JFrame { + + /** + * @return the rbClient + */ + public javax.swing.JRadioButton getRbClient() { + return rbClient; + } + + /** + * @return the rbServer + */ + public javax.swing.JRadioButton getRbServer() { + return rbServer; + } + + /** + * @return the btConnect + */ + public javax.swing.JButton getBtConnect() { + return btConnect; + } + + /** + * @return the lbIP + */ + public javax.swing.JLabel getLbIP() { + return lbIP; + } + + /** + * @return the lbPort + */ + public javax.swing.JLabel getLbPort() { + return lbPort; + } + + /** + * @return the tfIP + */ + public javax.swing.JTextField getTfIP() { + return tfIP; + } + + /** + * @return the tfPort + */ + public javax.swing.JTextField getTfPort() { + return tfPort; + } + + /** + * Creates new form ChatView + */ + public ChatView() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + bgSelect = new javax.swing.ButtonGroup(); + tfPort = new javax.swing.JTextField(); + lbPort = new javax.swing.JLabel(); + lbIP = new javax.swing.JLabel(); + tfIP = new javax.swing.JTextField(); + btConnect = new javax.swing.JButton(); + jSeparator1 = new javax.swing.JSeparator(); + rbClient = new javax.swing.JRadioButton(); + rbServer = new javax.swing.JRadioButton(); + gvDrawPane = new grafikchat.view.GrafikView(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + tfPort.setText("3210"); + tfPort.setToolTipText(""); + + lbPort.setText("Port:"); + lbPort.setToolTipText(""); + + lbIP.setText("IP:"); + + tfIP.setText("127.0.0.1"); + + btConnect.setText("connect"); + btConnect.setToolTipText(""); + + bgSelect.add(rbClient); + rbClient.setSelected(true); + rbClient.setText("Client"); + + bgSelect.add(rbServer); + rbServer.setText("Server"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(gvDrawPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(rbClient, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(215, 215, 215)) + .addComponent(jSeparator1) + .addGroup(layout.createSequentialGroup() + .addComponent(lbPort) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tfPort, javax.swing.GroupLayout.PREFERRED_SIZE, 61, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbIP) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tfIP, javax.swing.GroupLayout.DEFAULT_SIZE, 164, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btConnect)) + .addGroup(layout.createSequentialGroup() + .addComponent(rbServer) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(rbClient) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rbServer) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbPort) + .addComponent(tfPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(tfIP, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbIP) + .addComponent(btConnect)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(gvDrawPane, javax.swing.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the Nimbus look and feel */ + // + /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. + * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html + */ + try { + for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + javax.swing.UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (ClassNotFoundException ex) { + java.util.logging.Logger.getLogger(ChatView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (InstantiationException ex) { + java.util.logging.Logger.getLogger(ChatView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + java.util.logging.Logger.getLogger(ChatView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (javax.swing.UnsupportedLookAndFeelException ex) { + java.util.logging.Logger.getLogger(ChatView.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } + // + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new ChatView().setVisible(true); + } + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.ButtonGroup bgSelect; + private javax.swing.JButton btConnect; + private grafikchat.view.GrafikView gvDrawPane; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JLabel lbIP; + private javax.swing.JLabel lbPort; + private javax.swing.JRadioButton rbClient; + private javax.swing.JRadioButton rbServer; + private javax.swing.JTextField tfIP; + private javax.swing.JTextField tfPort; + // End of variables declaration//GEN-END:variables + + + /** + * @return the gvDrawPane + */ + public grafikchat.view.GrafikView getGvDrawPane() { + return gvDrawPane; + } +} diff --git a/src/grafikchat/view/GrafikView.java b/src/grafikchat/view/GrafikView.java new file mode 100644 index 0000000..c46d405 --- /dev/null +++ b/src/grafikchat/view/GrafikView.java @@ -0,0 +1,184 @@ +package grafikchat.view; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.geom.Line2D; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.List; +import java.util.logging.Logger; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.DialogTypeSelection; +import javax.swing.JComponent; +import javax.swing.JOptionPane; +import grafikchat.model.Figure; +import grafikchat.model.ChatModel; +import grafikchat.model.Figures; +import grafikchat.ohmlogger.OhmLogger; + +/** + * View of zeichenprogramm + * + * @author marian + */ +public class GrafikView extends JComponent implements Printable +{ + private final static Logger lg = OhmLogger.getLogger(); + private Line2D.Double line; + private ChatModel model; + private final static Color colorInternal = Color.BLACK; + private final static Color colorExternal = Color.RED; + + /** + * Constructor, initialize UI + */ + public GrafikView() + { + this.model = null; + this.setBackground(Color.WHITE); + line = new Line2D.Double(); + + lg.info("Call constructor of grafikview"); + } + + /** + * Set model + * @param model model of MVC + */ + public void setModel(ChatModel model) + { + this.model = model; + lg.info("Set model of grafik view"); + } + + /** + * Draw point (line with the point before) + * @param mode True to draw internal point, false to draw external point + */ + public void drawPoint(boolean mode) + { + if (this.model == null) { + lg.warning("Model not initialized"); + return; + } + + Graphics2D g2 = (Graphics2D) this.getGraphics(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + if (mode) { + drawLine(model.getIntern(), colorInternal, g2); + } else { + drawLine(model.getExtern(), colorExternal, g2); + } + g2.dispose(); + } + + /** + * Draw new line between two points + * @param f Figures with points + * @param c Color of line + * @param g2 Graphics context + */ + private void drawLine(Figures f, Color c, Graphics2D g2) + { + List points; + + try { + points = f.getLastTwoPoints(); + } catch (Exception e) { + return; + } + + line.setLine(points.get(0), points.get(1)); + + g2.setPaint(c); + g2.setStroke(new BasicStroke(3)); + g2.draw(line); + } + + /** + * Repaint view + * @param g Something special + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + if (model == null) { + lg.warning("Model not initialized"); + return; + } + + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + redrawFigures(model.getIntern(), colorInternal, g2); + redrawFigures(model.getExtern(), colorExternal, g2); + } + + /** + * Redraw figure + * @param figures Figure to redraw + * @param g2 Graphics context + */ + private void redrawFigures(Figures figures, Color c, Graphics2D g2) + { + for (Figure f : figures.getFigures()) { + List points = f.getPoints(); + for (int i=1; i