Graph.java

/*
 *     YAV (Yet another Visualiser)
 *     (c) 2004 by Robin Quast
 *    Version 1.0 (04.03.2004)
 *    
 *  erstellt im Rahmen der Diplomarbeit
 * "Theorie und Java- Realisierung
 *  ausgewählter Algorithmen zur
 *  Bestimmung kürzester Wege in Graphen"
 *
 *  betreut durch Prof. Dr. Lenze
 *  an der Fachhochschule Dortmund
 *  im SS 2003/ WS 2003/2004
 *
 *  @(#)Graph.java  1.6 04/03/09
 */

/* To Do: 
 * - Beim Zeichnen der Pfeile die Steigung an dem Zielknoten ermitteln??
 * - Kante mit Gegenkante kann nicht per Direktklick gelöscht werden => Routine 
 *   wird deaktiviert.
 */
 
import javax.swing.*;
import java.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.Enumeration;
import java.lang.Math;
import java.util.Collections;
import java.awt.geom.*;
import java.awt.print.PrinterJob;
import java.awt.print.*;
import javax.swing.event.*;
import java.io.*;

/** Klasse die die Graphenerstellung und die Anzeige übernimmt. Die Druckausgabe 
 * besitzt zur Zeit nur eingeschänkte Funktionalität und wird in einer kommenden
 * Version erweitert.
 */
public class Graph
extends JPanel
implements Printable, MouseListener, MouseMotionListener, TableModelListener {

  Graphics2D g2d=null;
  
    GraphNodeList graphDaten = new GraphNodeList();
  GraphNode selectedNode = null;//new GraphNode(null,null);
  
  GraphEdgeList graphKanten = new GraphEdgeList();
  
  EdgeTable etable = null;
  EdgeTableModel etmodel = null;  
  
  JPanel eastpanel = new JPanel();
    
  Adjazenzliste adlist = null;

    int drawMode=1;
    int radius=20;
    
  int nodeCounter = 0;
  Vector geloeschteKnoten = null;

  Color selectionsFarbe = Color.blue;  
  Color linienFarbe = Color.blue;  
  Color schriftFarbe = Color.black;  
  
  int selectedInt = -1;
  boolean dragged=false;
  int nodeLimit = 100;   // nicht mehr als 100 Knoten (0...99) sind zugelassen
              // ist aber nur ein Darstellungsproblem bzgl. des Textes in dem Knoten und sollte hier ausreichen
              // nodeLimit darf NICHT den Wert Integer.MAX_VALUE erhalten.
  Rectangle area = null;
    
  JLabel ueberschrift = new JLabel();    
  
  /** Konstruktor.
   */
    public Graph() {
    setLayout(new BorderLayout());

    etmodel = new EdgeTableModel();
    etable= new EdgeTable(etmodel);
    etmodel.addTableModelListener(this);

    JScrollPane scrollPane = new JScrollPane(etable);
    
    eastpanel.setLayout(new BoxLayout(eastpanel,BoxLayout.Y_AXIS));
    ueberschrift.setAlignmentX(Component.CENTER_ALIGNMENT);
    ueberschrift.setText("Kantenliste");
    eastpanel.add(ueberschrift);
    
    scrollPane.setAlignmentX(Component.CENTER_ALIGNMENT);
    eastpanel.add(scrollPane);
    
    //add(eastpanel,BorderLayout.EAST);  
    setBackground(Color.white);
    addMouseMotionListener(this);
    addMouseListener(this);
    
    adlist = new Adjazenzliste();
    geloeschteKnoten=new Vector();
    graphDaten=new GraphNodeList();
    setSize(new Dimension(790,590));
    }
    
    /** Zurückgeben des Panels, das die Knotentabelle enthält.
     */
    public JPanel getViewPanel() {
      return eastpanel;
    }
    
    /** Den Splitpane zurückgeben.
     */
    public JSplitPane getSplitPane() {
      JSplitPane spp_graph = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this, getViewPanel());
        spp_graph.setContinuousLayout(true);
    spp_graph.setOneTouchExpandable(true);
    spp_graph.setDividerLocation(600);
    return spp_graph;
    }
    
    /** Werden die Kosten für eine Kante eingegeben, dann muss der
     * Graph neu gezeichnet werden.
     */
    public void tableChanged(TableModelEvent e) {
      repaint();
    }

    /** Den Zeichenmodus setzen.
     */
    public void setDrawMode(int mode) {
    drawMode=mode;
    }

  /** Eventroutine bei einem Mausdrag. Dabei wird der Knoten bewegt, der 
   * selektiert ist und sich unter dem Mauszeiger befindet. Befindet sich kein 
   * Knoten unter dem Mauszeiger, oder ist kein Knoten selektiert,
   * dann wird nichts gemacht.
   */
    public void mouseDragged(MouseEvent e) {
      e.consume();
      if (selectedNode!=null) {
        dragged=true;
        selectedNode.rectangle=new Rectangle(e.getX()-radius/2,e.getY()-radius/2,radius,radius);
        repaint();
      }
    }

  /** Event für die Mausbewegung.
   */
    public void mouseMoved(MouseEvent e) {
    }

  /** Drücken der Maus löst je nach Modus eine bestimmte Reaktion aus.
   */
    public void mousePressed(MouseEvent e) {
    e.consume();
    Rectangle nr = new Rectangle(e.getX()-radius/2,e.getY()-radius/2,radius,radius);
    GraphNode intersectsNode=graphDaten.intersectsWith(nr);
    if (intersectsNode!=null)  {
      switch (drawMode)  {
        case 1// Knoten zeichnen
          selectedNode=intersectsNode;
          selectedInt=selectedNode.value;
          selectedNode.setColor(selectionsFarbe);
          break;
        case 2// Knoten löschen
          selectedNode=intersectsNode;
          geloeschteKnoten.add(selectedNode.getNode());
          graphDaten.remove(selectedNode);
          adlist.remove(selectedNode.getNode());  
          removeRows(selectedNode.getNode());
          selectedNode=null;selectedInt=-1;
          break;
        case 3// Zeichenmodus Kante
          if (selectedNode==null) {
            selectedNode=intersectsNode;  
            selectedInt=selectedNode.getValue();
            selectedNode.setColor(selectionsFarbe);
          else {
            Edge tmp_edge=new Edge(selectedNode.getNode(),intersectsNode.getNode(),0);
            adlist.add(tmp_edge);
            //adlist.add(selectedNode.node,intersectsNode.node,0);
            selectedNode=null;selectedInt=-1;
            etmodel.addRow(tmp_edge);
          }
          break;
        case 4// Kante löschen
          // Routine um die Kanten per Knotenklick zu löschen
          if (selectedNode==null) {
            selectedNode=intersectsNode;  
            selectedInt=selectedNode.getValue();
            selectedNode.setColor(selectionsFarbe);
          else {
            int tmp_kosten=adlist.getCost(selectedNode.getNode(),intersectsNode.getNode());
            Edge tmp_edge=new Edge(selectedNode.getNode(),intersectsNode.getNode(),tmp_kosten);
            adlist.remove(tmp_edge);
            //adlist.add(selectedNode.node,intersectsNode.node,0);
            selectedNode=null;selectedInt=-1;
            removeRow(tmp_edge)
          }
          break;
      }
    else {
      if (drawMode==4) {
        Point punkt = new Point(e.getX(),e.getY());
        //removeRow(punkt); // mit Kanten- Direktklick, diese löschen funktioniert noch nicht sauber für Kanten mit Gegenkanten, also als QuadCurve gemalte Kanten
      }
      selectedNode=null;selectedInt=-1;
    }
    
    dragged=false;
    repaint();

    }

  /** Loslassen der Maustaste löst je nach Zeichenmodus eine spezielle
   * Reaktion aus.
   */
    public void mouseReleased(MouseEvent e) {
      e.consume();
      int x=e.getX();int y=e.getY();
    switch(drawMode) {
      
      case 1:        
        if (nodeCounter<nodeLimit) {
           Rectangle nr = new Rectangle(e.getX()-radius/2,e.getY()-radius/2,radius,radius);
           GraphNode intersects_node = graphDaten.intersectsWith(nr);
                 
          if (intersects_node==null) {
            int node_number=getNextNodeNumber();
            adlist.add(node_number);
            graphDaten.add(new GraphNode(node_number,nr));
            selectedInt=-1;
                // wenn der Knoten noch nicht in die Liste aufgenommen wurde
          else {
            if (selectedNode==null) {
              selectedNode=intersects_node;
              selectedInt=selectedNode.getValue();
              selectedNode.setColor(selectionsFarbe);
            else {
              selectedNode=null;
              selectedInt=-1;            
            }
          }
        }
        break;
        
      case 2:

        break;
    }
    
    dragged=false;
    repaint();

    }

  /** F&uuml;r die Knotenerzeugung eine neue Knotennummer holen. Dabei
   * werden gel&ouml;schte Knotennummern ber&uuml;cksichtigt.
   */
  public int getNextNodeNumber() {
    
    if (geloeschteKnoten.size()!=0){
      Collections.sort(geloeschteKnoten);
      Node min_node=(Node)geloeschteKnoten.firstElement();
      if (Math.min(min_node.value,nodeCounter)==nodeCounter) {
        nodeCounter++;
      else {
        geloeschteKnoten.remove(min_node);
      }
      return Math.min(min_node.value,nodeCounter);
      
    else return nodeCounter++;
  }

  /** Mausevent f&uuml;r das Bewegen der Maus in einem Bereich.
   */
    public void mouseEntered(MouseEvent e) {

    }

  /** Mausevent f&uuml;r das Verlassen der Maus aus einem Bereich.
   */
    public void mouseExited(MouseEvent e) {

    }
    
  /** Mausevent f&uuml;r das Klicken der Maus.
   */
    public void mouseClicked(MouseEvent e) {

    }

  /** Zeichnen der Komponenten. Z.B. Kanten, Knoten usw.
   */
     public void paintComponent(Graphics g) {
      // male Knoten aus Vector und selektierten Knoten 
    super.paintComponent(g);
    g2d=(Graphics2Dg;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);    
        
      //erzeuge das Rechteck, welches zur &uuml;berpr&uuml;fung dient, ob ein Rechteck innerhalb 
      // des Malbereichs liegt
        Dimension dim = getSize();
        int w = (int)dim.getWidth();
        int h = (int)dim.getHeight();
        area = new Rectangle(dim);
    paintEdges(g2d);
    paintNodes(g2d);
    }
     
    /** Zeichnen der Knoten (auch f&uuml;r Druckerausgabe)
     */
    void paintNodes(Graphics2D g2d) {
      // male die Knoten
    int anzahl_knoten = graphDaten.getLength();
     for (int i=0; i<anzahl_knoten;i++) {
       GraphNode tmp_gn = graphDaten.get(i);
       if (tmp_gn!=null) {
         if (tmp_gn!=selectedNode) {
          paintGraphNode(tmp_gn,g2d,false);
        else {
          paintGraphNode(tmp_gn,g2d,true);
        }
       }
     }
    

  /** Zeichnen der Kanten (auch f&uuml;r Druckerausgabe)
   */
  void paintEdges(Graphics2D g2d){
    graphKanten.removeAllElements();

    // male die Kanten
    int highestNodeNumber=adlist.getMaxNodeNumber();
    for (int i=0; i<=highestNodeNumber;i++) { 
      // wenn es Kanten gibt, dann durchlaufe die Kantenmenge
      // und male die Kanten
      Vector edges=adlist.getEdgesWithTail(i);

      if (edges!=null) { 
        Enumeration tmp_enum = edges.elements();
         while (tmp_enum.hasMoreElements()) { // solange noch Knoten in der Liste gefunden werden, die gezeiochnet werden m&uuml;ssen 
           Edge tmp_kante = (Edgetmp_enum.nextElement()// Hole Element aus Vector        
          paintEdge(tmp_kante,g2d);
         }
      }
    
  
  }
   
  /** Malt eine Kante, die interaktiv oder per GraphNodeList und Adjazenzliste
   * vorgegeben ist.
   */
  void paintEdge(Edge tmp_kante,Graphics2D g2d) {
    
    // Mittelpunkt zu Head und Tail holen
    Point head = graphDaten.getMidpoint(tmp_kante.getHeadValue());
     Point tail = graphDaten.getMidpoint(tmp_kante.getTailValue());
     // pr&uuml;fen, ob die Kante eine Gegenkante enth&auml;lt
     boolean enthaelt_gegenkante=adlist.contains(new Edge(tmp_kante.getHead(),tmp_kante.getTail()));
     // Koordinaten der Kosten festhalten
     Point cost_position=new Point();
     cost_position.setLocation((2*head.x+tail.x)/3,(2*head.y+tail.y)/3);
     
     
    // male den Pfeil
    // berechne den Drehwinkel
     double y21=(-(head.getY()-tail.getY()));
     double x21=(head.getX()-tail.getX());
     double yx21 = 0;
     double drehung = 0;
    if (x21==0) {
      yx21 = (2/3);
      drehung=Math.PI*1/4;
      if (y21>=0) { 
        drehung=Math.PI*5/4
      }
     else {
       if (y21==0) {
         yx21=0;
       else {
         yx21 = y21/x21;
       }
       drehung = Math.PI*3/4-Math.atanyx21 );
     }
     
     double k=0;
     if (enthaelt_gegenkantek=0.3;
     int[] x=new int[3];
     int[] y=new int[3];
     int vorzeichen=1;
     if (x21<=0vorzeichen=(-1);
     // berechne die Polygonpunkte, die den Pfeil darstellen
    x[0]=head.x;x[1]=head.x+20*vorzeichen;x[2]=head.x+10*vorzeichen;
    y[0]=head.y;y[1]=head.y+10*vorzeichen;y[2]=head.y+20*vorzeichen;
    // erzeuge das Polygon
    Polygon pfeil = new Polygon(x,y,3);
    if (tmp_kante.getHeadValue()==tmp_kante.getTailValue()) drehung=Math.PI*2/7// Koordinatensystem drehen
    g2d.rotatedrehung+k,head.x,head.y)// Koordinatensystem drehen
     g2d.setColor(linienFarbe)// Liniesnfarbe setzen
     g2d.fillPolygon(pfeil)// Polygon malen/ rendern
     g2d.rotate-drehung-k,head.x,head.y)// Koordinatensystem zur&uuml;ckdrehen
    g2d.setColor(schriftFarbe)// "normale" Farbe setzen
    // Kosteninformationen rendern
     //g2d.drawString(""+tmp_kante.getCost(),cost_position.x,cost_position.y);        

    // male die Kante mit der Drehung, die f&uuml;r den Pfeil berechnet wurde.
     if (enthaelt_gegenkante || tmp_kante.getHeadValue()==tmp_kante.getTailValue()) {
       int korrektur=0;
       if (head.x>tail.x) {
         korrektur=1;
       else {
         korrektur=-1;
       }   
       // mittelpunkt der Kurve berechnen
       //Point mid = new Point((head.x+tail.x)/2+30*korrektur,(head.y+tail.y)/2+30*korrektur);
             
      if (tmp_kante.getHeadValue()==tmp_kante.getTailValue()) { // schlinge malen 
        CubicCurve2D.Double linie = new CubicCurve2D.Double(tail.getX(),tail.getY(), head.getX()-40,head.getY()-60,head.getX()+40,head.getY()-60,head.getX(),head.getY());
        graphKanten.add(tmp_kante,(Object)linie);
        cost_position.setLocation(head.x,head.y-50);
        g2d.setColor(linienFarbe)
        g2d.draw(linie);               
      else // kante mit gegenkante muss gebogen dargestellt werden
        // initialisiere entsprechende Variablen
        Point max,min;
        Point mitte = new Point();
          vorzeichen=1// head ist kleiner als tail
      
        // Wenn x f&uuml;r head und tail gleich sind, dann liegen die Punkte
        // waagerecht zueinander => einfachere Punktberechnung
        if (head.getX()==tail.getX()) {
          if (head.getY()<tail.getY()) { 
            min=head;
            max=tail;
            
          else {
            max=head;
            min=tail;
            vorzeichen=-1;
          }
          // Mitte der beiden Punkte berechnen
          mitte.setLocation(max.getX()+40*vorzeichen,min.getY()+((max.getY()-min.getY())/2));

          QuadCurve2D.Double linie = new QuadCurve2D.Double(tail.getX(),tail.getY(), mitte.getX(),mitte.getY(),head.getX(),head.getY());  
          graphKanten.add(tmp_kante,(Object)linie);
          g2d.setColor(linienFarbe)
          g2d.draw(linie);
          g2d.setColor(schriftFarbe)
          cost_position.setLocation(mitte.getX(),mitte.getY());
          g2d.drawString(""+tmp_kante.getCost(),cost_position.x,cost_position.y);        
        }

        // Wenn y f&uuml;r head und tail gleich sind, dann
        // liegen beide Punkte sekrecht zureinander
        // => einfachere Punktberechnung, kein Drehen n&ouml;tig
        if (head.getY()==tail.getY()) {
          if (head.getX()<tail.getX()) {
            min=head;
            max=tail;
          else {
            max=head;
            min=tail;
            vorzeichen=-1;
          }
          mitte.setLocation(min.getX()+((max.getX()-min.getX())/2),max.getY()+40*vorzeichen);
        
          QuadCurve2D.Double linie = new QuadCurve2D.Double(tail.getX(),tail.getY(), mitte.getX(),mitte.getY(),head.getX(),head.getY());  
          graphKanten.add(tmp_kante,(Object)linie);
          g2d.setColor(linienFarbe)
          g2d.draw(linie);
          g2d.setColor(schriftFarbe)
          cost_position.setLocation(mitte.getX(),mitte.getY());
          g2d.drawString(""+tmp_kante.getCost(),cost_position.x,cost_position.y);        
        }
        
        if ((head.getY()!=tail.getY()) && (head.getX()!=tail.getX())) {
          // hilfspunkt, der den waagerechten Tail Punkt darstellt
          Point hilfetail = new Point();
          // berechne die Streckenl&auml;nge nach Pytogoras
          double streckenlaenge = Math.sqrt(Math.pow(Math.abs(head.getX()-tail.getX()),2)+Math.pow(Math.abs(head.getY()-tail.getY()),2));
          // setze den Mittelpunkt der zu zeichnenden Waagerechten Strecke
          mitte.setLocation(head.getX()+streckenlaenge/2*vorzeichen,head.getY()+40*vorzeichen);
          // Setze den Endpunkt der Waagerechten Strecke
          hilfetail.setLocation(head.getX()+streckenlaenge*vorzeichen,head.getY());
          g2d.setColor(linienFarbe);
          if (head.getY()<tail.getY()) g2d.setColor(schriftFarbe);
          //g2d.rotate( -(drehung+Math.PI*5/4),head.x,head.y); // Koordinatensystem zur&uuml;ckdrehen
          double kor;
          if (head.getX()<tail.getX()) kor=Math.PI*5/4;
          else kor=Math.PI*1/4;
          g2d.rotatedrehung+kor,head.x,head.y)// Koordinatensystem drehen
          // render die Kosteninformationen der Kante
          cost_position.setLocation(mitte.x,mitte.y);
          g2d.setColor(schriftFarbe);       
          g2d.drawString(""+tmp_kante.getCost(),cost_position.x,cost_position.y);        
          QuadCurve2D.Double linie = new QuadCurve2D.Double(hilfetail.getX(),hilfetail.getY(), mitte.getX(),mitte.getY(),head.getX(),head.getY());  
          g2d.setColor(linienFarbe);            
          //AffineTransform at=g2d.getTransform();
          graphKanten.add(tmp_kante,(Object)linie);
          g2d.draw(linie);
          g2d.rotate-(drehung+kor),head.x,head.y)// Koordinatensystem zur&uuml;ckdrehen
     
         }
      }
    else {
      Line2D.Double linie = new Line2D.Double(tail, head);
      graphKanten.add(tmp_kante,(Object)linie);
      // F&uuml;r die Verwaltung in GraphEdgeList wird hier eine QuaDCurve verwendet
      //QuadCurve2D.Double linie=new QuadCurve2D.Double(tail.getX(),tail.getY(), head.getX(),head.getY(),head.getX(),head.getY());  
      g2d.setColor(linienFarbe)
      g2d.draw(linie);
      g2d.setColor(schriftFarbe);       
      g2d.drawString(""+tmp_kante.getCost(),cost_position.x,cost_position.y);        
    }
    g2d.setColor(schriftFarbe);       
    
  }
  
  /** Malt einen Knoten.
   */
  void paintGraphNode(GraphNode gn,Graphics2D g2d,boolean filled) {
      Rectangle tmp_rec =new Rectangle();
       tmp_rec = gn.rectangle;
      boolean ok = true;//checkRect(tmp_rec);
      if (ok) { // falls Zeichnen m&ouml;glich
        g2d.setColor(Color.white)
        g2d.fillArc(tmp_rec.x, tmp_rec.y, tmp_rec.width , tmp_rec.height , 0360);
        
        if (filled) {
          g2d.setColor(gn.getColor())
             g2d.fillArc(tmp_rec.x, tmp_rec.y, tmp_rec.width , tmp_rec.height , 0360);
        else {
          g2d.setColor(selectionsFarbe)
             g2d.drawArc(tmp_rec.x , tmp_rec.y, tmp_rec.width , tmp_rec.height , 0360);
        }     
        // male Knotentext  
        g2d.setColor(Color.black);
        int x_korrektur=3;
        if (gn.getValue()>9x_korrektur=6;
        g2d.drawString(""+gn.getValue(),tmp_rec.x+radius/2-x_korrektur,tmp_rec.y+radius/2+5);
      }
   }
   
  /** Pr&uuml;ft, ob das Rechteck rect in der "area" liegt. "area" stellt die 
   * Zeichenfl&auml;che dar. Liegt das Rechteck innerhalb der Fl&auml;che, so wird
   * true zu&uuml;ckgegeben. liegt es ausserhalb der Fl&auml;che, dann ist der
   * R&uuml;ckgabewert false.
     */

     boolean checkRect(Rectangle rect){  
       // ist keine Zeichenfl&auml;che definiert, dann 
       // false zur&uuml;ckgeben
    if (area == null) {
      return false;
      }

    // liegt das Rechteck rect innerhalb der area, dann 
    // true zur&uuml;ckgeben
        if(area.contains(rect.x, rect.y, radius, radius)){
          return true;
        }
        // nochfolgender Code wird nur ausgef&uuml;hrt, wenn das Rechteck NICHT
        // in der area enthalten ist
        // hole die Koordinaten des Rechtecks in "temopr&auml;re" Variablen
        
        int new_x = rect.x;
        int new_y = rect.y;
        // teste rechte Seite
        if((rect.x+radius)>area.getWidth()){
          new_x = (int)area.getWidth()-radius;
        }
        // teste linke Seite
        if(rect.x < 0){
          new_x = 0;  
        }
        // teste untere Seite
        if((rect.y+radius)>area.getHeight()){
          new_y = (int)area.getHeight()-radius;
        }
        // teste obere Kante
        if(rect.y < 0){
          new_y = 0;
        }
        // setze neue Koordinaten f&uuml;r das Rechteck
        rect.setLocation(new_x, new_y);
        return false;
    }

  /** L&ouml;scht eine Kantenzeile aus der Tabelle. 
   */
  public void removeRow(Point p) {
    
    // Kanten per Direktklick l&ouml;schen
    Edge kante = graphKanten.removeIntersectsEdge(p);
    if (kante!=null) {
      removeRow(kante);
      adlist.remove(kante);
    }
  }
  
  /** L&ouml;scht eine Kantenzeile mti dem Index <I>index</I> aus der Tabelle.
   */
  public void removeRow(int index) {
    if (index>=0) {
      Integer t=(Integer)etable.getValueAt(index,0);
      Integer h=(Integer)etable.getValueAt(index,1);
      Integer c=(Integer)etable.getValueAt(index,2);
      Edge kante = new Edge (t.intValue(),h.intValue(),c.intValue());
      etable.removeRow(index);
      adlist.remove(kante);
      YAV.status.setText("Kante "+kante+" wurde gel&ouml;scht.");
    else YAV.status.setText("Sie haben keine Kante in der Kantenliste selektiert.");
    repaint();
  }
  
  /** L&ouml;scht zu einem Knoten alle Kanten in der Kantentabelle.
   */
  public void removeRows(Node knoten) {
    int zeilenanzahl=etmodel.getRowCount();
    int i=0;
    while (i<zeilenanzahl)  {
      int tailint=((Integer)etmodel.getValueAt(i, 0)).intValue();
      int headint=((Integer)etmodel.getValueAt(i, 1)).intValue();
      
      if ((knoten.getValue()==tailint|| (knoten.getValue()==headint)) {
        removeRow(i);
      else {
        i++;  
      }
      zeilenanzahl=etmodel.getRowCount();
    }
    repaint();
  }
  
  /** L&ouml;scht die &uuml;bergebene Kante aus der Tabelle.
   */
  public void removeRow(Edge kante) {
    int index=etmodel.indexOf(kante);
    if (index!=-1removeRow(index);
    //repaint();
  }

  /** Druckroutine, ben&ouml;tigt Java 1.4.2.
   */
    public int print(Graphics g, PageFormat pf, int pithrows PrinterException
    {
      if (pi > 1) {
        
          return Printable.NO_SUCH_PAGE;
      }
    Graphics2D g2d=(Graphics2Dg;
    
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);    
        
      //erzeuge das Rechteck, welches zur &uuml;berpr&uuml;fung dient, ob ein Rechteck innerhalb 
      // des Malbereichs liegt
      // image
        Dimension dim = getSize();
    area = new Rectangle(dim);
    
    double scale =Math.min(pf.getImageableWidth()/getWidth(),pf.getImageableHeight()/getHeight());
    scale=Math.min(1.0,scale);
    g2d.translate(pf.getImageableX(), pf.getImageableY());
    g2d.scale(scale, scale);
    switch (pi)  {
    case 0: YAV.status.setText("Seite 1 wird gedruckt...");
        paintEdges(g2d);
        paintNodes(g2d);
        break;
    case 1: YAV.status.setText("Seite 2 wird gedruckt...");
        printNodeList(g2d,pf);
        break;
      }
      return Printable.PAGE_EXISTS;
    }

  /** Drucken der Knotenliste.
   */
  public void printNodeList(Graphics2D g2d,PageFormat pf) {
    // auf einer neuen Seite sollte hier die Knotenliste gedruckt werden
    int start=(int)area.y+(int)area.height;
    //g2d.drawString("Kantenliste",(int)pf.getImageableX(),(int)pf.getImageableX());
    ueberschrift.print(g2d);
    etable.print(g2d);
  }
  
  /** Speichern der Daten in zwei Dateien. Eine Datei mit Endung .ygd f&uuml;r
   * die GraphKnotenListe und eine f&uuml;r die Adjazenzliste mit Endung .yal.
   */
  public void writeGraphDatenToFile(String datei) {
    graphDaten.writeTo(datei+".ygd");
    adlist.writeTo(datei+".yal");
  }
  
  /** Lesen der Daten aus den Dateien mit den Endungen .ygd und .yal.
   */
  public void readGraphDatenFromFile(String datei) {
    init();
    graphDaten.readFrom(datei+".ygd");
    adlist.readFrom(datei+".yal");
    nodeCounter=adlist.getMaxNodeNumber()+1;
    etmodel.initialiseTable(adlist);
    erzeugeGeloeschteKnotenVector();
    repaint();
  }
    
    /** Knotenvektor f&uuml;r das merken der gel&ouml;schten Knoten, also den
     * L&uuml;cken in der Knotenliste erzeugen.
     */
    private void erzeugeGeloeschteKnotenVector() {
          geloeschteKnoten = new Vector();
          for (int i=0;i<=adlist.getMaxNodeNumber();i++) {
            Vector nlist=adlist.getEdgesWithTail(i);
            if (nlist==null) {
          geloeschteKnoten.add(new Node(i));
        }
          }
    }
    
    /** Initialisierung.
     */
    public void init() {
      adlist = new Adjazenzliste();
    geloeschteKnoten=new Vector();
    graphDaten=new GraphNodeList();
    etmodel.removeRows();
    selectedNode=null;selectedInt=-1;
    nodeCounter=0;
    repaint();      
    }
}