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(); | |||||
} | |||||
} |
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; | |||||
} | |||||
} | |||||
} |
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<Figures> 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<Figures> 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<Figures>)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; | |||||
} | |||||
} | |||||
} |
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; | |||||
} | |||||
} | |||||
} |
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<Figures> fig = (ArrayList<Figures>)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"); | |||||
} | |||||
} | |||||
} |
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"); | |||||
} | |||||
} | |||||
} |
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<Point> 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<Point> getPoints() | |||||
{ | |||||
return points; | |||||
} | |||||
} |
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<Figure> 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<Point> getLastTwoPoints() throws Exception | |||||
{ | |||||
if (secondToLastPoint == null || lastPoint == null) { | |||||
throw new Exception("Not enough points available"); | |||||
} | |||||
ArrayList<Point> 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<Point> getFigure() throws Exception | |||||
{ | |||||
if (lastFigure == null) { | |||||
throw new Exception("No figure available"); | |||||
} | |||||
return lastFigure.getPoints(); | |||||
} | |||||
/** | |||||
* Set new figures | |||||
* @param f | |||||
*/ | |||||
public void setFigures(ArrayList<Figure> f) | |||||
{ | |||||
figureList = f; | |||||
} | |||||
/** | |||||
* Get all current figures | |||||
* @return | |||||
*/ | |||||
public ArrayList<Figure> getFigures() | |||||
{ | |||||
return figureList; | |||||
} | |||||
} |
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"); | |||||
} | |||||
} | |||||
} |
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); | |||||
} |
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; | |||||
} | |||||
} |
package grafikchat.model; | |||||
public enum TransceiverDataEvent | |||||
{ | |||||
NEWPOINT, | |||||
NEWFIGURE, | |||||
REPAINT; | |||||
} |
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(); | |||||
} | |||||
} |
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); | |||||
} | |||||
} |
<?xml version="1.0" encoding="UTF-8" ?> | |||||
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo"> | |||||
<NonVisualComponents> | |||||
<Component class="javax.swing.ButtonGroup" name="bgSelect"> | |||||
</Component> | |||||
</NonVisualComponents> | |||||
<Properties> | |||||
<Property name="defaultCloseOperation" type="int" value="3"/> | |||||
</Properties> | |||||
<SyntheticProperties> | |||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/> | |||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/> | |||||
</SyntheticProperties> | |||||
<AuxValues> | |||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> | |||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> | |||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> | |||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> | |||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> | |||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> | |||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> | |||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> | |||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> | |||||
</AuxValues> | |||||
<Layout> | |||||
<DimensionLayout dim="0"> | |||||
<Group type="103" groupAlignment="0" attributes="0"> | |||||
<Group type="102" alignment="0" attributes="0"> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Group type="103" groupAlignment="0" attributes="0"> | |||||
<Component id="gvDrawPane" max="32767" attributes="0"/> | |||||
<Group type="102" alignment="0" attributes="0"> | |||||
<Component id="rbClient" max="32767" attributes="0"/> | |||||
<EmptySpace min="-2" pref="215" max="-2" attributes="0"/> | |||||
</Group> | |||||
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/> | |||||
<Group type="102" alignment="0" attributes="0"> | |||||
<Component id="lbPort" min="-2" max="-2" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="tfPort" min="-2" pref="61" max="-2" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="lbIP" min="-2" max="-2" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="tfIP" pref="164" max="32767" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="btConnect" min="-2" max="-2" attributes="0"/> | |||||
</Group> | |||||
<Group type="102" attributes="0"> | |||||
<Component id="rbServer" min="-2" max="-2" attributes="0"/> | |||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> | |||||
</Group> | |||||
</Group> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
</Group> | |||||
</Group> | |||||
</DimensionLayout> | |||||
<DimensionLayout dim="1"> | |||||
<Group type="103" groupAlignment="0" attributes="0"> | |||||
<Group type="102" alignment="0" attributes="0"> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="rbClient" min="-2" max="-2" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="rbServer" min="-2" max="-2" attributes="0"/> | |||||
<EmptySpace type="unrelated" max="-2" attributes="0"/> | |||||
<Group type="103" groupAlignment="3" attributes="0"> | |||||
<Component id="lbPort" alignment="3" min="-2" max="-2" attributes="0"/> | |||||
<Component id="tfPort" alignment="3" min="-2" max="-2" attributes="0"/> | |||||
<Component id="tfIP" alignment="3" min="-2" max="-2" attributes="0"/> | |||||
<Component id="lbIP" alignment="3" min="-2" max="-2" attributes="0"/> | |||||
<Component id="btConnect" alignment="3" min="-2" max="-2" attributes="0"/> | |||||
</Group> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
<Component id="gvDrawPane" pref="205" max="32767" attributes="0"/> | |||||
<EmptySpace max="-2" attributes="0"/> | |||||
</Group> | |||||
</Group> | |||||
</DimensionLayout> | |||||
</Layout> | |||||
<SubComponents> | |||||
<Component class="javax.swing.JTextField" name="tfPort"> | |||||
<Properties> | |||||
<Property name="text" type="java.lang.String" value="3210"/> | |||||
<Property name="toolTipText" type="java.lang.String" value=""/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JLabel" name="lbPort"> | |||||
<Properties> | |||||
<Property name="text" type="java.lang.String" value="Port:"/> | |||||
<Property name="toolTipText" type="java.lang.String" value=""/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JLabel" name="lbIP"> | |||||
<Properties> | |||||
<Property name="text" type="java.lang.String" value="IP:"/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JTextField" name="tfIP"> | |||||
<Properties> | |||||
<Property name="text" type="java.lang.String" value="127.0.0.1"/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JButton" name="btConnect"> | |||||
<Properties> | |||||
<Property name="text" type="java.lang.String" value="connect"/> | |||||
<Property name="toolTipText" type="java.lang.String" value=""/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JSeparator" name="jSeparator1"> | |||||
</Component> | |||||
<Component class="javax.swing.JRadioButton" name="rbClient"> | |||||
<Properties> | |||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> | |||||
<ComponentRef name="bgSelect"/> | |||||
</Property> | |||||
<Property name="selected" type="boolean" value="true"/> | |||||
<Property name="text" type="java.lang.String" value="Client"/> | |||||
</Properties> | |||||
</Component> | |||||
<Component class="javax.swing.JRadioButton" name="rbServer"> | |||||
<Properties> | |||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> | |||||
<ComponentRef name="bgSelect"/> | |||||
</Property> | |||||
<Property name="text" type="java.lang.String" value="Server"/> | |||||
</Properties> | |||||
</Component> | |||||
<Container class="grafikchat.view.GrafikView" name="gvDrawPane"> | |||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignAbsoluteLayout"> | |||||
<Property name="useNullLayout" type="boolean" value="true"/> | |||||
</Layout> | |||||
</Container> | |||||
</SubComponents> | |||||
</Form> |
/* | |||||
* 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") | |||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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(); | |||||
}// </editor-fold>//GEN-END:initComponents | |||||
/** | |||||
* @param args the command line arguments | |||||
*/ | |||||
public static void main(String args[]) { | |||||
/* Set the Nimbus look and feel */ | |||||
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> | |||||
/* 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); | |||||
} | |||||
//</editor-fold> | |||||
/* 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; | |||||
} | |||||
} |
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<Point> 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<Point> points = f.getPoints(); | |||||
for (int i=1; i<points.size(); i++) { | |||||
line.setLine(points.get(i-1), points.get(i)); | |||||
g2.setPaint(c); | |||||
g2.setStroke(new BasicStroke(3)); | |||||
g2.draw(line); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Try to print current graphics | |||||
*/ | |||||
public void doPrint() | |||||
{ | |||||
HashPrintRequestAttributeSet printSet = new HashPrintRequestAttributeSet(); | |||||
printSet.add(DialogTypeSelection.NATIVE); | |||||
PrinterJob pj = PrinterJob.getPrinterJob(); | |||||
pj.setPrintable(this); | |||||
// Druckdialog | |||||
if (pj.printDialog(printSet)) { | |||||
try { | |||||
pj.print(printSet); | |||||
} catch (Exception ex) { | |||||
JOptionPane.showMessageDialog(this, ex.toString()); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Perform print of graphics | |||||
* @param gp Current graphics | |||||
* @param pf format of page | |||||
* @param pageIndex index of page | |||||
* @return result if successful | |||||
* @throws PrinterException if something went wrong | |||||
*/ | |||||
@Override | |||||
public int print(Graphics gp, PageFormat pf, int pageIndex) throws PrinterException | |||||
{ | |||||
Graphics2D g2p = (Graphics2D) gp; | |||||
if (pageIndex == 0) { | |||||
g2p.translate(pf.getImageableX(), pf.getImageableY()); | |||||
g2p.scale(pf.getImageableWidth()/pf.getWidth(), pf.getImageableHeight() / pf.getHeight()); | |||||
super.print(g2p); | |||||
return Printable.PAGE_EXISTS; | |||||
} else { | |||||
return Printable.NO_SUCH_PAGE; | |||||
} | |||||
} | |||||
} |