[Schmitzm-commits] r28 - in trunk: . defaults dist src src/schmitzm/geotools/grid src/schmitzm/geotools/gui src/schmitzm/io src/schmitzm/swing src/schmitzm/swing/menu

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Mar 11 13:26:19 CET 2009


Author: mojays
Date: 2009-03-11 13:25:42 +0100 (Wed, 11 Mar 2009)
New Revision: 28

Added:
   trunk/src/schmitzm/io/LimitedInputStream.java
   trunk/src/schmitzm/io/TokenInputStream.java
   trunk/src/schmitzm/swing/MultiSplitPane.java
   trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java
Modified:
   trunk/defaults/.classpath
   trunk/dist/schmitzm-doc.zip
   trunk/dist/schmitzm-src.zip
   trunk/dist/schmitzm.jar
   trunk/readme.txt
   trunk/src/overview.html
   trunk/src/schmitzm/geotools/grid/GridUtil.java
   trunk/src/schmitzm/geotools/gui/FeatureCollectionPane.java
   trunk/src/schmitzm/geotools/gui/LayeredMapPane.java
   trunk/src/schmitzm/geotools/gui/MapContextControlPane.java
   trunk/src/schmitzm/io/BinaryInputBuffer.java
   trunk/src/schmitzm/io/BinaryInputStream.java
   trunk/src/schmitzm/io/BinaryUtil.java
   trunk/src/schmitzm/io/CombinedInputStream.java
   trunk/src/schmitzm/io/InputBuffer.java
Log:
dependency of ADAGIOS removed
added some useful classes from ADAGIOS

Modified: trunk/defaults/.classpath
===================================================================
--- trunk/defaults/.classpath	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/defaults/.classpath	2009-03-11 12:25:42 UTC (rev 28)
@@ -7,6 +7,5 @@
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jFreeChart"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jini"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Adagios"/>
 	<classpathentry kind="output" path="classes"/>
 </classpath>

Modified: trunk/dist/schmitzm-doc.zip
===================================================================
(Binary files differ)

Modified: trunk/dist/schmitzm-src.zip
===================================================================
(Binary files differ)

Modified: trunk/dist/schmitzm.jar
===================================================================
(Binary files differ)

Modified: trunk/readme.txt
===================================================================
--- trunk/readme.txt	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/readme.txt	2009-03-11 12:25:42 UTC (rev 28)
@@ -29,7 +29,6 @@
      - jFreeChart 1.0.6
      - Log4j 1.2.14
      - JINI
-     - ADAGIOS Java lib
 
 NOTE: All these libraries (except JRE/JDK) can be found in the
       'lib' folder of the XULU project:

Modified: trunk/src/overview.html
===================================================================
--- trunk/src/overview.html	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/overview.html	2009-03-11 12:25:42 UTC (rev 28)
@@ -168,17 +168,6 @@
 reicht: <a
  href="http://www.mojays.de/stuff/ms/schmitzm/lib/jini-ext.jar">jini-ext.jar</a>)</li>
   </ul>
-  <li class="MsoNormal" style="">Ein paar Klassen in <span
- style="font-family: &quot;Courier New&quot;;">schmitzm.swing.*</span>, <span
- style="font-family: monospace;">schmitzm</span><span
- style="font-family: &quot;Courier New&quot;;">.geotools.swing.*</span></li>
-  <ul type="circle">
-    <li class="MsoNormal" style=""><i>Projektgruppe <a
- href="http://www.mojays.de/stuff/ms/schmitzm/lib/AdagiosJavaLib.jar">ADAGIOS</a>
-der Universität Bonn (Institut für Informatik III)<a
- href="http://www.mojays.de/stuff/ms/schmitzm/lib/AdagiosJavaLib.jar"><br>
-      </a></i></li>
-  </ul>
 </ul>
 </div>
 </body>

Modified: trunk/src/schmitzm/geotools/grid/GridUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/GridUtil.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/geotools/grid/GridUtil.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -847,7 +847,7 @@
 
     // Check all raster cells inside the BB of the Geometry, whether they
     // really intersect the Geometry
-    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
+    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
     GeometryFactory geomFac    = new GeometryFactory();
     for (double y = bbMinY; y<=bbMaxY; y+=cellHeight)
       for (double x = bbMinX; x<=bbMaxX; x+=cellWidth) {
@@ -857,6 +857,8 @@
         cellBounds[1].y = y;
         cellBounds[2].x = x+cellWidth;
         cellBounds[2].y = y+cellHeight;
+        cellBounds[2].x = x;
+        cellBounds[2].y = y+cellHeight;
         cellBounds[3]   = cellBounds[0];
         if ( g.intersects(geomFac.createLinearRing(cellBounds)) ) {
           int[] cell = convertRealToRaster(gc, x, y);

Modified: trunk/src/schmitzm/geotools/gui/FeatureCollectionPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureCollectionPane.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/geotools/gui/FeatureCollectionPane.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -12,41 +12,36 @@
 package schmitzm.geotools.gui;
 
 import java.awt.BorderLayout;
-import java.awt.Insets;
 import java.awt.Dimension;
 import java.awt.event.MouseEvent;
-import javax.swing.ListSelectionModel;
-import javax.swing.JTable;
-import javax.swing.JSplitPane;
-import javax.swing.JScrollPane;
+import java.util.Vector;
+
 import javax.swing.BorderFactory;
-import javax.swing.table.AbstractTableModel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
 
-import org.geotools.map.MapLayer;
+import org.geotools.feature.AttributeType;
 import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureType;
 import org.geotools.feature.FeatureCollection;
 import org.geotools.feature.FeatureCollections;
-
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.JPanel;
-import schmitzm.geotools.gui.JMapPane;
-import schmitzm.geotools.feature.FeatureUtil;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.feature.FeatureType;
+import org.geotools.map.MapLayer;
 import org.geotools.styling.Style;
 
-import adagios.swing.MultiSplitPane;
-
-// fuer Doku
-import javax.swing.table.TableModel;
-import org.geotools.feature.FeatureIterator;
-import org.geotools.gui.swing.table.FeatureTableModel;
-import javax.swing.event.TableModelListener;
-import javax.swing.event.TableModelEvent;
-import org.geotools.feature.AttributeType;
-import java.util.Vector;
 import schmitzm.geotools.feature.AttributeTypeFilter;
+import schmitzm.geotools.feature.FeatureUtil;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.MultiSplitPane;
+import schmitzm.swing.SwingUtil;
 
 /**
  * Diese Komponente stellt eine Tabelle dar, in der die Attribute einer

Modified: trunk/src/schmitzm/geotools/gui/LayeredMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/LayeredMapPane.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/geotools/gui/LayeredMapPane.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -31,7 +31,7 @@
 import org.opengis.geometry.Envelope; // gt2-2.4.2
 //import org.opengis.spatialschema.geometry.Envelope; // gt2-2.3.4
 
-import adagios.swing.MultiSplitPane;
+import schmitzm.swing.MultiSplitPane;
 
 import schmitzm.swing.JPanel;
 import schmitzm.geotools.gui.MapContextControlPane;

Modified: trunk/src/schmitzm/geotools/gui/MapContextControlPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -46,7 +46,7 @@
 
 import com.vividsolutions.jts.geom.Envelope;
 
-import adagios.swing.ConnectedPopupMenu;
+import schmitzm.swing.menu.ConnectedPopupMenu;
 
 import schmitzm.lang.LangUtil;
 import schmitzm.swing.CaptionsChangeable;

Modified: trunk/src/schmitzm/io/BinaryInputBuffer.java
===================================================================
--- trunk/src/schmitzm/io/BinaryInputBuffer.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/BinaryInputBuffer.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -12,6 +12,11 @@
 package schmitzm.io;
 
 /**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
  * Der <code>BinaryInputBuffer</code> erweitert den <code>InputBuffer</code>
  * durch die Moeglichkeit, neben einzelnen Bytes, auch die Binaerdarstellung
  * ganze Zahlen (mehrere Bytes auf einen Schub) in den Buffer schreiben

Modified: trunk/src/schmitzm/io/BinaryInputStream.java
===================================================================
--- trunk/src/schmitzm/io/BinaryInputStream.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/BinaryInputStream.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -17,6 +17,11 @@
 import java.io.IOException;
 
 /**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
  * <code>BinaryInputStream</code> erweitert die Klasse
  * <code>java.io.DataInputStream</code> um Methoden, mit denen man Werte
  * wahlweise in <i>BigEndian</i> oder <i>LittleEndian</i> aus dem Stream

Modified: trunk/src/schmitzm/io/BinaryUtil.java
===================================================================
--- trunk/src/schmitzm/io/BinaryUtil.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/BinaryUtil.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -17,6 +17,11 @@
 import java.io.EOFException;
 
 /**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
  * Diese Klasse enthaelt statische Methoden, die das Arbeiten mit Binaerstrings
  * erleichtern.
  * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)

Modified: trunk/src/schmitzm/io/CombinedInputStream.java
===================================================================
--- trunk/src/schmitzm/io/CombinedInputStream.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/CombinedInputStream.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -15,6 +15,11 @@
 import java.io.IOException;
 
 /**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
  * Diese Klasse stellt einen Eingabe-Stream dar, der Daten auf Basis
  * mehrerer anderen <code>InputStream</code>-Instanzen liefert. Zunaechst
  * werden Bytes aus dem ersten Stream geliefert, wenn dieser Stream keine

Modified: trunk/src/schmitzm/io/InputBuffer.java
===================================================================
--- trunk/src/schmitzm/io/InputBuffer.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/InputBuffer.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -15,6 +15,11 @@
 import java.io.IOException;
 
 /**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
  * Diese Klasse stellt einen InputStream dar, der sukzessive Bytes
  * aus einem Buffer liefert. Dieser Buffer kann permanent wieder
  * (auf)gefuellt werden. Dazu muss er nicht erst komplett geleert

Added: trunk/src/schmitzm/io/LimitedInputStream.java
===================================================================
--- trunk/src/schmitzm/io/LimitedInputStream.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/LimitedInputStream.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -0,0 +1,97 @@
+/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+
+    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
+    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
+    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
+    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
+ **/
+package schmitzm.io;
+
+import java.io.*;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse repraesentiert einen Eingabe-Stream, der einen anderen
+ * Eingabe-Stream kapselt und auf eine bestimmte Groesse begrenzt.
+ * Somit ist es moeglich, einer Methode "vorzugaukeln" der ihr uebergebene
+ * InputStream habe eine bestimmte Laenge, obwohl er in Wirklichkeit viel
+ * groesser ist.<br>
+ * Der Leser fragt sich nach dem Sinn? :-)<br>
+ * <b>Beispiel:</b><br>
+ * In einem InputStream A stehen nacheinander die Binaer-Repraesentationen
+ * geometrischer Objekte. Die ersten N Bytes gehoeren zum ersten Objekt.<br>
+ * Uebergibt man nun den gesamten Stream an die <code>initFromBinary</code>-Methode,
+ * wuerde diese u.U. nicht nur die ersten N Bytes lesen, sondern versuchen,
+ * den kompletten Stream als Objekt zu interpretieren!!<br>
+ * Uebergibt man der <code>initFromBinary</code>-Methode jedoch einen
+ * <code>LimitedInputStream</code> der auf dem Stream A basiert und auf N
+ * Bytes begrenzt ist, sind die restlichen Bytes von A (die hinter dem N-ten
+ * Byte stehen) fuer die <code>initFromBinary</code>-Methode transparent.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LimitedInputStream extends InputStream {
+  private InputStream input;
+  private int         limit;
+  private int         readCount;
+
+  /**
+   * Erzeugt einen neuen <code>LimitedInputStream</code>.
+   * @param input Basis-Daten
+   * @param limit Maximale Anzahl an Bytes, die aus dem Basis-Stream gelesen
+   *              werden, bevor der <code>LimitedInputStream</code> sein
+   *              Ende erreicht
+   */
+  public LimitedInputStream(InputStream input, int limit) {
+    this.input     = input;
+    this.readCount = 0;
+    setLimit(limit);
+  }
+
+  /**
+   * Liefert das Limit fuer den Stream.
+   */
+  public int getLimit() {
+    return limit;
+  }
+
+  /**
+   * Setzt das Limit fuer den Stream.
+   * @param limit neues Limit (in Bytes)
+   * @exception java.lang.IllegalArgumentException falls <code>limit < 0</code>
+   */
+  public void setLimit(int limit) {
+    if ( limit < 0 )
+      throw new IllegalArgumentException("Limit must be greater or equal 0");
+    this.limit = limit;
+  }
+
+  /**
+   * Liefert die Anzahl an Bytes, die noch aus dem <code>LimitedInputStream</code>
+   * gelesen werden koennen.
+   * @exception java.io.IOException falls der <code>available()</code>-Aufruf
+   *            fuer den Basis-Stream scheitert
+   */
+  public int available() throws IOException {
+    return Math.min(input.available(),Math.max(limit-readCount,0));
+  }
+
+  /**
+   * Liefert ein Byte des Basis-Streams, solange das Limit (oder das Ende
+   * des Basis-Stream) noch nicht erreicht ist.
+   * @exception java.io.IOException falls der <code>read()</code>-Aufruf
+   *            fuer den Basis-Stream scheitert
+   */
+  public int read() throws IOException {
+    if ( available() <= 0 ) return -1;
+    readCount++;
+    return input.read();
+  }
+}
\ No newline at end of file

Added: trunk/src/schmitzm/io/TokenInputStream.java
===================================================================
--- trunk/src/schmitzm/io/TokenInputStream.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/io/TokenInputStream.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -0,0 +1,350 @@
+/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+
+    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
+    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
+    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
+    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
+ **/
+package schmitzm.io;
+
+import java.io.*;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse erweitert einen <code>DataInputStream</code> um die
+ * Eigenschaft des <code>StreamTokenizer</code>
+ * @see java.io.StreamTokenizer
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+
+public class TokenInputStream extends PushbackInputStream {
+  /**
+   * Instanz von <code>DefaultTokenDefinition</code>.
+   * @see adagios.types.TokenInputStream.DefaultTokenDefinition
+   */
+  public static final TokenDefinition DEFAULT_TOKENDEF = new DefaultTokenDefinition();
+
+
+  /**
+   * Signalisiert, dass kein Token mehr gelesen werden konnte, da
+   * das Ende des Basisstreams erreicht wurde.
+   * @see java.io.StreamTokenizer#TT_EOF
+   */
+  public static final int TT_EOF = StreamTokenizer.TT_EOF;
+
+  /**
+   * Signalisiert, dass das gelesene Token numerisch ist und
+   * in <code>nval</code> gespeichert ist.
+   * @see java.io.StreamTokenizer#TT_NUMBER
+   */
+  public static final int TT_NUMBER = StreamTokenizer.TT_NUMBER;
+
+  /**
+   * Signalisiert, dass das gelesene Token alphanumerisch ist und
+   * in <code>sval</code> gespeichert ist.
+   * @see java.io.StreamTokenizer#TT_WORD
+   */
+  public static final int TT_WORD = StreamTokenizer.TT_WORD;
+
+  /**
+   * Enthaelt den Typ des letzten gelesenene Tokens.
+   * @see #TT_EOF
+   * @see #TT_NUMBER
+   * @see #TT_WORD
+   * @see java.io.StreamTokenizer#ttype
+   */
+  public int    ttype = 0;
+
+  /**
+   * Handelt es sich bei dem letzten Token um eine Zeichenkette, wird diese
+   * in <code>sval</code> gespeichtert. Ansonsten ist <code>sval = null</code>.
+   * @see java.io.StreamTokenizer#sval
+   */
+  public String sval  = null;
+
+  /**
+   * Handelt es sich bei dem letzten Token um einen numerischen Wert, wird dieser
+   * in <code>nval</code> gespeichtert. Ansonsten ist <code>nval = 0.0</code>.
+   * @see java.io.StreamTokenizer#nval
+   */
+  public double nval  = 0.0;
+
+  private TokenDefinition def = new DefaultTokenDefinition();
+
+  /**
+   * Erzeugt einen neuen TokenInputStream.
+   * Der Pushback-Buffer wird mit 64Byte initialisiert. Als Tokendefinition wird
+   * <code>DefaultTokenDefinition</code> verwendet.
+   * @param is BasisInputStream
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is) {
+    this(is,64);
+  }
+
+  /**
+   * Erzeugt einen neuen TokenInputStream. Als Tokendefinition wird
+   * <code>DefaultTokenDefinition</code> verwendet.
+   * @param is   BasisInputStream
+   * @param size Groesse des Pushback-Buffers
+   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is, int size) {
+    this(is,size,DEFAULT_TOKENDEF);
+  }
+
+  /**
+   * Erzeugt einen neuen TokenInputStream.
+   * @param is   BasisInputStream
+   * @param size Groesse des Pushback-Buffers
+   * @param def  bestimmt wie die Token aufgebaut sind
+   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
+   * @see adagios.types.TokenInputStream.TokenDefinition
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is, int size, TokenDefinition def) {
+    super(is,size);
+    this.def = def;
+  }
+
+  /**
+   * Liefert einen neuen <code>TokenInputStream</code>.
+   * Handelt es sich bei dem uebergebenen Basis-Stream bereits um einen
+   * <code>TokenInputStream</code> wird dieser (gecastet) zurueckgeliefert,
+   * ansonsten wird eine neue Instanz erzeugt.
+   * @param is Basis-Stream
+   */
+  public static TokenInputStream fromInputStream(InputStream is) {
+    if ( is instanceof TokenInputStream )
+      return (TokenInputStream)is;
+    return new TokenInputStream(is);
+  }
+
+  /**
+   * Liefert die zugrunde liegende Token-Definition.
+   */
+  public TokenDefinition getTokenDefinition() {
+    return def;
+  }
+
+  /**
+   * Liesst ein Token vom Stream. Dabei werden zunaecht alle Delimiter-Zeichen
+   * aus dem Stream gelesen und ignoriert.
+   * Das erste Nicht-Delimiter-Zeichen bestimmt, ob das Token numerisch ist,
+   * oder nicht. Bei numerischen Tokens wird das "Token-Lesen" beim ersten
+   * nicht-numerischen Zeichen abgebrochen. Bei nicht-numerische Tokens erst
+   * beim naechsten Delimiter.<br>
+   * Der Wert des Tokens wird der Variablen <code>sval</code> oder
+   * <code>nval</code> hinterlegt.<br>
+   * Ein (nicht-numerisches) Ein-Zeichen-Token wird direkt als <code>int</code>
+   * im Attribut <code>ttype</code> gespeichert und nicht in <code>sval</code>
+   * (vgl. <code>StreamTokenizer</code>).<br>
+   * <b>Beispiel (Delimiter = " \n\t"):</b><br>
+   * <code>"   abcd456bla   999.99k k88 9,88   "</code> liefert die Token<br>
+   * <ul>
+   * <li><code>sval  = "abcd456bla"</code></li>
+   * <li><code>nval  = 999.99</code></li>
+   * <li><code>sval  = "k"</code></li>
+   * <li><code>sval  = "k88"</code></li>
+   * <li><code>nval  = 9.0</code></li>
+   * <li><code>ttype = ','</code></li>
+   * <li><code>nval  = 88.0</code></li>
+   * </ul>
+   * @return Typ des Tokens (Inhalt von <code>ttype</code>)
+   * @see #ttype
+   * @see #sval
+   * @see #nval
+   * @see StreamTokenizer#ttype
+   * @see StreamTokenizer#nextToken()
+   */
+  public int readToken() throws IOException {
+    char         c            = 999;
+    StringBuffer token        = new StringBuffer();
+
+    // Stream bereits zu Ende
+    if ( available() <= 0 )
+      return determineGlobalVariables("");
+
+    // alle Delimiter-Chars ignorieren
+    while ( available()>0 && def.isDelimiter( c = (char)read() ) );
+    // wenn das letzte gelesene Zeichen ein Delimiter war ist der Stream zu Ende,
+    // ohne dass ein Token gelesen werden kann
+    if ( def.isDelimiter(c) )
+      return determineGlobalVariables("");
+
+    // letztes gelesenes Zeichen gehoert bereits zum Token
+    token.append(c);
+
+    boolean numericToken = false;
+    // handelt es sich um ein Single-Character, wird nicht weitergelesen
+    if ( !def.isSingleChar(c) ) {
+      // ob das Token numerisch ist, bestimmt das erste Zeichen
+      numericToken = def.isNumericStarter(c);
+      // alle Zeichen dem Token hinzufuegen, bis ein Delimiter, ein SingleChar
+      // oder bei numerischen Tokens ein nicht-numerisches Zeichen erreicht wird
+      while ( available()>0 && !def.isDelimiter( c = (char)read() )
+                            && !def.isSingleChar( c )
+                            && (!numericToken || def.isNumeric(c)) ) {
+        token.append(c);
+      }
+      // letztes gelesenes Zeichen ist ein Delimiter oder ein Zeichen, dass
+      // nicht zum Token "passt"
+      // --> dieses muss zurueck auf den Stream
+      unread(c);
+    }
+//    System.err.println("-> "+token.toString());
+
+    return determineGlobalVariables(token.toString());
+  }
+
+  /**
+   * Legt das letzte Token zurueck auf den Stream. Wiederholte Aufrufe legen
+   * das letzte Token mehrmals zurueck auf den Stream!!
+   * Die Methode wird ignoriert, falls den letze Aufruf von
+   * <code>nextToken(..)</code> das Streamende ueberschritten hat.
+   * @return <code>false</code>, falls das letzte Token nicht auf den Stream
+   *         zurueckgelegt werden konnte
+   * @exception java.io.IOException falls das Zuruecklegen der Bytes auf den
+   *            BasisStream scheitert
+   */
+  public boolean pushBack() throws IOException {
+    byte[] b = null;
+    switch (ttype) {
+      case StreamTokenizer.TT_NUMBER: // numerisches Token
+                                      b = String.valueOf(nval).getBytes();
+                                      break;
+      case StreamTokenizer.TT_WORD: // alphanumerisches Token
+                                    b = sval.getBytes();
+                                    break;
+      case StreamTokenizer.TT_EOL: // Token kann nicht rekonstruiert werden
+      case StreamTokenizer.TT_EOF: return false;
+      default: // ein Zeichen
+               b = new byte[] { (byte)ttype };
+    }
+
+    unread(b);
+    return true;
+  }
+
+  /**
+   * Bestimmt den Typ des Tokens (Char, numerisch, alphanumerisch) und
+   * belegt entsprechend die globalen Variablen.
+   * @return neuer Wert von <code>ttype</code>
+   */
+  private int determineGlobalVariables(String token) {
+    // keine Nicht-Delimiter mehr auf dem Stream
+    if (token.length() == 0)
+      return setGlobalVariables(StreamTokenizer.TT_EOF, null, 0.0);
+
+    // ein Ein-Zeichen-Token wird als int im Typ-Feld gespeichert
+    if ( token.length() == 1 && def.isSingleChar(token.charAt(0)) )
+      return setGlobalVariables(token.charAt(0),null,0.0);
+
+    try {
+      // versuchen, dass Token in eine Zahl umzuwandeln
+      return setGlobalVariables(StreamTokenizer.TT_NUMBER,null,Double.parseDouble(token));
+    }
+    catch (Exception err) {
+      // scheitert der Versuch, dass Token in eine Zahl umzuwandeln, handelt
+      // es sich bei dem Token um eine Zeichenkette
+      return setGlobalVariables(StreamTokenizer.TT_WORD,token,0.0);
+    }
+  }
+
+  /**
+   * Belegt die globalen Variablen mit den angegebenen Werten.
+   * @return neuer Wert von <code>ttype</code>
+   */
+  private int setGlobalVariables(int ttype, String sval, double nval) {
+    this.ttype = ttype;
+    this.sval  = sval;
+    this.nval  = nval;
+    return ttype;
+  }
+
+  /**
+   * Diese Klasse bestimmt, wie die Zeichen in einem <code>TokenInputStream</code>
+   * zu Token zusammengefasst werde.
+   */
+  public static interface TokenDefinition {
+    /**
+     * Bestimmt, welche Zeichen "Delimiter" sind. Delimiter-Zeichen trennen
+     * Token voneinander und werden ignoriert.
+     */
+    public boolean isDelimiter(char c);
+
+    /**
+     * Bestimmt, welche Zeichen numerisch sind.<br>
+     * z.B. 0 bis 9 und '.'
+     */
+    public boolean isNumeric(char c);
+
+    /**
+     * Bestimmt, welche Zeichen ein numerisches Token einleiten. Im
+     * Gegensatz zu <code>isNumeric(..)</code> sollten z.B. keine
+     * Kommas oder Punkte als "NumericStarter" deklariert werden.<br>
+     * z.B. 0 bis 9
+     */
+    public boolean isNumericStarter(char c);
+
+    /**
+     * Bestimmt, ob ein Zeichen ein "Einzelnes Zeichen" ist. SingleChars werden
+     * werden nicht zu Token zusammengefasst, sondern immer als eigenes
+     * Token behandelt. SingleChars trennen also auch Token voneinander.
+     */
+    public boolean isSingleChar(char c);
+  }
+
+  /**
+   * Diese Klasse stellt eine Standard-Definition fuer einen
+   * <code>TokenInputStream</code> dar.
+   * @see adagios.types.TokenInputStream
+   * @see adagios.types.TokenInputStream.TokenDefinition
+   */
+  public static class DefaultTokenDefinition implements TokenDefinition {
+    /**
+     * Delimiter sind SPACE ' ', TAB '\t' und CR '\n'.
+     */
+    public boolean isDelimiter(char c) {
+      return c == ' '   // SPACE
+          || c == '\t'  // TAB
+          || c == '\n'; // CR
+    }
+
+    /**
+     * Numerische Token muessen mit '0'..'9' oder '-' beginnen.
+     */
+    public boolean isNumericStarter(char c) {
+      return c >= '0' && c <= '9' || c == '-';
+    }
+
+    /**
+     * Numerische Zeichen sind NumericStarter oder Punkt.
+     */
+    public boolean isNumeric(char c) {
+      return isNumericStarter(c) || c == '.';
+    }
+
+    /**
+     * SingleChars sind Komma, Semikolon, Plus, Minus, Gleich, Slash,
+     * BackSlash, Doppelpunkt, Pipe, runde Klammern, eckige Klammern und
+     * geschweifte Klammern.
+     */
+    public boolean isSingleChar(char c) {
+      return c == ',' || c == ';'
+          || c == '+'  || c == '=' || c == '/'
+          || c == ':' || c == '\\' || c == '|'
+          || c == '(' || c == ')'  || c == '[' || c == ']'
+          || c == '{' || c == '}';
+    }
+  }
+}
\ No newline at end of file

Added: trunk/src/schmitzm/swing/MultiSplitPane.java
===================================================================
--- trunk/src/schmitzm/swing/MultiSplitPane.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/swing/MultiSplitPane.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -0,0 +1,704 @@
+/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+
+    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
+    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
+    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
+    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
+ **/
+package schmitzm.swing;
+
+import java.awt.Container;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.BorderLayout;
+import javax.swing.JSplitPane;
+import javax.swing.JComponent;
+import javax.swing.border.Border;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Ein <code>MultiSplitPane</code> ist eine Menge von horizontal oder
+ * vertikal angeordneten Containern.<br>
+ * Die Groesse dieser <code>Container</code> kann durch den Benutzer manuell
+ * veraendert werden, in dem er die Trennlinien ("Dividers") zwischen den
+ * Containern verschiebt.<br>
+ * Das <code>MultiSplitPane</code> ist implementiert als eine baumartige
+ * Verschachtelung von <code>JSplitPane</code>-Objekten, in denen immer
+ * genau zwei Komponenten hinterlegt werden koennen.<br>
+ * Aus diesem Grund kann die Darstellung der Randbereiche recht
+ * unregelmaessig erscheinen. Deshalb ist es sinnvoll, den Rand entweder
+ * komplett auszuschalten (<code>setInnerBorder(null)</code>), oder einen
+ * unsichtbaren Rand zu verwenden (<code>setInnerBorder( new EmptyBorder(..) )</code>.
+ * Dies gilt vor allem, wenn man ein <code>MultiSplitPane</code> mit vielen
+ * Containern verwendet (mehr als 6 oder 7).
+ * @see javax.swing.JSplitPane
+ * @see javax.swing.JComponent
+ * @see #setInnerBorder(Border)
+ * @see javax.swing.border.EmptyBorder
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class MultiSplitPane extends JComponent {
+
+  public static final int HORIZONTAL_SPLIT = JSplitPane.HORIZONTAL_SPLIT;
+  public static final int VERTICAL_SPLIT   = JSplitPane.VERTICAL_SPLIT;
+
+  private Container[]    container     = null;
+  private SplitPaneTree  rootSplitPane = null;
+  private int            orientation   = HORIZONTAL_SPLIT;
+  private int            dividerSize   = 0;
+  private Border         innerBorder   = new JSplitPane().getBorder();
+
+  /**
+   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
+   * 2 Containern bestehen. Diese werden horizontal angeordnet.
+   * @param compCount   Anzahl an Containern im MultiSplitPane
+   * @exception java.lang.IllegalArgumentException falls die
+   *            Container-Anzahl < 2 ist.
+   */
+  public MultiSplitPane(int compCount) {
+    this(compCount,HORIZONTAL_SPLIT);
+  }
+
+  /**
+   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
+   * 2 Containern bestehen. Moegliche Orientierungen:
+   * <ul>
+   * <li><code>HORIZONTAL_SPLIT</code></li>
+   * <li><code>VERTICAL_SPLIT</code></li>
+   * </ul>
+   * @param compCount   Anzahl an Containern im MultiSplitPane
+   * @param orientation Orientierung des MultiSplitPane
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist oder die Container-Anzahl < 2 ist.
+   */
+  public MultiSplitPane(int compCount, int orientation) {
+    super();
+    this.setLayout( new BorderLayout() );
+
+    if (compCount < 2)
+      throw new IllegalArgumentException("MultiSplitPane must have at least 2 Components");
+    // erstmal nur die Orientierung checken, setzen folgt nachdem
+    // der SplitPaneTree aufgebaut ist
+    checkOrientation(orientation);
+
+    // Referenz auf die Container (der Effizienz wegen) nochmal
+    // in einer Liste speichern
+    container = new Container[compCount];
+    for (int i=0; i<container.length; i++) {
+      container[i] = new Container();
+      container[i].setLayout( new BorderLayout() );
+    }
+    rootSplitPane = new SplitPaneTree(container);
+    // Orientierung setzen
+    setOrientation(orientation);
+    // Basis-SplitPane im Haupt-Container einfuegen
+    this.add(rootSplitPane.getSplitPane());
+  }
+
+  /**
+   * Liefert die Anzahl an Komponenten, in die das SplitPane aufgeteilt ist.
+   */
+  public int getContainerCount() {
+    return container.length;
+  }
+
+  /**
+   * Liefert den Inhalt eine Teil-Panes.
+   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   */
+  public Container getContainer(int i) {
+    return container[i];
+  }
+
+  /**
+   * Setzt den Inhalt eine Teil-Panes.
+   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @param cont neuer Inhalt des Teil-Panes
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   */
+  public void setContainer(int i, Container cont) {
+    this.container[i] = cont;
+    rootSplitPane.setContainer(i,cont);
+  }
+
+  /**
+   * Liefert die Orientierung in der die Container des MultiSplitPanes
+   * angeordnet sind.
+   * @see #setOrientation(int)
+   */
+  public int getOrientation() {
+    return this.orientation;
+  }
+
+  /**
+   * Aendert die Orientierung des SplitPanes. Moegliche
+   * Orientierungen:
+   * <ul>
+   * <li><code>HORIZONTAL_SPLIT</code></li>
+   * <li><code>VERTICAL_SPLIT</code></li>
+   * </ul>
+   * @param orientation neue Orientierung
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist
+   * @see #getOrientation()
+   */
+  public void setOrientation(int orientation) {
+    checkOrientation(orientation);
+
+    final int o = orientation;
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setOrientation(o);
+            }
+        }
+    );
+    this.orientation = orientation;
+  }
+
+  /**
+   * Checkt, ob die angegebene Orientierung gueltig ist. Andernfalls wird
+   * eine Exception geworfen.
+   * @param orientation Orientierung
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist
+   */
+  protected void checkOrientation(int orientation) {
+    if (orientation != HORIZONTAL_SPLIT &&
+        orientation != VERTICAL_SPLIT)
+      throw new IllegalArgumentException("HORIZONTAL_SPLIT or VERTICAL_SPLIT expected!!");
+  }
+
+  /**
+   * Liefert die Groesse des Dividers (in Pixeln).
+   */
+  public int getDividerSize() {
+    return dividerSize;
+  }
+
+  /**
+   * Setzt die Groesse der Divider-Balken. Die Darstellung des "laestigen"
+   * einpixligen Strichs laesst sich zwar verhindern, indem man die
+   * Divider-Groesse auf 0 setzt, leider sind dann aber auch die Groessen der
+   * einzelnen Container nicht mehr veraenderbar!!
+   * @param size Groesse in Pixeln
+   * @see #getDividerSize()
+   */
+  public void setDividerSize(int size) {
+    final int s = size;
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setDividerSize(s);
+            }
+        }
+    );
+    this.dividerSize = size;
+  }
+
+  /**
+   * Liefert das gesetzte Gewicht eines Containers, mit dessen Anteil
+   * dieser bei einer Platzvergroesserung beruecksichtigt wird.
+   * @param i Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   * @see #setResizeWeigth(double[])
+   */
+  public double getResizeWeight(int i) {
+    // Teilbaum (JSplitPane) suchen, in dem der Container mit
+    // dem Index i abgelegt ist
+    SplitPaneTree tree = rootSplitPane.getSplitPaneTree(i);
+
+    // ResizeWeight-Anteil des SplitPanes
+    double splitPaneWeight = tree.getResizeWeight();
+    // Gewicht der linken Komponente (bezogen auf das eine SplitPane)
+    double weight = tree.getSplitPane().getResizeWeight();
+    // liegt der gesuchte Container im rechten Teil-Pane,
+    // muss das Gegengewicht genommen werden
+    if ( tree.getSplitPane().getLeftComponent() != getContainer(i) )
+      weight = 1 - weight;
+
+    return weight * splitPaneWeight;
+  }
+
+  /**
+   * Liefert die Gewichte aller Containers, mit deren Anteil diese bei
+   * einer Platzvergroesserung beruecksichtigt werden.
+   * @see #getResizeWeight(int)
+   * @see #setResizeWeigth(double[])
+   */
+  public double[] getResizeWeight() {
+    double[] weight = new double[ getContainerCount() ];
+    for (int i=0; i<weight.length; i++)
+      weight[i] = getResizeWeight(i);
+    return weight;
+  }
+
+  /**
+   * Setzt die Container-Gewichtungen, mit deren Anteil diese bei einer
+   * Platzvergroesserung beruecksichtigt werden. Bei der Angabe der
+   * Gewichte sind folgende Punkte zu beachten:
+   * <ul>
+   * <li>Die Summe der angegebenen Gewichte darf 1 nicht ueberschreiten.</li>
+   * <li>Es duerfen hoechstens so viele Gewichte angegeben werden, wie
+   *     Container im <code>MultiSplitPane</code> vorhanden sind.</li>
+   * <li>Werden genau so viele Gewichte angegeben, wie Container im
+   *     <code>MultiSplitPane</code> vorhanden sind, muss die Summe der
+   *     Gewichte 1 ergeben</li>
+   * <li>Werden weniger Gewichte als vorhandene Container angegeben, so wird
+   *     das restliche Gewicht gleichmaessig auf die uebrigen Container
+   *     verteilt.</li>
+   * </ul>
+   * @param weight neue Gewichte
+   * @exception java.lang.IllegalArgumentException falls eine der obigen
+   *            Bedingungen verletzt ist.
+   */
+  public void setResizeWeigth(double[] weight) {
+    if ( weight.length > getContainerCount() )
+      throw new IllegalArgumentException("Es duerfen hoechstens so viele Gewichte, wie Container angegeben werden!");
+
+    // Gewichte in einen Array kopieren, dessen Groesse genau der
+    // Anzahl an Containern entspricht
+    final double[] newWeight = new double[ getContainerCount() ];
+          double   weightSum = 0.0;
+
+    for (int i=0; i<newWeight.length; i++) {
+      if ( i<weight.length ) {
+        weightSum += weight[i]; // Gewichtssumme ermitteln
+        if ( weightSum > 1.0 )
+          throw new IllegalArgumentException("Die angegebnene Summe der Gewichte ist groesser als 1!!");
+        newWeight[i] = weight[i]; // vorhandenes Gewicht kopieren
+      }
+      else {
+        // Bei Angabe von zu wenig Gewichten, wird der Rest "gerecht"
+        // verteilt
+        newWeight[i] = (1-weightSum) / (newWeight.length - weight.length);
+      }
+    }
+
+    if ( weight.length == newWeight.length && weightSum < 1 )
+      throw new IllegalArgumentException("Werden Gewichte fuer alle Container angegeben, muss deren Summe 1 ergeben!!");
+
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            private int contCounter = 0;
+
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              // Beinhaltet das SplitPane einen (finalen) Container
+              // wird dessen neues Gewicht genommen, ansonsten das
+              // Gewicht des gesamten Teilbaums (dieses ist aufgrund
+              // des POSTORDER-Druchlaufs bereits neu berechnet!!)
+              double lWeight = ( !tree.isSplittedLeft() )  ? newWeight[contCounter++] : tree.getLeftResizeWeight();
+              double rWeight = ( !tree.isSplittedRight() ) ? newWeight[contCounter++] : tree.getRightResizeWeight();
+              // neues Gewicht fuer den Teilbaum neu setzen
+              tree.setResizeWeight( lWeight + rWeight );
+              // neues Gewicht fuer das Root-SplitPane des Teilbaum neu setzen
+              tree.getSplitPane().setResizeWeight( lWeight / tree.getResizeWeight() );
+            }
+        });
+  }
+
+  /**
+   * Liefert die Border des <code>MultiSplitPane</code>
+   */
+  public Border getInnerBorder() {
+    return this.innerBorder;
+  }
+
+  /**
+   * Setzt die Border fuer alle Container.
+   */
+  public void setInnerBorder(final Border border) {
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setBorder(border);
+            }
+        });
+    this.innerBorder = border;
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///// Interface   SplitPaneTreePerformer                            /////
+  /////////////////////////////////////////////////////////////////////////
+  private interface SplitPaneTreePerformer {
+    public void performSplitPaneTree(SplitPaneTree tree);
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///// Klasse   SplitPaneTree                                        /////
+  /////////////////////////////////////////////////////////////////////////
+  private class SplitPaneTree {
+    private JSplitPane    splitPane    = null;
+    private int           contCount    = 0;
+    private SplitPaneTree leftTree     = null;
+    private SplitPaneTree rightTree    = null;
+    private double        resizeWeight = 0.0;
+
+    /**
+     * Interner Konstruktor zum Initialisieren ALLER Variablen.
+     */
+    private void init(JSplitPane splitPane, int contCount, double weight, SplitPaneTree left, SplitPaneTree right) {
+      this.splitPane    = splitPane;
+      this.contCount    = contCount;
+      this.resizeWeight = weight;
+      this.leftTree     = left;
+      this.rightTree    = right;
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
+     * sowohl links, als auch rechts weiter geplittet ist.
+     */
+    private void initInner(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
+      init(splitPane,left.getContainerCount()+right.getContainerCount(),weight,left,right);
+    }
+
+    /**
+     * Erzeugt einen neuen (Teil-)Baum, der sowohl links, als auch rechts
+     * weiter gesplittet ist. Beide Teil-Panes sind also weiter unterteilt.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     * @param left      linker Teilbaum
+     * @param right     rechter Teilbaum
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
+      initInner(splitPane,weight,left,right);
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines Blattes.
+     */
+    private void initLeaf(JSplitPane splitPane, double weight) {
+      init(splitPane,2,weight,null,null);
+    }
+
+    /**
+     * Erzeugt ein neues Blatt. Beide Teil-Panes enthalten also einen
+     * <code>Container</code> und sind nicht weiter gesplittet.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight) {
+      initLeaf(splitPane,weight);
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
+     * links gesplittet ist und rechts ein Blatt hat.
+     */
+    private void initHalfLeaf(JSplitPane splitPane, double weight, SplitPaneTree left) {
+      init(splitPane,left.getContainerCount()+1,weight,left,null);
+    }
+
+    /**
+     * Erzeugt einen neuen (Teil-)Baum, der nach links gesplittet ist und rechts
+     * endet ("Halb-Blatt"). Das linke Teil-Pane ist also weiter unterteilt, waehrend im
+     * rechten Teil-Pane ein <code>Container</code> zu finden ist.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     * @param left      linker Teilbaum
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left) {
+      initHalfLeaf(splitPane,weight,left);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     * @param start     Index im <code>Container</code>-Array, bei dem
+     *                  begonnen wird (alle davor werden ignoriert)
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(Container[] container, int start, int count, double weight) {
+//  System.out.println(start+"\t"+count+"\t"+weight);
+      if ( count < 2 )
+        throw new IllegalArgumentException("SplitPane must have at least 2 Containers");
+
+      if ( start + count -1 >= container.length )
+        throw new IllegalArgumentException("'count' too big for this start position in Container-Array");
+
+      this.splitPane = new JSplitPane();
+
+      // Aufteilung ermitteln
+      int rightCount  = count / 2;
+      int leftCount   = count - rightCount;
+      // Vergroesserungs-Gewichte ermitteln:
+      // --> Entsprechend der Aufteilung erhalten die beiden Teil-Panes
+      //     einen Anteil am Gesamt-Gewicht des SplitPanes
+      double rightWeight = weight/count * rightCount;
+      double leftWeight  = weight/count * leftCount;
+
+      // bei nur 2 Teil-Panes wird nicht mehr weiter gesplitten
+      // --> Blatt erzeugen
+      if ( leftCount == 1 && rightCount == 1 )
+        initLeaf(splitPane,weight);
+
+      // nur das linke Teil-Pane wird weitergesplittet
+      // --> Halb-Blatt erzeugen
+      if ( leftCount > 1 && rightCount == 1)
+        initHalfLeaf(splitPane,weight,new SplitPaneTree(container,start,leftCount,leftWeight));
+
+      // beider Teil-Panes werden weitergesplittet
+      // --> Inneren Knoten erzeugen
+      if ( leftCount > 1 && rightCount > 1)
+        initInner(splitPane,weight, new SplitPaneTree(container,start,leftCount,leftWeight),
+                                    new SplitPaneTree(container,start+leftCount,rightCount,rightWeight) );
+
+      // Das Split-Pane initialisieren, fuer das dieser Knoten steht
+//  System.out.println(start+"\t"+count+"\t"+isSplittedLeft()+"\t"+isSplittedRight());
+      if ( this.isSplittedLeft() )
+        this.splitPane.setLeftComponent( this.getLeftTree().getSplitPane() );
+      else
+        this.splitPane.setLeftComponent( container[ start ] );
+
+      if ( this.isSplittedRight() )
+        this.splitPane.setRightComponent( this.getRightTree().getSplitPane() );
+      else
+        this.splitPane.setRightComponent( container[ start+count-1 ] );
+
+      this.splitPane.setResizeWeight(leftWeight/weight);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     * @param start     Index im <code>Container</code>-Array, bei dem
+     *                  begonnen wird (alle davor werden ignoriert)
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(Container[] container, int start, double weight) {
+      this(container,start,container.length - start,weight);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     */
+    public SplitPaneTree(Container[] container) {
+      this(container,0,1.0);
+    }
+
+    /**
+     * Liefert das <code>JSplitPane</code> fuer das der Knoten steht.
+     */
+    public JSplitPane getSplitPane() {
+      return splitPane;
+    }
+
+    /**
+     * Liefert die Anzahl an Containern, die im Teil-Baum vorhanden sind.
+     */
+    public int getContainerCount() {
+      return contCount;
+    }
+
+    /**
+     * Checkt, ob das linke (obere) Teil-Pane wiederum gesplittet ist
+     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
+     */
+    public boolean isSplittedLeft() {
+      return getLeftTree() != null;
+    }
+
+    /**
+     * Liefert den linken Teilbaum des aktuellen Knoten.
+     * @return <code>null</code>, falls das linke (obere) Teil-Pane einen
+     *         Container enthaelt und nicht weiter gesplittet ist.
+     */
+    public SplitPaneTree getLeftTree() {
+      return leftTree;
+    }
+
+    /**
+     * Checkt, ob das rechte (untere) Teil-Pane wiederum gesplittet ist
+     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
+     */
+    public boolean isSplittedRight() {
+      return getRightTree() != null;
+    }
+
+    /**
+     * Liefert den rechten Teilbaum des aktuellen Knoten.
+     * @return <code>null</code>, falls das rechte (untere) Teil-Pane einen
+     *         Container enthaelt und nicht weiter gesplittet ist.
+     */
+    public SplitPaneTree getRightTree() {
+      return rightTree;
+    }
+
+    /**
+     * Aendert den Gesamt-Anteil am neuen Platz, den die Container im (Teil-Baum)
+     * erhalten.<br>
+     * <b>Diese Methode sollte nur in einem kontrollierten Durchlauf durch
+     * alle Teilbaeume verwendet werden, in dem gewaehrleistet ist, dass
+     * mit der Aenderung des Gewichts auch die Gewichte der anderen Teilbaeume
+     * korrekt abgeaendert werden!! Die macht diese Methode naemlich
+     * <u>nicht</u> automatisch!!</b>
+     */
+    public void setResizeWeight(double weight) {
+      this.resizeWeight = weight;
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im (Teil-)Baums liegen.
+     */
+    public double getResizeWeight() {
+      return resizeWeight;
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im linken Teil-Baum (also im linken/oberen Teil-Pane) liegen.
+     */
+    public double getLeftResizeWeight() {
+      if ( isSplittedLeft() ) return getLeftTree().getResizeWeight();
+      return getSplitPane().getResizeWeight() * getResizeWeight();
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im rechten Teil-Baum (also im rechten/unteren Teil-Pane) liegen.
+     */
+    public double getRightResizeWeight() {
+      if ( isSplittedRight() ) return getRightTree().getResizeWeight();
+      return (1-getSplitPane().getResizeWeight()) * getResizeWeight();
+    }
+
+    /**
+     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
+     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
+     * @param i Nummer des Containers
+     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
+     *            nicht genug Container vorhanden sind
+     */
+    public Container getContainer(int i) {
+      if ( i>= getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum
+      // --> also Container im linken Teil-Pane ist der gesuchte
+      if ( i == 0 && leftCount == 0 )
+        return (Container)splitPane.getLeftComponent();
+      // letzter Container gesucht und kein rechter Teilbaum
+      // --> also Container im rechten Teil-Pane ist der gesuchte
+      if ( i == getContainerCount()-1 && rightCount == 0 )
+        return (Container)splitPane.getRightComponent();
+      // gesuchter Container liegt im linken Teil-Pane
+      if ( i < leftCount )
+        return getLeftTree().getContainer(i);
+      // gesuchter Container liegt im rechten Teil-Pane
+      return getRightTree().getContainer(i-leftCount);
+    }
+
+    /**
+     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
+     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
+     * @param i Nummer des Containers
+     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
+     *            nicht genug Container vorhanden sind
+     */
+    public void setContainer(int i, Container cont) {
+      if ( i>= getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum
+      // --> also Container im linken Teil-Pane ist der gesuchte
+      if ( i == 0 && leftCount == 0 )
+        splitPane.setLeftComponent(cont);
+      else
+        // letzter Container gesucht und kein rechter Teilbaum
+        // --> also Container im rechten Teil-Pane ist der gesuchte
+        if ( i == getContainerCount()-1 && rightCount == 0 )
+          splitPane.setRightComponent(cont);
+        else
+          // gesuchter Container liegt im linken Teil-Pane
+          if ( i < leftCount )
+            getLeftTree().setContainer(i,cont);
+          else
+            // gesuchter Container liegt im rechten Teil-Pane
+            getRightTree().setContainer(i-leftCount,cont);
+    }
+
+    /**
+     * Liefert das <code>JSplitPane</code> in dessen linker oder rechter
+     * (bzw. oberer oder unterer) Komponente der i-te Container gespeichert
+     * ist (Zaehlung beginnt bei 0!!).
+     * @exception java.lang.ArrayIndexOutOfBoundsException falls in dem
+     *            (Teil-)Baum weniger als i+1 Container gespeichert sind
+     */
+    public SplitPaneTree getSplitPaneTree(int i) {
+      if ( i>=getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum ODER
+      // letzter Container gesucht und kein rechter Teilbaum
+      // --> gesuchter Container liegt im aktuellen SplitPane
+      if ( i == 0                     && leftCount == 0 ||
+           i == getContainerCount()-1 && rightCount == 0)
+        return this;
+
+      // gesuchter Container liegt im linken Teil-Pane
+      if ( i < leftCount )  return getLeftTree().getSplitPaneTree(i);
+
+      // gesuchter Container liegt im rechten Teil-Pane
+      return getRightTree().getSplitPaneTree(i-leftCount);
+    }
+
+    /**
+     * Aendert rekursiv alle SplitPanes (in einem Post-Order-Durchlauf).
+     * Was an den SplitPanes geaendert wird, bestimmt der <code>SplitPaneTreePerformer</code>.
+     * @param performer bestimmt die Verarbeitung der SplitPanes
+     */
+    public void performAllSplitPanes(SplitPaneTreePerformer performer) {
+      if ( isSplittedLeft() )
+        getLeftTree().performAllSplitPanes( performer );
+      if ( isSplittedRight() )
+        getRightTree().performAllSplitPanes( performer );
+      // Orientierung des SplitPanes setzen
+      performer.performSplitPaneTree(this);
+    }
+
+  }
+}
+
+

Added: trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java
===================================================================
--- trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java	2009-03-06 13:21:33 UTC (rev 27)
+++ trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java	2009-03-11 12:25:42 UTC (rev 28)
@@ -0,0 +1,164 @@
+/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+
+    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
+    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
+    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
+    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
+ **/
+package schmitzm.swing.menu;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import java.util.Vector;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse erweitert das <code>JPopupMenu</code>.
+ * Menueeintraege (Instanzen von <code>JMenuItem</code>) werden automatisch
+ * in der <code>add(String)</code>-Methode erzeugt und dem Menue hinzugefuegt.
+ * Es muss nicht jedem Menueeintragen einzeln ein eigener <code>ActionListener</code>
+ * hinzugefuegt werden, um auf eine Aktion zu reagieren. Das
+ * <code>ConnectedPopupMenu</code> selbst "achtet" auf eine Aktion und
+ * informiert ueber <b>einen</b> <code>ActionListener</code> die verbundenen
+ * Anwendungen. In deren <code>actionPerformed(..)</code>-Methode kann die
+ * Anwendung ueber <code>getProcessedItem()</code> ermittelt werden, welcher
+ * Menueeintrag gewaehlt wurde.
+ * @see javax.swing.JPopupMenu
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class ConnectedPopupMenu extends JPopupMenu implements MouseListener, ActionListener {
+  private Object popupClickSource = null;
+  private Vector listeners        = new Vector();
+  private int    processedItem    = -1;
+
+  /**
+   * Fuegt dem Menue einen <code>ActionListener</code> hinzu.
+   * Dieser wird informiert, sobald ein Menueeintrag des PopupMenue
+   * ausgewaehlt wurde.
+   */
+  public void addActionListener(ActionListener listener) {
+    listeners.add( listener );
+  }
+
+  /**
+   * Entfernt einen <code>ActionListener</code>.
+   */
+  public void removeActionListener(ActionListener listener) {
+    listeners.remove( listener );
+  }
+
+  /**
+   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
+   * verbundene Komponente gedrueckt wurde.
+   * Die Methode checkt, ob es sich bei dem Klick um einen PopupTrigger
+   * (i.A. Rechtsklick) handelt.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  public void mousePressed(MouseEvent e) {
+    checkPopupSignal(e);
+  }
+
+  /**
+   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
+   * verbundene Komponente losgelassen wurde.
+   * Die Methode checkt, ob es sich bei dem Loslassen um einen PopupTrigger
+   * (i.A. Rechtsklick) handelt.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  public void mouseReleased(MouseEvent e) {
+    checkPopupSignal(e);
+  }
+
+  /**
+   * Checkt, ob ein PopupTrigger (i.A. Rechtsklick) auf eine mit dem
+   * PopupMenue verbundene Komponente stattgefunden hat.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  private void checkPopupSignal(MouseEvent e) {
+    if ( e.isPopupTrigger() ) {
+      this.show( (Component)e.getSource(), e.getX(), e.getY() );
+      popupClickSource = e.getSource();
+      e.consume();
+    }
+  }
+
+  /**
+   * Liefert den Index des Menueeintrags, der ausgewaehlt wurde.
+   * Ist nur zugaenglich, waehrend ein <code>ActionListerner</code> ueber
+   * die Auswahl eines Menueeintrags informiert wird!! Zu allen anderen
+   * Zeitpunkten liefert diese Methode -1.
+   */
+  public int getProcessedItem() {
+    return processedItem;
+  }
+
+  /**
+   * Checkt, auf welchen Menueeintrag geklickt wurde und informiert die
+   * angeschlossenen <code>ActionListener</code> ueber das Ereignis.<br>
+   * Diese koennen (in ihrer <code>actionPerformed</code>-Methode ueber die
+   * Methode <code>getProcessedItem()</code> ermitteln, auf welchen
+   * Menueeintrag geklickt wurde.<br>
+   * Das an die <code>ActionListener</code> weiter gereichte
+   * <code>ActionEvent</code> erhaelt als Quelle (<code>getSource()</code>)
+   * dasjenige Objekt, auf dem das PopupMenue (mittels Linksklick)
+   * geoeffnet wurde (nicht das <code>ConnectedPopupMenu</code>!!)
+   * @see #addMouseListener(MouseListener)
+   */
+  public void actionPerformed(ActionEvent e) {
+    // herausfinden, weches Menueitem geklickt wurde
+    for (int i=0; i<this.getComponentCount(); i++) {
+      if ( this.getComponent(i) == e.getSource() ) {
+        processedItem = i;
+        for (int j=0; j<listeners.size(); j++)
+          ((ActionListener)listeners.elementAt(j)).actionPerformed( new ActionEvent( popupClickSource, e.getID(), "" ) );
+        processedItem = -1;
+        break;
+      }
+    }
+  }
+
+  /**
+   * Verbindet das Popup-Menue mit einer Komponente.
+   * Beim (Rechts-)Klick auf diese Komponente wird das Popup-Menue geoeffnet.
+   */
+  public void connectTo(Component comp) {
+    comp.addMouseListener(this);
+  }
+
+  /**
+   * Erzeugt einen Menueeintrag und fuegt ihn dem Menue hinzu.
+   * Als <code>ActionListener</code> fuer den Menueeintrag wird die
+   * <code>ConnectedPopupMenue</code>-Instanz selbst verwendet, welcher
+   * wiederum die angeschlossenen <code>ActionListener</code> informiert.
+   * @param desc Beschreibung fuer den Menueeintrag
+   * @see #actionPerformed(ActionEvent)
+   */
+  public JMenuItem add(String desc) {
+    JMenuItem item = super.add(desc);
+    item.addActionListener(this);
+    return item;
+  }
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseClicked(MouseEvent e) {}
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseEntered(MouseEvent e) {}
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseExited(MouseEvent e) {}
+}
\ No newline at end of file



More information about the Schmitzm-commits mailing list