/[schmitzm]/trunk/src/skrueger/geotools/XMapPane.java
ViewVC logotype

Diff of /trunk/src/skrueger/geotools/XMapPane.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/src/org/geotools/gui/swing/JMapPane.java revision 127 by mojays, Sat May 30 14:29:58 2009 UTC branches/1.0-gt2-2.6/src/org/geotools/gui/swing/JMapPane.java revision 341 by alfonx, Mon Aug 31 10:16:40 2009 UTC
# Line 58  import java.util.Map; Line 58  import java.util.Map;
58  import javax.swing.JPanel;  import javax.swing.JPanel;
59    
60  import org.apache.log4j.Logger;  import org.apache.log4j.Logger;
 import org.geotools.feature.FeatureCollection;  
 import org.geotools.filter.IllegalFilterException;  
 import org.geotools.gui.swing.event.HighlightChangeListener;  
 import org.geotools.gui.swing.event.HighlightChangedEvent;  
 import org.geotools.gui.swing.event.SelectionChangeListener;  
 import org.geotools.gui.swing.event.SelectionChangedEvent;  
 import org.geotools.map.DefaultMapContext;  
61  import org.geotools.map.MapContext;  import org.geotools.map.MapContext;
 import org.geotools.map.MapLayer;  
62  import org.geotools.map.event.MapLayerListEvent;  import org.geotools.map.event.MapLayerListEvent;
63  import org.geotools.map.event.MapLayerListListener;  import org.geotools.map.event.MapLayerListListener;
 import org.geotools.referencing.crs.DefaultGeographicCRS;  
64  import org.geotools.renderer.GTRenderer;  import org.geotools.renderer.GTRenderer;
65    import org.geotools.renderer.label.LabelCacheImpl;
66  import org.geotools.renderer.lite.LabelCache;  import org.geotools.renderer.lite.LabelCache;
 import org.geotools.renderer.lite.LabelCacheDefault;  
67  import org.geotools.renderer.lite.StreamingRenderer;  import org.geotools.renderer.lite.StreamingRenderer;
68    import org.geotools.renderer.shape.TransitionShapefileRenderer;
69  import org.geotools.styling.Graphic;  import org.geotools.styling.Graphic;
70  import org.geotools.styling.LineSymbolizer;  import org.geotools.styling.LineSymbolizer;
71  import org.geotools.styling.Mark;  import org.geotools.styling.Mark;
72  import org.geotools.styling.PointSymbolizer;  import org.geotools.styling.PointSymbolizer;
73  import org.geotools.styling.PolygonSymbolizer;  import org.geotools.styling.PolygonSymbolizer;
 import org.geotools.styling.Style;  
74  import org.geotools.styling.StyleBuilder;  import org.geotools.styling.StyleBuilder;
75  import org.geotools.styling.StyleFactory;  import org.geotools.styling.StyleFactory;
 import org.opengis.filter.Filter;  
76  import org.opengis.filter.FilterFactory2;  import org.opengis.filter.FilterFactory2;
77  import org.opengis.referencing.crs.CoordinateReferenceSystem;  import org.opengis.referencing.crs.CoordinateReferenceSystem;
78    
# Line 90  import schmitzm.swing.SwingUtil; Line 80  import schmitzm.swing.SwingUtil;
80    
81  import com.vividsolutions.jts.geom.Coordinate;  import com.vividsolutions.jts.geom.Coordinate;
82  import com.vividsolutions.jts.geom.Envelope;  import com.vividsolutions.jts.geom.Envelope;
 import com.vividsolutions.jts.geom.Geometry;  
83  import com.vividsolutions.jts.geom.GeometryFactory;  import com.vividsolutions.jts.geom.GeometryFactory;
84    
85  public class JMapPane extends JPanel implements MouseListener,  public class JMapPane extends JPanel implements MouseListener,
86          MouseMotionListener, HighlightChangeListener,SelectionChangeListener, PropertyChangeListener,                  MouseMotionListener, PropertyChangeListener, MapLayerListListener {
87          MapLayerListListener {          private static Logger LOGGER = Logger.getLogger(JMapPane.class.getName());
     private static Logger LOGGER = Logger.getLogger( JMapPane.class.getName() );  
    /**  
      *  
      */  
     private static final long serialVersionUID = -8647971481359690499L;  
88    
89      public static final int Reset = 0;          private static final long serialVersionUID = -8647971481359690499L;
90    
91      public static final int ZoomIn = 1;          public static final int Reset = 0;
92    
93      public static final int ZoomOut = 2;          public static final int ZoomIn = 1;
94    
95      public static final int Pan = 3;          public static final int ZoomOut = 2;
96    
97      public static final int Select = 4;          public static final int Pan = 3;
98    
99      private static final int POLYGON = 0;          public static final int Select = 4;
100    
101      private static final int LINE = 1;          private static final int POLYGON = 0;
102    
103      private static final int POINT = 2;          private static final int LINE = 1;
104    
105      /**          private static final int POINT = 2;
      * what renders the map  
      */  
     GTRenderer renderer;  
106    
107      private GTRenderer highlightRenderer, selectionRenderer;          /**
108             * what renders the map
109             */
110            GTRenderer renderer;
111    
112      /**          private GTRenderer highlightRenderer, selectionRenderer;
      * the map context to render  
      */  
     MapContext context;  
113    
114      private MapContext selectionContext;          /**
115             * the map context to render
116             */
117            MapContext context;
118    
119      /**          private MapContext selectionContext;
      * the area of the map to draw  
      */  
 //xulu.sc  
 //    Envelope mapArea;  
     protected Envelope mapArea;  
 //xulu.ec  
120    
121      /**          /**
122       * the size of the pane last time we drew           * the area of the map to draw
123       */           */
124  //xulu.sc          // xulu.sc
125  //    private Rectangle oldRect = null;          // Envelope mapArea;
126      protected Rectangle oldRect = null;          protected Envelope mapArea;
127  //xulu.ec          // xulu.ec
128    
129      /**          /**
130       * the last map area drawn.           * the size of the pane last time we drew
131       */           */
132  //xulu.sc          // xulu.sc
133  //    private Envelope oldMapArea = null;          // private Rectangle oldRect = null;
134      protected Envelope oldMapArea = null;          protected Rectangle oldRect = null;
135  //xulu.ec          // xulu.ec
136    
137      /**          /**
138       * the base image of the map           * the last map area drawn.
139       */           */
140      protected  BufferedImage baseImage, panningImage;          // xulu.sc
141      // SK: private BufferedImage baseImage, panningImage;          // private Envelope oldMapArea = null;
142            protected Envelope oldMapArea = null;
143            // xulu.ec
144    
145      /**          /**
146       * image of selection           * the base image of the map
147       */           */
148      private BufferedImage selectImage;          protected BufferedImage baseImage, panningImage;
149            // SK: private BufferedImage baseImage, panningImage;
150    
151      /**          /**
152       * style for selected items           * a factory for filters
153       */           */
154      private Style selectionStyle;          FilterFactory2 ff;
155    
156      /**          /**
157       * layer that selection works on           * a factory for geometries
158       */           */
159      private MapLayer selectionLayer;          GeometryFactory gf = new GeometryFactory(); // FactoryFinder.getGeometryFactory(null);
160    
161      /**          private int state = ZoomIn;
      * layer that highlight works on  
      */  
     private MapLayer highlightLayer;  
162    
163      /**          /**
164       * the object which manages highlighting           * how far to zoom in or out
165       */           */
166      private HighlightManager highlightManager;          private double zoomFactor = 2.0;
167    
168      /**          boolean changed = true;
      * is highlighting on or off  
      */  
     private boolean highlight = true;  
169    
170      /**          LabelCache labelCache = new LabelCacheImpl();
      * a factory for filters  
      */  
     FilterFactory2 ff;  
171    
172      /**          // xulu.sc
173       * a factory for geometries          // private boolean reset = false;
174       */          protected boolean reset = false;
175      GeometryFactory gf = new GeometryFactory(); // FactoryFinder.getGeometryFactory(null);          // xulu.ec
176    
177      /**          int startX;
      * the collections of features to be selected or highlighted  
      */  
     FeatureCollection selection;  
178    
179      /**          int startY;
      * the collections of features to be selected or highlighted  
      */  
     FeatureCollection highlightFeature;  
180    
181      private int state = ZoomIn;          private boolean clickable;
182    
183      /**          int lastX;
      * how far to zoom in or out  
      */  
     private double zoomFactor = 2.0;  
184    
185      Style lineHighlightStyle;          int lastY;
186    
187      Style pointHighlightStyle;          // xulu.sn
188            private Double maxZoomScale = Double.MIN_VALUE;
189            private Double minZoomScale = Double.MAX_VALUE;
190            // xulu.en
191    
192      Style polygonHighlightStyle;          // sk.sn
193            /**
194             * Wenn true, dann wurde PANNING via mouseDraged-Events begonnen. Dieses
195             * Flag wird benutzt um nur einmal den passenden Cursor nur einmal zu
196             * setzen.
197             */
198            private boolean panning_started = false;
199    
200      Style polygonSelectionStyle;          // sk.en
201    
202      Style pointSelectionStyle;          public JMapPane() {
203                    this(null, true, null, null);
204            }
205    
206      Style lineSelectionStyle;          /**
207             * create a basic JMapPane
208             *
209             * @param render
210             *            - how to draw the map
211             * @param context
212             *            - the map context to display
213             */
214            public JMapPane(final GTRenderer render, final MapContext context) {
215                    this(null, true, render, context);
216            }
217    
218      boolean changed = true;          /**
219             * full constructor extending JPanel
220             *
221             * @param layout
222             *            - layout (probably shouldn't be set)
223             * @param isDoubleBuffered
224             *            - a Swing thing I don't really understand
225             * @param render
226             *            - what to draw the map with
227             * @param context
228             *            - what to draw
229             */
230            public JMapPane(final LayoutManager layout, final boolean isDoubleBuffered,
231                            final GTRenderer render, final MapContext context) {
232                    super(layout, isDoubleBuffered);
233    
234                    ff = (FilterFactory2) org.geotools.factory.CommonFactoryFinder
235                                    .getFilterFactory(null);
236                    setRenderer(render);
237    
238                    setContext(context);
239    
240                    this.addMouseListener(this);
241                    this.addMouseMotionListener(this);
242                    setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
243            }
244    
245      LabelCache labelCache = new LabelCacheDefault();          /**
246             * get the renderer
247             */
248            public GTRenderer getRenderer() {
249                    return renderer;
250            }
251    
252  //xulu.sc          public void setRenderer(final GTRenderer renderer) {
253  //    private boolean reset = false;                  Map hints = new HashMap();
254      protected boolean reset = false;                  
255  //xulu.ec                  this.renderer = renderer;
256                    
257                    if (renderer instanceof StreamingRenderer || renderer instanceof TransitionShapefileRenderer) {
258                            hints = renderer.getRendererHints();
259                            if (hints == null) {
260                                    hints = new HashMap();
261                            }
262                            if (hints.containsKey(StreamingRenderer.LABEL_CACHE_KEY)) {
263                                    labelCache = (LabelCache) hints
264                                                    .get(StreamingRenderer.LABEL_CACHE_KEY);
265                            } else {
266                                    hints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);
267                            }
268    
269                            hints.put("memoryPreloadingEnabled", Boolean.TRUE);
270                            
271                            renderer.setRendererHints(hints);
272                    }
273    
274      int startX;  //              this.highlightRenderer = new StreamingRenderer();
275    //              this.selectionRenderer = new StreamingRenderer();
276    
277      int startY;  //              highlightRenderer.setRendererHints(hints);
278    //              selectionRenderer.setRendererHints(hints);
279                    
280    //              renderer.setRendererHints(hints);
281    
282      private boolean clickable;                  if (this.context != null) {
283                            this.renderer.setContext(this.context);
284                    }
285            }
286    
287      int lastX;          public MapContext getContext() {
288                    return context;
289            }
290    
291      int lastY;          public void setContext(final MapContext context) {
292                    if (this.context != null) {
293                            this.context.removeMapLayerListListener(this);
294                    }
295    
296      private SelectionManager selectionManager;                  this.context = context;
 //xulu.sn  
     private Double maxZoomScale = Double.MIN_VALUE;  
     private Double minZoomScale = Double.MAX_VALUE;  
 //xulu.en  
297    
298  // sk.sn                      if (context != null) {
299      /**                          this.context.addMapLayerListListener(this);
300       * Wenn true, dann wurde PANNING via mouseDraged-Events begonnen. Dieses Flag wird benutzt um nur einmal den passenden Cursor nur einmal zu setzen.                  }
301       */  
302          private boolean panning_started = false;                  if (renderer != null) {
303  // sk.en                                  renderer.setContext(this.context);
304                    }
305            }
306    
307            public Envelope getMapArea() {
308                    return mapArea;
309            }
310    
311            public void setMapArea(final Envelope mapArea) {
312                    this.mapArea = mapArea;
313            }
314    
315            public int getState() {
316                    return state;
317            }
318    
319            public void setState(final int state) {
320                    this.state = state;
321    
322                    // System.out.println("State: " + state);
323            }
324    
325            public double getZoomFactor() {
326                    return zoomFactor;
327            }
328    
329            public void setZoomFactor(final double zoomFactor) {
330                    this.zoomFactor = zoomFactor;
331            }
332    
333    
334            protected void paintComponent(final Graphics g) {
335                    super.paintComponent(g);
336    
337                    if ((renderer == null) || (mapArea == null)) {
338                            return;
339                    }
340    
341                    final Rectangle r = getBounds();
342                    final Rectangle dr = new Rectangle(r.width, r.height);
343    
344                    if (!r.equals(oldRect) || reset) {
345                            if (!r.equals(oldRect) && (mapArea == null)) {
346                                    try {
347                                            mapArea = context.getLayerBounds();
348                                    } catch (final IOException e) {
349                                            LOGGER.warn("context.getLayerBounds()", e);
350                                    }
351                            }
352    
353                            if (mapArea != null) {
354                                    /* either the viewer size has changed or we've done a reset */
355                                    changed = true; /* note we need to redraw */
356                                    reset = false; /* forget about the reset */
357                                    oldRect = r; /* store what the current size is */
358    
359                                    mapArea = fixAspectRatio(r, mapArea);
360                            }
361                    }
362    
363                    if (!mapArea.equals(oldMapArea)) { /* did the map extent change? */
364                            changed = true;
365                            oldMapArea = mapArea;
366                            // when we tell the context that the bounds have changed WMSLayers
367                            // can refresh them selves
368                            context.setAreaOfInterest(mapArea, context
369                                            .getCoordinateReferenceSystem());
370                    }
371    
372                    if (changed ) { /* if the map changed then redraw */
373                            changed = false;
374                            baseImage = new BufferedImage(dr.width, dr.height,
375                                            BufferedImage.TYPE_INT_ARGB);
376    
377                            final Graphics2D ig = baseImage.createGraphics();
378                            /* System.out.println("rendering"); */
379                            if (renderer.getContext() != null)
380                                    renderer.setContext(context);
381                            labelCache.clear(); // work around anoying labelcache bug
382    
383                            // draw the map
384                            renderer.paint((Graphics2D) ig, dr, mapArea);
385    
386                            // TODO nur machen, wenn panning beginnt
387                            panningImage = new BufferedImage(dr.width, dr.height,
388                                            BufferedImage.TYPE_INT_RGB);
389    
390                    }
391    
392                    ((Graphics2D) g).drawImage(baseImage, 0, 0, this);
393            }
394    
395            private Envelope fixAspectRatio(final Rectangle r, final Envelope mapArea) {
396    
397                    final double mapWidth = mapArea.getWidth(); /* get the extent of the map */
398                    final double mapHeight = mapArea.getHeight();
399                    final double scaleX = r.getWidth() / mapArea.getWidth(); /*
400                                                                                                                             * calculate the new
401                                                                                                                             * scale
402                                                                                                                             */
403    
404                    final double scaleY = r.getHeight() / mapArea.getHeight();
405                    double scale = 1.0; // stupid compiler!
406    
407                    if (scaleX < scaleY) { /* pick the smaller scale */
408                            scale = scaleX;
409                    } else {
410                            scale = scaleY;
411                    }
412    
413                    /* calculate the difference in width and height of the new extent */
414                    final double deltaX = /* Math.abs */((r.getWidth() / scale) - mapWidth);
415                    final double deltaY = /* Math.abs */((r.getHeight() / scale) - mapHeight);
416    
417                    /*
418                     * System.out.println("delta x " + deltaX);
419                     * System.out.println("delta y " + deltaY);
420                     */
421    
422                    /* create the new extent */
423                    final Coordinate ll = new Coordinate(mapArea.getMinX() - (deltaX / 2.0),
424                                    mapArea.getMinY() - (deltaY / 2.0));
425                    final Coordinate ur = new Coordinate(mapArea.getMaxX() + (deltaX / 2.0),
426                                    mapArea.getMaxY() + (deltaY / 2.0));
427    
428                    return new Envelope(ll, ur);
429            }
430    
431    //      public void doSelection(final double x, final double y, final MapLayer layer) {
432    //
433    //              final Geometry geometry = gf.createPoint(new Coordinate(x, y));
434    //
435    //              // org.opengis.geometry.Geometry geometry = new Point();
436    //
437    //              findFeature(geometry, layer);
438    //
439    //      }
440    //
441    //      /**
442    //       * @param geometry
443    //       *            - a geometry to construct the filter with
444    //       * @param i
445    //       *            - the index of the layer to search
446    //       * @throws IndexOutOfBoundsException
447    //       */
448    //      private void findFeature(final Geometry geometry, final MapLayer layer)
449    //                      throws IndexOutOfBoundsException {
450    //              org.opengis.filter.spatial.BinarySpatialOperator f = null;
451    //
452    //              if ((context == null) || (layer == null)) {
453    //                      return;
454    //              }
455    //
456    //              try {
457    //                      String name = layer.getFeatureSource().getSchema()
458    //                                      .getDefaultGeometry().getLocalName();
459    //
460    //                      if (name == "") {
461    //                              name = "the_geom";
462    //                      }
463    //
464    //                      try {
465    //                              f = ff.contains(ff.property(name), ff.literal(geometry));
466    //                              if (selectionManager != null) {
467    ////                                    System.out.println("selection changed");
468    //                                      selectionManager.selectionChanged(this, f);
469    //
470    //                              }
471    //                      } catch (final IllegalFilterException e) {
472    //                              // TODO Auto-generated catch block
473    //                              e.printStackTrace();
474    //                      }
475    //
476    //                      /*
477    //                       * // f.addLeftGeometry(ff.property(name)); //
478    //                       * System.out.println("looking with " + f); FeatureCollection fc =
479    //                       * layer.getFeatureSource().getFeatures(f);
480    //                       *
481    //                       *
482    //                       *
483    //                       * if (fcol == null) { fcol = fc;
484    //                       *
485    //                       * // here we should set the defaultgeom type } else {
486    //                       * fcol.addAll(fc); }
487    //                       */
488    //
489    //                      /*
490    //                       * GeometryAttributeType gat =
491    //                       * layer.getFeatureSource().getSchema().getDefaultGeometry();
492    //                       * fcol.setDefaultGeometry((Geometry)gat.createDefaultValue());
493    //                       */
494    //
495    //                      /*
496    //                       * Iterator fi = fc.iterator(); while (fi.hasNext()) { SimpleFeature feat
497    //                       * = (SimpleFeature) fi.next(); System.out.println("selected " +
498    //                       * feat.getAttribute("STATE_NAME")); }
499    //                       */
500    //              } catch (final IllegalFilterException e) {
501    //                      // TODO Auto-generated catch block
502    //                      e.printStackTrace();
503    //              }
504    //              return;
505    //      }
506    
507            public void mouseClicked(final MouseEvent e) {
508                    if (mapArea == null) return;
509                    // System.out.println("before area "+mapArea+"\nw:"+mapArea.getWidth()+"
510                    // h:"+mapArea.getHeight());
511                    final Rectangle bounds = this.getBounds();
512                    final double x = (double) (e.getX());
513                    final double y = (double) (e.getY());
514                    final double width = mapArea.getWidth();
515                    final double height = mapArea.getHeight();
516                    // xulu.sc
517                    // double width2 = mapArea.getWidth() / 2.0;
518                    // double height2 = mapArea.getHeight() / 2.0;
519                    final double width2 = width / 2.0;
520                    final double height2 = height / 2.0;
521                    // xulu.ec
522                    final double mapX = ((x * width) / (double) bounds.width) + mapArea.getMinX();
523                    final double mapY = (((bounds.getHeight() - y) * height) / (double) bounds.height)
524                                    + mapArea.getMinY();
525    
526                    /*
527                     * System.out.println(""+x+"->"+mapX);
528                     * System.out.println(""+y+"->"+mapY);
529                     */
530    
531                    /*
532                     * Coordinate ll = new Coordinate(mapArea.getMinX(), mapArea.getMinY());
533                     * Coordinate ur = new Coordinate(mapArea.getMaxX(), mapArea.getMaxY());
534                     */
535                    double zlevel = 1.0;
536    
537                    switch (state) {
538                    case Pan:
539                            zlevel = 1.0;
540                            // xulu.sc SK: return here.. a mouselistener is managing the PANNING
541                            // break;
542                            return;
543                            // xulu.ec
544                    case ZoomIn:
545                            zlevel = zoomFactor;
546    
547                            break;
548    
549                    case ZoomOut:
550                            zlevel = 1.0 / zoomFactor;
551    
552                            break;
553    //
554    //              case Select:
555    //                      doSelection(mapX, mapY, selectionLayer);
556    //
557    //                      return;
558    
559                    default:
560                            return;
561                    }
562    
563                    final Coordinate ll = new Coordinate(mapX - (width2 / zlevel), mapY
564                                    - (height2 / zlevel));
565                    final Coordinate ur = new Coordinate(mapX + (width2 / zlevel), mapY
566                                    + (height2 / zlevel));
567                    // xulu.sc SK: Check for min/max scale
568                    // mapArea = new Envelope(ll, ur);
569                    final Envelope newMapArea = new Envelope(ll, ur);
570                    setMapArea(bestAllowedMapArea(newMapArea));
571                    // xulu.ec
572    
573                    // sk.ec
574    
575                    // System.out.println("after area "+mapArea+"\nw:"+mapArea.getWidth()+"
576                    // h:"+mapArea.getHeight());
577                    repaint();
578            }
579    
580            public void mouseEntered(final MouseEvent e) {
581            }
582    
583      public JMapPane() {          public void mouseExited(final MouseEvent e) {
584          this(null, true, null, null);          }
585      }  
586            public void mousePressed(final MouseEvent e) {
587      /**                  startX = e.getX();
588       * create a basic JMapPane                  startY = e.getY();
589       *                  lastX = 0;
590       * @param render -                  lastY = 0;
591       *            how to draw the map          }
592       * @param context -  
593       *            the map context to display          public void mouseReleased(final MouseEvent e) {
594       */                  final int endX = e.getX();
595      public JMapPane(GTRenderer render, MapContext context) {                  final int endY = e.getY();
596          this(null, true, render, context);  
597      }                  processDrag(startX, startY, endX, endY, e);
598                    lastX = 0;
599      /**                  lastY = 0;
600       * full constructor extending JPanel  
601       *                  /**
602       * @param layout -                   * Es wird nicht (mehr) gepannt!
603       *            layout (probably shouldn't be set)                   */
604       * @param isDoubleBuffered -                  panning_started = false;
605       *            a Swing thing I don't really understand          }
606       * @param render -  
607       *            what to draw the map with          public void mouseDragged(final MouseEvent e) {
608       * @param context -                  final Graphics graphics = this.getGraphics();
609       *            what to draw                  final int x = e.getX();
610       */                  final int y = e.getY();
611      public JMapPane(LayoutManager layout, boolean isDoubleBuffered,  
612              GTRenderer render, MapContext context) {                  if ((state == JMapPane.Pan)
613          super(layout, isDoubleBuffered);                                  || ((e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0)) {
614                            /**
615          ff = (FilterFactory2) org.geotools.factory.CommonFactoryFinder                           * SK: Der Cursor wird auf PANNING gesetzt.
616                  .getFilterFactory(null);                           */
617          setRenderer(render);                          if (panning_started == false) {
618                                    panning_started = true;
619          setContext(context);                                  setCursor(SwingUtil.PANNING_CURSOR);
620                            }
621          this.addMouseListener(this);  
622          this.addMouseMotionListener(this);                          // move the image with the mouse
623          setHighlightManager(new HighlightManager(highlightLayer));                          if ((lastX > 0) && (lastY > 0)) {
624          setSelectionManager(new SelectionManager(selectionLayer));                                  final int dx = lastX - startX;
625          lineHighlightStyle = setupStyle(LINE, Color.red);                                  final int dy = lastY - startY;
626                                    // System.out.println("translate "+dx+","+dy);
627          pointHighlightStyle = setupStyle(POINT, Color.red);                                  final Graphics2D g2 = panningImage.createGraphics();
628                                    g2.setBackground(new Color(240, 240, 240)); // TODO richtige
629          polygonHighlightStyle = setupStyle(POLYGON, Color.red);                                                                                                                          // farbe? am besten
630                                                                                                                            // vom L&F die
631          polygonSelectionStyle = setupStyle(POLYGON, Color.cyan);                                                                                                                          // hintergrundfarbe
632                                                                                                                            // auslesen...
633          pointSelectionStyle = setupStyle(POINT, Color.cyan);                                  
   
         lineSelectionStyle = setupStyle(LINE, Color.cyan);  
         setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));  
     }  
   
     /**  
      * get the renderer  
      */  
     public GTRenderer getRenderer() {  
         return renderer;  
     }  
   
     public void setRenderer(GTRenderer renderer) {  
         Map hints = new HashMap();  
         if (renderer instanceof StreamingRenderer) {  
             hints = renderer.getRendererHints();  
             if (hints == null) {  
                 hints = new HashMap();  
             }  
             if (hints.containsKey(StreamingRenderer.LABEL_CACHE_KEY)) {  
                 labelCache = (LabelCache) hints  
                         .get(StreamingRenderer.LABEL_CACHE_KEY);  
             } else {  
                 hints.put(StreamingRenderer.LABEL_CACHE_KEY, labelCache);  
             }  
             renderer.setRendererHints(hints);  
         }  
   
         this.renderer = renderer;  
         this.highlightRenderer = new StreamingRenderer();  
         this.selectionRenderer = new StreamingRenderer();  
   
         hints.put("memoryPreloadingEnabled", Boolean.FALSE);  
         highlightRenderer.setRendererHints(hints);  
         selectionRenderer.setRendererHints(hints);  
   
         if (this.context != null) {  
             this.renderer.setContext(this.context);  
         }  
     }  
   
     public MapContext getContext() {  
         return context;  
     }  
   
     public void setContext(MapContext context) {  
         if (this.context != null) {  
             this.context.removeMapLayerListListener(this);  
         }  
   
         this.context = context;  
   
         if (context != null) {  
             this.context.addMapLayerListListener(this);  
         }  
   
         if (renderer != null) {  
             renderer.setContext(this.context);  
         }  
     }  
   
     public Envelope getMapArea() {  
         return mapArea;  
     }  
   
     public void setMapArea(Envelope mapArea) {  
         this.mapArea = mapArea;  
     }  
   
     public int getState() {  
         return state;  
     }  
   
     public void setState(int state) {  
         this.state = state;  
   
         // System.out.println("State: " + state);  
     }  
   
     public double getZoomFactor() {  
         return zoomFactor;  
     }  
   
     public void setZoomFactor(double zoomFactor) {  
         this.zoomFactor = zoomFactor;  
     }  
   
     public MapLayer getSelectionLayer() {  
         return selectionLayer;  
     }  
   
     public void setSelectionLayer(MapLayer selectionLayer) {  
         this.selectionLayer = selectionLayer;  
         if(selectionManager!=null) {  
             selectionManager.setSelectionLayer(selectionLayer);  
         }  
     }  
   
     public boolean isHighlight() {  
         return highlight;  
     }  
   
     public void setHighlight(boolean highlight) {  
         this.highlight = highlight;  
     }  
   
     public MapLayer getHighlightLayer() {  
         return highlightLayer;  
     }  
   
     public void setHighlightLayer(MapLayer highlightLayer) {  
         this.highlightLayer = highlightLayer;  
   
         if (highlightManager != null) {  
             highlightManager.setHighlightLayer(highlightLayer);  
         }  
     }  
   
     public HighlightManager getHighlightManager() {  
         return highlightManager;  
     }  
   
     public void setHighlightManager(HighlightManager highlightManager) {  
         this.highlightManager = highlightManager;  
         this.highlightManager.addHighlightChangeListener(this);  
         this.addMouseMotionListener(this.highlightManager);  
     }  
   
     public Style getLineHighlightStyle() {  
         return lineHighlightStyle;  
     }  
   
     public void setLineHighlightStyle(Style lineHighlightStyle) {  
         this.lineHighlightStyle = lineHighlightStyle;  
     }  
   
     public Style getLineSelectionStyle() {  
         return lineSelectionStyle;  
     }  
   
     public void setLineSelectionStyle(Style lineSelectionStyle) {  
         this.lineSelectionStyle = lineSelectionStyle;  
     }  
   
     public Style getPointHighlightStyle() {  
         return pointHighlightStyle;  
     }  
   
     public void setPointHighlightStyle(Style pointHighlightStyle) {  
         this.pointHighlightStyle = pointHighlightStyle;  
     }  
   
     public Style getPointSelectionStyle() {  
         return pointSelectionStyle;  
     }  
   
     public void setPointSelectionStyle(Style pointSelectionStyle) {  
         this.pointSelectionStyle = pointSelectionStyle;  
     }  
   
     public Style getPolygonHighlightStyle() {  
         return polygonHighlightStyle;  
     }  
   
     public void setPolygonHighlightStyle(Style polygonHighlightStyle) {  
         this.polygonHighlightStyle = polygonHighlightStyle;  
     }  
   
     public Style getPolygonSelectionStyle() {  
         return polygonSelectionStyle;  
     }  
   
     public void setPolygonSelectionStyle(Style polygonSelectionStyle) {  
         this.polygonSelectionStyle = polygonSelectionStyle;  
     }  
   
     protected void paintComponent(Graphics g) {  
         super.paintComponent(g);  
   
         if ((renderer == null) || (mapArea == null)  ) {  
             return;  
         }  
   
         Rectangle r = getBounds();  
         Rectangle dr = new Rectangle(r.width, r.height);  
   
         if (!r.equals(oldRect) || reset) {  
                 if(!r.equals(oldRect) && (mapArea == null)) {  
                         try {  
                                         mapArea=context.getLayerBounds();  
                                 } catch (IOException e) {  
                                         // TODO Auto-generated catch block  
                                         e.printStackTrace();  
                                 }  
                 }  
                   
                 if (mapArea != null){  
                         /* either the viewer size has changed or we've done a reset */  
                         changed = true; /* note we need to redraw */  
                         reset = false; /* forget about the reset */  
                         oldRect = r; /* store what the current size is */  
                           
                         mapArea = fixAspectRatio(r, mapArea);  
                 }  
         }  
   
         if (!mapArea.equals(oldMapArea)) { /* did the map extent change? */  
             changed = true;  
             oldMapArea = mapArea;  
 //          when we tell the context that the bounds have changed WMSLayers  
             // can refresh them selves  
             context.setAreaOfInterest(mapArea, context  
                     .getCoordinateReferenceSystem());  
         }  
   
         if (changed) { /* if the map changed then redraw */  
             changed = false;  
             baseImage = new BufferedImage(dr.width, dr.height,  
                     BufferedImage.TYPE_INT_ARGB);  
   
             Graphics2D ig = baseImage.createGraphics();  
             /* System.out.println("rendering"); */  
             renderer.setContext(context);  
             labelCache.clear(); // work around anoying labelcache bug  
   
   
             // draw the map  
             renderer.paint((Graphics2D) ig, dr, mapArea);  
   
             // TODO , nur machen, wenn panning beginnt  
             panningImage = new BufferedImage(dr.width, dr.height,  
                         BufferedImage.TYPE_INT_RGB);  
               
         }  
   
         ((Graphics2D) g).drawImage(baseImage, 0, 0, this);  
   
         if ((selection != null) && (selection.size() > 0)) {  
             // paint selection  
   
             String type = selectionLayer.getFeatureSource().getSchema()  
             .getDefaultGeometry().getType().getName();  
             /*String type = selection.getDefaultGeometry().getGeometryType();*/  
             /*System.out.println(type);*/  
             if (type == null)  
                 type = "polygon";  
   
             /* String type = "point"; */  
   
             if (type.toLowerCase().endsWith("polygon")) {  
                 selectionStyle = polygonSelectionStyle;  
             } else if (type.toLowerCase().endsWith("point")) {  
                 selectionStyle = pointSelectionStyle;  
             } else if (type.toLowerCase().endsWith("line")) {  
                 selectionStyle = lineSelectionStyle;  
             }  
   
             selectionContext = new DefaultMapContext(DefaultGeographicCRS.WGS84);  
   
             selectionContext.addLayer(selection, selectionStyle);  
             selectionRenderer.setContext(selectionContext);  
   
             selectImage = new BufferedImage(dr.width, dr.height,  
                     BufferedImage.TYPE_INT_ARGB);  
   
             Graphics2D ig = selectImage.createGraphics();  
             /* System.out.println("rendering selection"); */  
             selectionRenderer.paint((Graphics2D) ig, dr, mapArea);  
   
             ((Graphics2D) g).drawImage(selectImage, 0, 0, this);  
         }  
   
         if (highlight && (highlightFeature != null)  
                 && (highlightFeature.size() > 0)) {  
             /*  
              * String type = selection.getDefaultGeometry().getGeometryType();  
              * System.out.println(type); if(type==null) type="polygon";  
              */  
             String type = highlightLayer.getFeatureSource().getSchema()  
             .getDefaultGeometry().getType().getName();  
             /*String type = selection.getDefaultGeometry().getGeometryType();*/  
             //System.out.println(type);  
             if (type == null)  
                 type = "polygon";  
   
             /* String type = "point"; */  
             Style highlightStyle = null;  
             if (type.toLowerCase().endsWith("polygon")) {  
                 highlightStyle = polygonHighlightStyle;  
             } else if (type.toLowerCase().endsWith("point")) {  
                 highlightStyle = pointHighlightStyle;  
             } else if (type.toLowerCase().endsWith("line")) {  
                 highlightStyle = lineHighlightStyle;  
             }  
   
   
   
   
             MapContext highlightContext = new DefaultMapContext(  
                     DefaultGeographicCRS.WGS84);  
   
             highlightContext.addLayer(highlightFeature, highlightStyle);  
             highlightRenderer.setContext(highlightContext);  
   
             /* System.out.println("rendering highlight"); */  
             highlightRenderer.paint((Graphics2D) g, dr, mapArea);  
         }  
     }  
   
     private Envelope fixAspectRatio(Rectangle r, Envelope mapArea) {  
           
         double mapWidth = mapArea.getWidth(); /* get the extent of the map */  
         double mapHeight = mapArea.getHeight();  
         double scaleX = r.getWidth() / mapArea.getWidth(); /*  
                                                              * calculate the new  
                                                              * scale  
                                                              */  
   
         double scaleY = r.getHeight() / mapArea.getHeight();  
         double scale = 1.0; // stupid compiler!  
   
         if (scaleX < scaleY) { /* pick the smaller scale */  
             scale = scaleX;  
         } else {  
             scale = scaleY;  
         }  
   
         /* calculate the difference in width and height of the new extent */  
         double deltaX = /* Math.abs */((r.getWidth() / scale) - mapWidth);  
         double deltaY = /* Math.abs */((r.getHeight() / scale) - mapHeight);  
   
         /*  
          * System.out.println("delta x " + deltaX); System.out.println("delta y " +  
          * deltaY);  
          */  
   
         /* create the new extent */  
         Coordinate ll = new Coordinate(mapArea.getMinX() - (deltaX / 2.0),  
                 mapArea.getMinY() - (deltaY / 2.0));  
         Coordinate ur = new Coordinate(mapArea.getMaxX() + (deltaX / 2.0),  
                 mapArea.getMaxY() + (deltaY / 2.0));  
   
         return new Envelope(ll, ur);  
     }  
   
     public void doSelection(double x, double y, MapLayer layer) {  
   
         Geometry geometry = gf.createPoint(new Coordinate(x, y));  
   
         // org.opengis.geometry.Geometry geometry = new Point();  
   
             findFeature(geometry, layer);  
   
     }  
   
     /**  
      * @param geometry -  
      *            a geometry to construct the filter with  
      * @param i -  
      *            the index of the layer to search  
      * @throws IndexOutOfBoundsException  
      */  
     private void findFeature(Geometry geometry, MapLayer layer)  
             throws IndexOutOfBoundsException {  
         org.opengis.filter.spatial.BinarySpatialOperator f = null;  
   
   
         if ((context == null) || (layer==null)) {  
             return ;  
         }  
   
   
   
         try {  
             String name = layer.getFeatureSource().getSchema()  
                     .getDefaultGeometry().getName();  
   
             if (name == "") {  
                 name = "the_geom";  
             }  
   
             try {  
                 f = ff.contains(ff.property(name), ff.literal(geometry));  
                 if(selectionManager!=null) {  
                     System.out.println("selection changed");  
                     selectionManager.selectionChanged(this, f);  
   
                 }  
             } catch (IllegalFilterException e) {  
                 // TODO Auto-generated catch block  
                 e.printStackTrace();  
             }  
   
             /*// f.addLeftGeometry(ff.property(name));  
             // System.out.println("looking with " + f);  
             FeatureCollection fc = layer.getFeatureSource().getFeatures(f);  
   
   
   
             if (fcol == null) {  
                 fcol = fc;  
   
                 // here we should set the defaultgeom type  
             } else {  
                 fcol.addAll(fc);  
             }*/  
   
             /*  
              * GeometryAttributeType gat =  
              * layer.getFeatureSource().getSchema().getDefaultGeometry();  
              * fcol.setDefaultGeometry((Geometry)gat.createDefaultValue());  
              */  
   
             /*  
              * Iterator fi = fc.iterator(); while (fi.hasNext()) { Feature feat =  
              * (Feature) fi.next(); System.out.println("selected " +  
              * feat.getAttribute("STATE_NAME")); }  
              */  
         } catch (IllegalFilterException e) {  
             // TODO Auto-generated catch block  
             e.printStackTrace();  
         }  
         return ;  
     }  
   
     public void mouseClicked(MouseEvent e) {  
         // System.out.println("before area "+mapArea+"\nw:"+mapArea.getWidth()+"  
         // h:"+mapArea.getHeight());  
         Rectangle bounds = this.getBounds();  
         double x = (double) (e.getX());  
         double y = (double) (e.getY());  
         double width = mapArea.getWidth();  
         double height = mapArea.getHeight();  
 //xulu.sc  
 //        double width2 = mapArea.getWidth() / 2.0;  
 //        double height2 = mapArea.getHeight() / 2.0;  
         double width2 = width / 2.0;  
         double height2 = height / 2.0;  
 //xulu.ec  
         double mapX = ((x * width) / (double) bounds.width) + mapArea.getMinX();  
         double mapY = (((bounds.getHeight() - y) * height) / (double) bounds.height)  
                 + mapArea.getMinY();  
   
         /*  
          * System.out.println(""+x+"->"+mapX);  
          * System.out.println(""+y+"->"+mapY);  
          */  
   
         /*  
          * Coordinate ll = new Coordinate(mapArea.getMinX(), mapArea.getMinY());  
          * Coordinate ur = new Coordinate(mapArea.getMaxX(), mapArea.getMaxY());  
          */  
         double zlevel = 1.0;  
   
         switch (state) {  
         case Pan:  
             zlevel = 1.0;  
 //xulu.sc SK: return here.. a mouselistener is maanaging the PANNING  
 //            break;  
             return;  
 //xulu.ec  
         case ZoomIn:  
             zlevel = zoomFactor;  
   
             break;  
   
         case ZoomOut:  
             zlevel = 1.0 / zoomFactor;  
   
             break;  
   
         case Select:  
             doSelection(mapX, mapY, selectionLayer);  
   
   
             return;  
   
         default:  
             return;  
         }  
   
         Coordinate ll = new Coordinate(mapX - (width2 / zlevel), mapY  
                 - (height2 / zlevel));  
         Coordinate ur = new Coordinate(mapX + (width2 / zlevel), mapY  
                 + (height2 / zlevel));  
 //xulu.sc SK: Check for min/max scale  
 //        mapArea = new Envelope(ll, ur);  
         final Envelope newMapArea = new Envelope(ll, ur);  
         setMapArea( bestAllowedMapArea( newMapArea ) );  
 //xulu.ec  
   
         // System.out.println("after area "+mapArea+"\nw:"+mapArea.getWidth()+"  
         // h:"+mapArea.getHeight());  
         repaint();  
     }  
   
     public void mouseEntered(MouseEvent e) {  
     }  
   
     public void mouseExited(MouseEvent e) {  
     }  
   
     public void mousePressed(MouseEvent e) {  
         startX = e.getX();  
         startY = e.getY();  
         lastX = 0;  
         lastY = 0;  
     }  
       
     public void mouseReleased(MouseEvent e) {  
         int endX = e.getX();  
         int endY = e.getY();  
           
         processDrag(startX, startY, endX, endY, e);  
         lastX = 0;  
         lastY = 0;  
           
         /**  
          * Es wird nicht (mehr) gepannt!  
          */  
         panning_started = false;  
     }  
   
     public void mouseDragged(MouseEvent e) {  
         Graphics graphics = this.getGraphics();  
         int x = e.getX();  
         int y = e.getY();  
           
   
         if ( (state == JMapPane.Pan) || ((e.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0))  {  
             /**  
              * SK:  
              * Der Cursor wird auf PANNING gesetzt.  
              */  
                 if (panning_started == false){  
                         panning_started = true;  
                         setCursor( SwingUtil.PANNING_CURSOR );  
                 }  
                   
                   
             // move the image with the mouse  
             if ((lastX > 0) && (lastY > 0)) {  
                 int dx = lastX - startX;  
                 int dy = lastY - startY;  
                 // System.out.println("translate "+dx+","+dy);  
                 final Graphics2D g2 = panningImage.createGraphics();  
                 g2.setBackground( new Color(240,240,240) ); //TODO richtige farbe? am besten vom L&F die hintergrundfarbe auslesen...  
634                                  g2.clearRect(0, 0, this.getWidth(), this.getHeight());                                  g2.clearRect(0, 0, this.getWidth(), this.getHeight());
635                                  g2.drawImage(baseImage, dx, dy, this);                                  g2.drawImage(baseImage, dx, dy, this);
636                  graphics.drawImage(panningImage, 0, 0, this);                                  graphics.drawImage(panningImage, 0, 0, this);
637              }                          }
638    
639                            lastX = x;
640                            lastY = y;
641                    } else
642    
643                    if ((state == JMapPane.ZoomIn) || (state == JMapPane.ZoomOut)) {
644    
645                            graphics.setXORMode(Color.WHITE);
646    
647                            if ((lastX > 0) && (lastY > 0)) {
648                                    drawRectangle(graphics);
649                            }
650    
651                            // draw new box
652                            lastX = x;
653                            lastY = y;
654                            drawRectangle(graphics);
655                    }
656    //              else if (state == JMapPane.Select && selectionLayer != null) {
657    //
658    //                      // construct a new bbox filter
659    //                      final Rectangle bounds = this.getBounds();
660    //
661    //                      final double mapWidth = mapArea.getWidth();
662    //                      final double mapHeight = mapArea.getHeight();
663    //
664    //                      final double x1 = ((this.startX * mapWidth) / (double) bounds.width)
665    //                                      + mapArea.getMinX();
666    //                      final double y1 = (((bounds.getHeight() - this.startY) * mapHeight) / (double) bounds.height)
667    //                                      + mapArea.getMinY();
668    //                      final double x2 = ((x * mapWidth) / (double) bounds.width)
669    //                                      + mapArea.getMinX();
670    //                      final double y2 = (((bounds.getHeight() - y) * mapHeight) / (double) bounds.height)
671    //                                      + mapArea.getMinY();
672    //                      final double left = Math.min(x1, x2);
673    //                      final double right = Math.max(x1, x2);
674    //                      final double bottom = Math.min(y1, y2);
675    //                      final double top = Math.max(y1, y2);
676    //
677    //                      String name = selectionLayer.getFeatureSource().getSchema()
678    //                                      .getDefaultGeometry().getName();
679    //
680    //                      if (name == "") {
681    //                              name = "the_geom";
682    //                      }
683    //                      final Filter bb = ff.bbox(ff.property(name), left, bottom, right, top,
684    //                                      getContext().getCoordinateReferenceSystem().toString());
685    //                      if (selectionManager != null) {
686    //                              selectionManager.selectionChanged(this, bb);
687    //                      }
688    //
689    //                      graphics.setXORMode(Color.green);
690    //
691    //                      /*
692    //                       * if ((lastX > 0) && (lastY > 0)) { drawRectangle(graphics); }
693    //                       */
694    //
695    //                      // draw new box
696    //                      lastX = x;
697    //                      lastY = y;
698    //                      drawRectangle(graphics);
699    //              }
700    
701            }
702    
703            // sk.cs
704            // private void processDrag(int x1, int y1, int x2, int y2) {
705            // sk.ce
706            protected void processDrag(final int x1, final int y1, final int x2,
707                            final int y2, final MouseEvent e) {
708    
709                    /****
710                     * If no layer is availabe we dont want a NullPointerException
711                     */
712                    if (mapArea == null)
713                            return;
714    
715                    // System.out.println("processing drag from " + x1 + "," + y1 + " -> "
716                    // + x2 + "," + y2);
717                    if ((x1 == x2) && (y1 == y2)) {
718                            if (isClickable()) {
719                                    mouseClicked(new MouseEvent(this, 0, new Date().getTime(), 0,
720                                                    x1, y1, y2, false));
721                            }
722    
723                            return;
724                    }
725    
726                    final Rectangle bounds = this.getBounds();
727    
728                    final double mapWidth = mapArea.getWidth();
729                    final double mapHeight = mapArea.getHeight();
730    
731                    final double startX = ((x1 * mapWidth) / (double) bounds.width)
732                                    + mapArea.getMinX();
733                    final double startY = (((bounds.getHeight() - y1) * mapHeight) / (double) bounds.height)
734                                    + mapArea.getMinY();
735                    final double endX = ((x2 * mapWidth) / (double) bounds.width)
736                                    + mapArea.getMinX();
737                    final double endY = (((bounds.getHeight() - y2) * mapHeight) / (double) bounds.height)
738                                    + mapArea.getMinY();
739    
740                    if ((state == JMapPane.Pan) || (e.getButton() == MouseEvent.BUTTON3)) {
741                            // move the image with the mouse
742                            // calculate X offsets from start point to the end Point
743                            final double deltaX1 = endX - startX;
744    
745                            // System.out.println("deltaX " + deltaX1);
746                            // new edges
747                            final double left = mapArea.getMinX() - deltaX1;
748                            final double right = mapArea.getMaxX() - deltaX1;
749    
750                            // now for Y
751                            final double deltaY1 = endY - startY;
752    
753                            // System.out.println("deltaY " + deltaY1);
754                            final double bottom = mapArea.getMinY() - deltaY1;
755                            final double top = mapArea.getMaxY() - deltaY1;
756                            final Coordinate ll = new Coordinate(left, bottom);
757                            final Coordinate ur = new Coordinate(right, top);
758                            // xulu.sc
759                            // mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));
760                            setMapArea(fixAspectRatio(this.getBounds(), new Envelope(ll, ur)));
761                            // xulu.ec
762                    } else if (state == JMapPane.ZoomIn) {
763    
764                            // Zu kleine Flächen sollen nicht gezoomt werden.
765                            // sk.bc
766                            if ((Math.abs(x1 - x2) * Math.abs(y2 - y1)) < 150)
767                                    return;
768                            // sk.ec
769    
770                            drawRectangle(this.getGraphics());
771                            // make the dragged rectangle (in map coords) the new BBOX
772                            final double left = Math.min(startX, endX);
773                            final double right = Math.max(startX, endX);
774                            final double bottom = Math.min(startY, endY);
775                            final double top = Math.max(startY, endY);
776                            final Coordinate ll = new Coordinate(left, bottom);
777                            final Coordinate ur = new Coordinate(right, top);
778                            // xulu.sc
779    
780                            // mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));
781                            setMapArea(bestAllowedMapArea(new Envelope(ll, ur)));
782    
783                            // sk.sc
784    //                      {
785    //                      // SK tries to paint a preview of the zoom ;-9 aha.... well
786    //                      Graphics2D graphics = (Graphics2D) JMapPane.this.getGraphics();
787    //                      graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
788    //                                      RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
789    //                      graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
790    //                                      RenderingHints.VALUE_ANTIALIAS_OFF);
791    //                      graphics.setRenderingHint(RenderingHints.KEY_RENDERING,
792    //                                      RenderingHints.VALUE_RENDER_SPEED);
793    //                      graphics.drawImage(baseImage, 0, 0, JMapPane.this.getWidth(),
794    //                                      JMapPane.this.getHeight(), x1, y1, x2, y2, null);
795    //                      }
796                            // xulu.ec
797                    } else if (state == JMapPane.ZoomOut) {
798                            drawRectangle(this.getGraphics());
799    
800                            // make the dragged rectangle in screen coords the new map size?
801                            final double left = Math.min(startX, endX);
802                            final double right = Math.max(startX, endX);
803                            final double bottom = Math.min(startY, endY);
804                            final double top = Math.max(startY, endY);
805                            final double nWidth = (mapWidth * mapWidth) / (right - left);
806                            final double nHeight = (mapHeight * mapHeight) / (top - bottom);
807                            final double deltaX1 = left - mapArea.getMinX();
808                            final double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;
809                            final double deltaY1 = bottom - mapArea.getMinY();
810                            final double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;
811                            final Coordinate ll = new Coordinate(mapArea.getMinX() - nDeltaX1,
812                                            mapArea.getMinY() - nDeltaY1);
813                            final double deltaX2 = mapArea.getMaxX() - right;
814                            final double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;
815                            final double deltaY2 = mapArea.getMaxY() - top;
816                            final double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;
817                            final Coordinate ur = new Coordinate(mapArea.getMaxX() + nDeltaX2,
818                                            mapArea.getMaxY() + nDeltaY2);
819                            // xulu.sc
820                            // mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));
821                            setMapArea(bestAllowedMapArea(new Envelope(ll, ur)));
822    
823                            // xulu.ec
824                    }
825    //              else if (state == JMapPane.Select && selectionLayer != null) {
826    //                      final double left = Math.min(startX, endX);
827    //                      final double right = Math.max(startX, endX);
828    //                      final double bottom = Math.min(startY, endY);
829    //                      final double top = Math.max(startY, endY);
830    //
831    //                      String name = selectionLayer.getFeatureSource().getSchema()
832    //                                      .getDefaultGeometry().getLocalName();
833    //
834    //                      if (name == "") {
835    //                              name = "the_geom";
836    //                      }
837    //                      final Filter bb = ff.bbox(ff.property(name), left, bottom, right, top,
838    //                                      getContext().getCoordinateReferenceSystem().toString());
839    //                      // System.out.println(bb.toString());
840    //                      if (selectionManager != null) {
841    //                              selectionManager.selectionChanged(this, bb);
842    //                      }
843    //                      /*
844    //                       * FeatureCollection fc; selection = null; try { fc =
845    //                       * selectionLayer.getFeatureSource().getFeatures(bb); selection =
846    //                       * fc; } catch (IOException e) { e.printStackTrace(); }
847    //                       */
848    //              }
849    
850                    // xulu.so
851                    // setMapArea(mapArea);
852                    // xulu.eo
853                    repaint();
854            }
855    
856            private boolean isClickable() {
857                    return clickable;
858            }
859    
860              lastX = x;          private org.geotools.styling.Style setupStyle(final int type, final Color color) {
861              lastY = y;                  final StyleFactory sf = org.geotools.factory.CommonFactoryFinder
862          } else                                  .getStyleFactory(null);
863                                    final StyleBuilder sb = new StyleBuilder();
         if ((state == JMapPane.ZoomIn) || (state == JMapPane.ZoomOut)) {  
           
           
             graphics.setXORMode(Color.WHITE);  
   
             if ((lastX > 0) && (lastY > 0)) {  
                 drawRectangle(graphics);  
             }  
   
             // draw new box  
             lastX = x;  
             lastY = y;  
             drawRectangle(graphics);  
         } else if (state == JMapPane.Select && selectionLayer != null) {  
   
             // construct a new bbox filter  
             Rectangle bounds = this.getBounds();  
   
             double mapWidth = mapArea.getWidth();  
             double mapHeight = mapArea.getHeight();  
   
             double x1 = ((this.startX * mapWidth) / (double) bounds.width)  
                     + mapArea.getMinX();  
             double y1 = (((bounds.getHeight() - this.startY) * mapHeight) / (double) bounds.height)  
                     + mapArea.getMinY();  
             double x2 = ((x * mapWidth) / (double) bounds.width)  
                     + mapArea.getMinX();  
             double y2 = (((bounds.getHeight() - y) * mapHeight) / (double) bounds.height)  
                     + mapArea.getMinY();  
             double left = Math.min(x1, x2);  
             double right = Math.max(x1, x2);  
             double bottom = Math.min(y1, y2);  
             double top = Math.max(y1, y2);  
   
   
             String name = selectionLayer.getFeatureSource().getSchema()  
                     .getDefaultGeometry().getName();  
   
             if (name == "") {  
                 name = "the_geom";  
             }  
             Filter bb = ff.bbox(ff.property(name), left, bottom, right, top,  
                     getContext().getCoordinateReferenceSystem().toString());  
             if(selectionManager!=null) {  
                 selectionManager.selectionChanged(this, bb);  
             }  
   
             graphics.setXORMode(Color.green);  
   
             /*  
              * if ((lastX > 0) && (lastY > 0)) { drawRectangle(graphics); }  
              */  
   
             // draw new box  
             lastX = x;  
             lastY = y;  
             drawRectangle(graphics);  
        }  
       
     }  
   
     // sk.cs  
 //    private void processDrag(int x1, int y1, int x2, int y2) {  
     // sk.ce  
     protected void processDrag(int x1, int y1, int x2, int y2, MouseEvent e) {  
           
         /****  
          * If no layer is availabe we dont want a NullPointerException  
          */  
         if (mapArea == null) return;  
           
         // System.out.println("processing drag from " + x1 + "," + y1 + " -> "  
         // + x2 + "," + y2);  
         if ((x1 == x2) && (y1 == y2)) {  
             if (isClickable()) {  
                 mouseClicked(new MouseEvent(this, 0, new Date().getTime(), 0,  
                         x1, y1, y2, false));  
             }  
   
             return;  
         }  
           
         Rectangle bounds = this.getBounds();  
   
         double mapWidth = mapArea.getWidth();  
         double mapHeight = mapArea.getHeight();  
   
         double startX = ((x1 * mapWidth) / (double) bounds.width)  
                 + mapArea.getMinX();  
         double startY = (((bounds.getHeight() - y1) * mapHeight) / (double) bounds.height)  
                 + mapArea.getMinY();  
         double endX = ((x2 * mapWidth) / (double) bounds.width)  
                 + mapArea.getMinX();  
         double endY = (((bounds.getHeight() - y2) * mapHeight) / (double) bounds.height)  
                 + mapArea.getMinY();  
   
         if (  (state == JMapPane.Pan) || (e.getButton()== MouseEvent.BUTTON3)) {  
             // move the image with the mouse  
             // calculate X offsets from start point to the end Point  
             double deltaX1 = endX - startX;  
   
             // System.out.println("deltaX " + deltaX1);  
             // new edges  
             double left = mapArea.getMinX() - deltaX1;  
             double right = mapArea.getMaxX() - deltaX1;  
   
             // now for Y  
             double deltaY1 = endY - startY;  
   
             // System.out.println("deltaY " + deltaY1);  
             double bottom = mapArea.getMinY() - deltaY1;  
             double top = mapArea.getMaxY() - deltaY1;  
             Coordinate ll = new Coordinate(left, bottom);  
             Coordinate ur = new Coordinate(right, top);  
 //xulu.sc  
 //            mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));  
             setMapArea( fixAspectRatio(this.getBounds(), new Envelope(ll, ur)) );  
 //xulu.ec  
         } else if (state == JMapPane.ZoomIn) {  
                   
   
                 // Zu kleine Flächen sollen nicht gezoomt werden.  
                 //sk.bc  
                 if ( (Math.abs(x1-x2) * Math.abs(y2-y1) )<100 ) return;  
                 // sk.ec  
                   
                 drawRectangle(this.getGraphics());  
             // make the dragged rectangle (in map coords) the new BBOX  
             double left = Math.min(startX, endX);  
             double right = Math.max(startX, endX);  
             double bottom = Math.min(startY, endY);  
             double top = Math.max(startY, endY);  
             Coordinate ll = new Coordinate(left, bottom);  
             Coordinate ur = new Coordinate(right, top);  
 //xulu.sc  
 //            mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));  
             setMapArea( fixAspectRatio(this.getBounds(), new Envelope(ll, ur)) );  
 //xulu.ec  
         } else if (state == JMapPane.ZoomOut) {  
                 drawRectangle(this.getGraphics());  
                   
                 // make the dragged rectangle in screen coords the new map size?  
             double left = Math.min(startX, endX);  
             double right = Math.max(startX, endX);  
             double bottom = Math.min(startY, endY);  
             double top = Math.max(startY, endY);  
             double nWidth = (mapWidth * mapWidth) / (right - left);  
             double nHeight = (mapHeight * mapHeight) / (top - bottom);  
             double deltaX1 = left - mapArea.getMinX();  
             double nDeltaX1 = (deltaX1 * nWidth) / mapWidth;  
             double deltaY1 = bottom - mapArea.getMinY();  
             double nDeltaY1 = (deltaY1 * nHeight) / mapHeight;  
             Coordinate ll = new Coordinate(mapArea.getMinX() - nDeltaX1,  
                     mapArea.getMinY() - nDeltaY1);  
             double deltaX2 = mapArea.getMaxX() - right;  
             double nDeltaX2 = (deltaX2 * nWidth) / mapWidth;  
             double deltaY2 = mapArea.getMaxY() - top;  
             double nDeltaY2 = (deltaY2 * nHeight) / mapHeight;  
             Coordinate ur = new Coordinate(mapArea.getMaxX() + nDeltaX2,  
                     mapArea.getMaxY() + nDeltaY2);  
 //xulu.sc              
 //            mapArea = fixAspectRatio(this.getBounds(), new Envelope(ll, ur));  
             setMapArea( fixAspectRatio(this.getBounds(), new Envelope(ll, ur)) );  
 //xulu.ec  
         } else if (state == JMapPane.Select && selectionLayer !=null) {  
             double left = Math.min(startX, endX);  
             double right = Math.max(startX, endX);  
             double bottom = Math.min(startY, endY);  
             double top = Math.max(startY, endY);  
   
   
             String name = selectionLayer.getFeatureSource().getSchema()  
                     .getDefaultGeometry().getLocalName();  
   
             if (name == "") {  
                 name = "the_geom";  
             }  
             Filter bb = ff.bbox(ff.property(name), left, bottom, right, top,  
                     getContext().getCoordinateReferenceSystem().toString());  
             //System.out.println(bb.toString());  
             if(selectionManager!=null) {  
                 selectionManager.selectionChanged(this, bb);  
             }  
             /*FeatureCollection fc;  
             selection = null;  
             try {  
                 fc = selectionLayer.getFeatureSource().getFeatures(bb);  
                 selection = fc;  
             } catch (IOException e) {  
                 e.printStackTrace();  
             }  
 */  
         }  
   
 //xulu.so  
 //        setMapArea(mapArea);  
 //xulu.eo  
         repaint();  
     }  
   
     private boolean isClickable() {  
         return clickable;  
     }  
   
     private org.geotools.styling.Style setupStyle(int type, Color color) {  
         StyleFactory sf = org.geotools.factory.CommonFactoryFinder  
                 .getStyleFactory(null);  
         StyleBuilder sb = new StyleBuilder();  
   
         org.geotools.styling.Style s = sf.createStyle();  
         s.setTitle("selection");  
   
         // TODO parameterise the color  
         PolygonSymbolizer ps = sb.createPolygonSymbolizer(color);  
         ps.setStroke(sb.createStroke(color));  
   
         LineSymbolizer ls = sb.createLineSymbolizer(color);  
         Graphic h = sb.createGraphic();  
         h.setMarks(new Mark[] { sb.createMark("square", color) });  
   
         PointSymbolizer pts = sb.createPointSymbolizer(h);  
   
         // Rule r = sb.createRule(new Symbolizer[]{ps,ls,pts});  
         switch (type) {  
         case POLYGON:  
             s = sb.createStyle(ps);  
   
             break;  
   
         case POINT:  
             s = sb.createStyle(pts);  
   
             break;  
   
         case LINE:  
             s = sb.createStyle(ls);  
         }  
   
         return s;  
     }  
   
     public void highlightChanged(HighlightChangedEvent e) {  
         org.opengis.filter.Filter f = e.getFilter();  
   
         try {  
             highlightFeature = highlightLayer.getFeatureSource().getFeatures(f);  
         } catch (IOException e1) {  
             // TODO Auto-generated catch block  
             e1.printStackTrace();  
         }  
   
         repaint();  
     }  
   
     public void propertyChange(PropertyChangeEvent evt) {  
         String prop = evt.getPropertyName();  
   
         if (prop.equalsIgnoreCase("crs")) {  
             context.setAreaOfInterest(context.getAreaOfInterest(),  
                     (CoordinateReferenceSystem) evt.getNewValue());  
         }  
     }  
   
     public boolean isReset() {  
         return reset;  
     }  
   
     public void setReset(boolean reset) {  
         this.reset = reset;  
     }  
   
     public void layerAdded(MapLayerListEvent event) {  
         changed = true;  
   
         if (context.getLayers().length == 1) { // the first one  
   
             try {  
 //xulu.sc      
 //            mapArea = context.getLayerBounds();  
               mapArea = context.getAreaOfInterest();  
               if ( mapArea == null )  
                 mapArea = context.getLayerBounds();  
 //xulu.ec  
             } catch (IOException e) {  
                 // TODO Auto-generated catch block  
                 e.printStackTrace();  
             }  
   
             reset = true;  
         }  
   
         repaint();  
     }  
   
     public void layerRemoved(MapLayerListEvent event) {  
         changed = true;  
         repaint();  
     }  
   
     public void layerChanged(MapLayerListEvent event) {  
         changed = true;  
         // System.out.println("layer changed - repaint");  
         repaint();  
     }  
   
     public void layerMoved(MapLayerListEvent event) {  
         changed = true;  
         repaint();  
     }  
   
     protected void drawRectangle(Graphics graphics) {  
         // undraw last box/draw new box  
         int left = Math.min(startX, lastX);  
         int right = Math.max(startX, lastX);  
         int top = Math.max(startY, lastY);  
         int bottom = Math.min(startY, lastY);  
         int width = right - left;  
         int height = top - bottom;  
         // System.out.println("drawing rect("+left+","+bottom+","+ width+","+  
         // height+")");  
         graphics.drawRect(left, bottom, width, height);  
     }  
   
     /**  
      * if clickable is set to true then a single click on the map pane will zoom  
      * or pan the map.  
      *  
      * @param clickable  
      */  
     public void setClickable(boolean clickable) {  
         this.clickable = clickable;  
     }  
   
     public void mouseMoved(MouseEvent e) {  
     }  
   
     public FeatureCollection getSelection() {  
         return selection;  
     }  
   
     public void setSelection(FeatureCollection selection) {  
         this.selection = selection;  
         repaint();  
     }  
   
     /* (non-Javadoc)  
      * @see org.geotools.gui.swing.event.SelectionChangeListener#selectionChanged(org.geotools.gui.swing.event.SelectionChangedEvent)  
      */  
     public void selectionChanged(SelectionChangedEvent e) {  
   
         try {  
             selection = selectionLayer.getFeatureSource().getFeatures(e.getFilter());  
             repaint();  
         } catch (IOException e1) {  
             e1.printStackTrace();  
         }  
     }  
   
     public SelectionManager getSelectionManager() {  
         return selectionManager;  
     }  
   
     public void setSelectionManager(SelectionManager selectionManager) {  
         this.selectionManager = selectionManager;  
         this.selectionManager.addSelectionChangeListener(this);  
864    
865      }                  org.geotools.styling.Style s = sf.createStyle();
866                    s.setTitle("selection");
867    
868                    // TODO parameterise the color
869                    final PolygonSymbolizer ps = sb.createPolygonSymbolizer(color);
870                    ps.setStroke(sb.createStroke(color));
871    
872                    final LineSymbolizer ls = sb.createLineSymbolizer(color);
873                    final Graphic h = sb.createGraphic();
874                    h.setMarks(new Mark[] { sb.createMark("square", color) });
875    
876                    final PointSymbolizer pts = sb.createPointSymbolizer(h);
877    
878                    // Rule r = sb.createRule(new Symbolizer[]{ps,ls,pts});
879                    switch (type) {
880                    case POLYGON:
881                            s = sb.createStyle(ps);
882    
883                            break;
884    
885                    case POINT:
886                            s = sb.createStyle(pts);
887    
888                            break;
889    
890                    case LINE:
891                            s = sb.createStyle(ls);
892                    }
893    
894                    return s;
895            }
896    
897    
898            public void propertyChange(final PropertyChangeEvent evt) {
899                    final String prop = evt.getPropertyName();
900    
901                    if (prop.equalsIgnoreCase("crs")) {
902                            context.setAreaOfInterest(context.getAreaOfInterest(),
903                                            (CoordinateReferenceSystem) evt.getNewValue());
904                    }
905            }
906    
907            public boolean isReset() {
908                    return reset;
909            }
910    
911            public void setReset(final boolean reset) {
912                    this.reset = reset;
913            }
914    
915            public void layerAdded(final MapLayerListEvent event) {
916                    changed = true;
917    
918                    if (context.getLayers().length == 1) { // the first one
919    
920                            try {
921                                    // xulu.sc
922                                    // mapArea = context.getLayerBounds();
923                                    mapArea = context.getAreaOfInterest();
924                                    if (mapArea == null)
925                                            mapArea = context.getLayerBounds();
926                                    // xulu.ec
927                            } catch (final IOException e) {
928                                    // TODO Auto-generated catch block
929                                    e.printStackTrace();
930                            }
931    
932                            reset = true;
933                    }
934    
935                    repaint();
936            }
937    
938            public void layerRemoved(final MapLayerListEvent event) {
939                    changed = true;
940                    repaint();
941            }
942    
943            public void layerChanged(final MapLayerListEvent event) {
944                    changed = true;
945                    // System.out.println("layer changed - repaint");
946                    repaint();
947            }
948    
949            public void layerMoved(final MapLayerListEvent event) {
950                    changed = true;
951                    repaint();
952            }
953    
954            protected void drawRectangle(final Graphics graphics) {
955                    // undraw last box/draw new box
956                    final int left = Math.min(startX, lastX);
957                    final int right = Math.max(startX, lastX);
958                    final int top = Math.max(startY, lastY);
959                    final int bottom = Math.min(startY, lastY);
960                    final int width = right - left;
961                    final int height = top - bottom;
962                    // System.out.println("drawing rect("+left+","+bottom+","+ width+","+
963                    // height+")");
964                    graphics.drawRect(left, bottom, width, height);
965            }
966    
967  //xulu.sn          /**
968             * if clickable is set to true then a single click on the map pane will zoom
969             * or pan the map.
970             *
971             * @param clickable
972             */
973            public void setClickable(final boolean clickable) {
974                    this.clickable = clickable;
975            }
976    
977            public void mouseMoved(final MouseEvent e) {
978            }
979    
980    
981    
982            // xulu.sn
983          /**          /**
984           * Korrigiert den {@link Envelope} aka {@code mapArea} auf die beste           * Korrigiert den {@link Envelope} aka {@code mapArea} auf die beste
985           * erlaubte Flaeche damit die Massstabsbeschaenkungen noch eingehalten           * erlaubte Flaeche damit die Massstabsbeschaenkungen noch eingehalten
# Line 1258  public class JMapPane extends JPanel imp Line 998  public class JMapPane extends JPanel imp
998                          return env;                          return env;
999    
1000                  /**                  /**
1001                   * Correct the aspect Ratio before we check the rest. Otherwise we might easily fail.                   * Correct the aspect Ratio before we check the rest. Otherwise we might
1002                     * easily fail.
1003                   */                   */
1004                  env = fixAspectRatio(this.getBounds(), env);                  env = fixAspectRatio(this.getBounds(), env);
1005    
1006                  double scale = env.getWidth() / getWidth();                  final double scale = env.getWidth() / getWidth();
1007                  double centerX = env.getMinX() + env.getWidth() / 2.;                  final double centerX = env.getMinX() + env.getWidth() / 2.;
1008                  double centerY = env.getMinY() + env.getHeight() / 2.;                  final double centerY = env.getMinY() + env.getHeight() / 2.;
1009                  double newWidth2;                  double newWidth2;
1010                  double newHeight2;                  double newHeight2;
1011                  if (scale < getMaxZoomScale()) {                  if (scale < getMaxZoomScale()) {
# Line 1286  public class JMapPane extends JPanel imp Line 1027  public class JMapPane extends JPanel imp
1027                          return env;                          return env;
1028                  }                  }
1029    
1030                  Coordinate ll = new Coordinate(centerX - newWidth2, centerY                  final Coordinate ll = new Coordinate(centerX - newWidth2, centerY
1031                                  - newHeight2);                                  - newHeight2);
1032                  Coordinate ur = new Coordinate(centerX + newWidth2, centerY                  final Coordinate ur = new Coordinate(centerX + newWidth2, centerY
1033                                  + newHeight2);                                  + newHeight2);
1034    
1035                  return new Envelope(ll, ur);                  return new Envelope(ll, ur);
1036          }          }
1037    
1038    /**          /**
1039     * Retuns the minimum allowed zoom scale. This is the bigger number value of the two.           * Retuns the minimum allowed zoom scale. This is the bigger number value of
1040     * Defaults to {@link Double}.MAX_VALUE           * the two. Defaults to {@link Double}.MAX_VALUE
1041     *           *
1042     * @author <a href="mailto:[email protected]">Stefan Alfons Kr&uuml;ger</a>           * @author <a href="mailto:[email protected]">Stefan Alfons
1043     */           *         Kr&uuml;ger</a>
1044    public Double getMinZoomScale() {           */
1045      return minZoomScale;          public Double getMinZoomScale() {
1046    }                  return minZoomScale;
1047            }
1048    /**  
1049     * Retuns the maximum allowed zoom scale. This is the smaller number value of the two.          /**
1050     * Defaults to {@link Double}.MIN_VALUE           * Retuns the maximum allowed zoom scale. This is the smaller number value
1051     *           * of the two. Defaults to {@link Double}.MIN_VALUE
1052     * @author <a href="mailto:[email protected]">Stefan Alfons Kr&uuml;ger</a>           *
1053     */           * @author <a href="mailto:[email protected]">Stefan Alfons
1054    public Double getMaxZoomScale() {           *         Kr&uuml;ger</a>
1055      return maxZoomScale;           */
1056    }          public Double getMaxZoomScale() {
1057                    return maxZoomScale;
1058    /**          }
    * Set the maximum allowed zoom scale. This is the smaller number value of the two.  
    *  
    * @author <a href="mailto:[email protected]">Stefan Alfons Kr&uuml;ger</a>  
    */  
   public void setMaxZoomScale(Double maxZoomScale) {  
     // System.out.println("setting max scale to "+maxZoomScale);  
     this.maxZoomScale = maxZoomScale;  
   }  
   
   /**  
    * Set the minimum (nearest) allowed zoom scale. This is the bigger number value of the two.  
    *  
    * @author <a href="mailto:[email protected]">Stefan Alfons Kr&uuml;ger</a>  
    */  
   public void setMinZoomScale(Double minZoomScale) {  
     this.minZoomScale = minZoomScale;  
   }  
 //xulu.en  
1059    
1060            /**
1061             * Set the maximum allowed zoom scale. This is the smaller number value of
1062             * the two.
1063             *
1064             * @author <a href="mailto:[email protected]">Stefan Alfons
1065             *         Kr&uuml;ger</a>
1066             */
1067            public void setMaxZoomScale(final Double maxZoomScale) {
1068                    // System.out.println("setting max scale to "+maxZoomScale);
1069                    this.maxZoomScale = maxZoomScale;
1070            }
1071    
1072            /**
1073             * Set the minimum (nearest) allowed zoom scale. This is the bigger number
1074             * value of the two.
1075             *
1076             * @author <a href="mailto:[email protected]">Stefan Alfons
1077             *         Kr&uuml;ger</a>
1078             */
1079            public void setMinZoomScale(final Double minZoomScale) {
1080                    this.minZoomScale = minZoomScale;
1081            }
1082            // xulu.en
1083    
1084  }  }

Legend:
Removed from v.127  
changed lines
  Added in v.341

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26