UmlGui.java
package algorithmen.umleditor;
import java.util.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Baut die graphische Oberfläche auf.
* Manager für alle Elemente eines UML-Diagramms.
* Ist zuständig für alle globalen Operationen wie laden und speichern.
* Enthält eine Liste aller Views
*/
public class UmlGui extends JApplet implements Serializable {
protected java.util.List views;
protected JFileChooser fc;
protected int state; // action that is just being performed
// types of actions
protected static final int POINTING = 0;
protected static final int EDITING = 1;
protected static final int DELETING = 2;
protected static final int CHOOSING_LEFT_H = 3;
protected static final int CHOOSING_RIGHT_H = 4;
protected static final int CHOOSING_LEFT_V = 5;
protected static final int CHOOSING_RIGHT_V = 6;
protected static final int MOVING = 7;
protected View leftObject; // object found with the first click
/** Creates a new instance of UMLGui */
public UmlGui() {
init();
}
public void init() {
Container cp = getContentPane();
// Erzeuge den Toolbar
JToolBar toolBar = new JToolBar();
addButtons(toolBar);
// Erzeuge die Zeichenfläche
JPanel drawArea = new DisplayPanel();
DisplayMouseListener dml = new DisplayMouseListener();
drawArea.addMouseListener(dml);
drawArea.addMouseMotionListener(dml);
JScrollPane scrollPane = new JScrollPane(drawArea);
cp.add(toolBar, BorderLayout.NORTH);
cp.add(scrollPane, BorderLayout.CENTER);
try { // keine Dateioperation möglich, wenn UmlGui als Applet läuft
fc = new JFileChooser();
} catch(Exception e) {
// ok, tue nichts
}
views = new ArrayList();
state = POINTING;
}
/**
* Fügt die Buttons zum Toolbar hinzu
*/
protected void addButtons(JToolBar toolbar) {
JButton button;
// Button Laden
button = new JButton(getIcon("load"));
button.setToolTipText("Laden");
button.addActionListener(new LoadListener());
toolbar.add(button);
// Button Speichern
button = new JButton(getIcon("save"));
button.setToolTipText("Speichern");
button.addActionListener(new SaveListener());
toolbar.add(button);
toolbar.addSeparator();
// Button Neue Klasse
button = new JButton(getIcon("class"));
button.setToolTipText("Neue Klasse");
button.addActionListener(new AddClassListener());
toolbar.add(button);
// Button Neues Interface
button = new JButton(getIcon("interface"));
button.setToolTipText("Neues Interface");
button.addActionListener(new AddInterfaceListener());
toolbar.add(button);
// Button Neues Objekt
button = new JButton(getIcon("object"));
button.setToolTipText("Neues Objekt");
button.addActionListener(new AddObjectListener());
toolbar.add(button);
toolbar.addSeparator();
// Button Neuer Pfeil vertikal
button = new JButton(getIcon("up"));
button.setToolTipText("Neuer vertikaler Pfeil");
button.addActionListener(new AddUpArrowListener());
toolbar.add(button);
// Button Neuer Pfeil horizontal
button = new JButton(getIcon("right"));
button.setToolTipText("Neuer horizontaler Pfeil");
button.addActionListener(new AddRightArrowListener());
toolbar.add(button);
toolbar.addSeparator();
// Button Edit
button = new JButton(getIcon("edit"));
button.setToolTipText("Editieren");
button.addActionListener(new EditListener());
toolbar.add(button);
// Button Delete
button = new JButton(getIcon("delete"));
button.setToolTipText("Löschen");
button.addActionListener(new DeleteListener());
toolbar.add(button);
}
/**
* Fügt den View eines UML-Objekts in die Liste ein.
*/
public void addUmlElement(View o) {
views.add(o);
repaint();
}
/**
* löscht alle Views aus der Liste.
*/
public void clear() {
views.clear();
}
/**
* Speichert die Liste aller Views in der Datei file.
*/
public void save() {
if (fc.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) {
return;
}
File file = fc.getSelectedFile();
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
out.writeObject(views);
out.close(); // flushes output
} catch (Exception e) {
System.err.println("Fehler beim Speichern in " + file.getName());
e.printStackTrace();
}
}
/**
* Lädt die Liste aller Views aus der Datei file.
*/
public void load() {
if (fc.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) {
return;
}
File file = fc.getSelectedFile();
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
views = (java.util.List) in.readObject();
} catch (Exception e) {
System.err.println("Fehler beim Laden von " + file.getName());
e.printStackTrace();
}
repaint();
}
public static void main(String[] args) {
// erzeuge ein neues Fenster, das sich richtig beendet
JFrame meinFenster = new JFrame("UML Editor");
meinFenster.setDefaultCloseOperation(meinFenster.EXIT_ON_CLOSE);
// packe ein ZeichenFenster hinein
Container p = meinFenster.getContentPane();
p.add(new UmlGui());
// zeige das Fenster in bestimmter Größe an
meinFenster.setSize(640, 480);
meinFenster.setVisible(true);
}
// interne Methoden
/*
* Erzeugt ein ImageIcon aus der Datei name im images-Verzeichnis.
* Hängt Endung .gif an name an.
*/
protected ImageIcon getIcon(String name) {
// Problem:
// Programm läuft als Applet und Applikation ->
// als Applet kann der Pfad nicht direkt verwendet werden,
// als Applikation kann getCodebase von Applet nicht benutzt werden.
// Daher verwende ich den ClassLoader explizit
// -> Basis-URL bezieht sich auf Spitze der Paket-Hierarchie
ClassLoader myCL = getClass().getClassLoader();
String urlString = "algorithmen/umleditor/images/" + name + ".gif";
URL myURL = myCL.getResource(urlString);
if (myURL != null) {
return new ImageIcon(myURL);
} else {
return null;
}
}
/**
* Bestimmt das umgebende Frame.
* Vor allem für das Applet wichtig.
*/
protected Frame getFrame() {
Container c = getParent();
while (c != null && !(c instanceof Frame)) {
c = c.getParent();
}
return (Frame) c;
}
class DisplayPanel extends JPanel {
public void paintComponent(Graphics g) {
setBackground(Color.WHITE);
super.paintComponent(g);
// laufe durch die Objektliste
for (Iterator i = views.iterator(); i.hasNext(); ) {
View v = (View) i.next();
v.draw(g);
}
}
}
class LoadListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (fc != null) { // no load when running as applet
load();
}
}
}
class SaveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (fc != null) { // no save when running as applet
save();
}}
}
class AddClassListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
addUmlElement(new ClassView());
}
}
class AddInterfaceListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
addUmlElement(new InterfaceView());
}
}
class AddObjectListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
addUmlElement(new ObjectView());
}
}
class AddRightArrowListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
state = CHOOSING_LEFT_H;
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
}
class AddUpArrowListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
state = CHOOSING_LEFT_V;
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
}
class EditListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
state = EDITING;
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
}
class DeleteListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
state = DELETING;
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
}
}
class DisplayMouseListener extends MouseAdapter
implements MouseMotionListener {
// aktives Objekt einer Mausoperation
protected View hitObjectView = null;
// Koordinaten des letzten mousePressed
protected Point lastPoint;
public void mousePressed(MouseEvent e){
// prüfe, welches Objekt getroffen wurde
hitObjectView = null;
for (Iterator i = views.iterator(); i.hasNext(); ) {
View v = (View) i.next();
if (v.contains(e.getPoint())) {
hitObjectView = v;
break;
}
}
// nichts getroffen -> zurück in Grundzustand
if (hitObjectView == null) {
state = POINTING;
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
return;
}
// Aktion je nach Zustand durchführen
Arrow a;
switch (state) {
case DELETING:
views.remove(hitObjectView);
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
state = POINTING;
repaint();
break;
case EDITING:
hitObjectView.createEditor(hitObjectView.getModel(), getFrame());
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
state = POINTING;
repaint();
break;
case POINTING:
lastPoint = e.getPoint();
state = MOVING;
break;
case CHOOSING_LEFT_H:
leftObject = hitObjectView;
state = CHOOSING_RIGHT_H;
break;
case CHOOSING_LEFT_V:
leftObject = hitObjectView;
state = CHOOSING_RIGHT_V;
break;
case CHOOSING_RIGHT_H:
a = new Arrow(leftObject.getModel(), hitObjectView.getModel(),
ArrowType.REFERENCE);
addUmlElement(new ArrowView(a, leftObject, hitObjectView));
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
state = POINTING;
repaint();
break;
case CHOOSING_RIGHT_V:
a = new Arrow(leftObject.getModel(), hitObjectView.getModel(),
ArrowType.EXTENSION);
addUmlElement(new ArrowView(a, leftObject, hitObjectView));
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
state = POINTING;
repaint();
break;
}
}
public void mouseDragged(MouseEvent e) {
if (hitObjectView != null && state == MOVING) {
hitObjectView.translate(e.getX() - lastPoint.x, e.getY() - lastPoint.y);
lastPoint = e.getPoint();
repaint();
}
}
public void mouseReleased(MouseEvent e){
if (hitObjectView != null && state == MOVING) {
hitObjectView.translate(e.getX() - lastPoint.x, e.getY() - lastPoint.y);
hitObjectView = null;
state = POINTING;
repaint();
}
}
public void mouseMoved(MouseEvent e) { // tue nichts
}
}
}