Package org.openstreetmap.josm.gui

Source Code of org.openstreetmap.josm.gui.MapView

// License: GPL. See LICENSE file for details.

package org.openstreetmap.josm.gui;

import static org.openstreetmap.josm.tools.I18n.tr;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedList;

import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.AutoScaleAction;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.actions.MoveAction;
import org.openstreetmap.josm.actions.mapmode.MapMode;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.SelectionChangedListener;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.DataSource;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
import org.openstreetmap.josm.data.projection.Projection;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.MapViewPaintable;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer.ModifiedChangedListener;
import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;

import es.emergya.ui.gis.IMapView;

/**
* This is a component used in the MapFrame for browsing the map. It use is to
* provide the MapMode's enough capabilities to operate.
*
* MapView hold meta-data about the data set currently displayed, as scale
* level, center point viewed, what scrolling mode or editing mode is selected
* or with what projection the map is viewed etc..
*
* MapView is able to administrate several layers.
*
* @author imi
*/
public class MapView extends NavigatableComponent implements IMapView {

  /**
   * A list of all layers currently loaded.
   */
  protected ArrayList<Layer> layers = new ArrayList<Layer>();
  /**
   * The play head marker: there is only one of these so it isn't in any
   * specific layer
   */
  public PlayHeadMarker playHeadMarker = null;
  /**
   * Direct link to the edit layer (if any) in the layers list.
   */
  public OsmDataLayer editLayer;
  /**
   * The layer from the layers list that is currently active.
   */
  protected Layer activeLayer;

  /**
   * The last event performed by mouse.
   */
  public MouseEvent lastMEvent;

  private LinkedList<MapViewPaintable> temporaryLayers = new LinkedList<MapViewPaintable>();

  private BufferedImage offscreenBuffer;

  public MapView() {
    addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        removeComponentListener(this);

        MapSlider zoomSlider = new MapSlider(MapView.this);
        add(zoomSlider);
        zoomSlider.setBounds(3, 0, 114, 30);

        MapScaler scaler = new MapScaler(MapView.this, Main.proj);
        add(scaler);
        scaler.setLocation(10, 30);

        if (!zoomToEditLayerBoundingBox())
          new AutoScaleAction("data").actionPerformed(null);

        new MapMover(MapView.this, Main.contentPane);
        JosmAction mv;
        mv = new MoveAction(MoveAction.Direction.UP);
        if (mv.getShortcut() != null) {
          Main.contentPane.getInputMap(
              JComponent.WHEN_IN_FOCUSED_WINDOW).put(
              mv.getShortcut().getKeyStroke(), "UP");
          Main.contentPane.getActionMap().put("UP", mv);
        }
        mv = new MoveAction(MoveAction.Direction.DOWN);
        if (mv.getShortcut() != null) {
          Main.contentPane.getInputMap(
              JComponent.WHEN_IN_FOCUSED_WINDOW).put(
              mv.getShortcut().getKeyStroke(), "DOWN");
          Main.contentPane.getActionMap().put("DOWN", mv);
        }
        mv = new MoveAction(MoveAction.Direction.LEFT);
        if (mv.getShortcut() != null) {
          Main.contentPane.getInputMap(
              JComponent.WHEN_IN_FOCUSED_WINDOW).put(
              mv.getShortcut().getKeyStroke(), "LEFT");
          Main.contentPane.getActionMap().put("LEFT", mv);
        }
        mv = new MoveAction(MoveAction.Direction.RIGHT);
        if (mv.getShortcut() != null) {
          Main.contentPane.getInputMap(
              JComponent.WHEN_IN_FOCUSED_WINDOW).put(
              mv.getShortcut().getKeyStroke(), "RIGHT");
          Main.contentPane.getActionMap().put("RIGHT", mv);
        }
      }
    });

    // listend to selection changes to redraw the map
    DataSet.selListeners.add(new SelectionChangedListener() {
      public void selectionChanged(
          Collection<? extends OsmPrimitive> newSelection) {
        repaint();
      }
    });

    // store the last mouse action
    this.addMouseMotionListener(new MouseMotionListener() {
      public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
      }

      public void mouseMoved(MouseEvent e) {
        lastMEvent = e;
      }
    });
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#addLayer(org.openstreetmap.josm.gui
   * .layer.Layer)
   */
  @Override
  public void addLayer(Layer layer) {
    addLayer(layer, 0);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#addLayer(org.openstreetmap.josm.gui
   * .layer.Layer, int)
   */
  @Override
  public void addLayer(Layer layer, int pos) {
    if (layer instanceof OsmDataLayer) {
      editLayer = (OsmDataLayer) layer;
      Main.ds = editLayer.data;
      editLayer.listenerModified.add(new ModifiedChangedListener() {
        public void modifiedChanged(boolean value, OsmDataLayer source) {
          JOptionPane.getFrameForComponent(Main.parent).setTitle(
              (value ? "*" : "")
                  + tr("Java OpenStreetMap Editor"));
        }
      });
    }
    if (layer instanceof MarkerLayer && playHeadMarker == null)
      playHeadMarker = PlayHeadMarker.create();
    // int pos = 0;//layers.size();
    // while(pos > 0 && layers.get(pos-1).background)
    // --pos;
    layers.add(pos, layer);

    for (Layer.LayerChangeListener l : Layer.listeners)
      l.layerAdded(layer);
    if (layer instanceof OsmDataLayer || activeLayer == null) {
      // autoselect the new layer
      Layer old = activeLayer;
      setActiveLayer(layer);
      for (Layer.LayerChangeListener l : Layer.listeners)
        l.activeLayerChange(old, layer);
    }
    repaint();
  }

  @Override
  protected DataSet getData() {
    if (activeLayer != null && activeLayer instanceof OsmDataLayer)
      return ((OsmDataLayer) activeLayer).data;
    return new DataSet();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#isDrawableLayer()
   */
  @Override
  public Boolean isDrawableLayer() {
    return activeLayer != null && activeLayer instanceof OsmDataLayer;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#isVisibleDrawableLayer()
   */
  @Override
  public Boolean isVisibleDrawableLayer() {
    return isDrawableLayer() && activeLayer.visible;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#removeLayer(org.openstreetmap.josm
   * .gui.layer.Layer)
   */
  @Override
  public void removeLayer(Layer layer) {
    if (layers.remove(layer)) {
      for (Layer.LayerChangeListener l : Layer.listeners)
        l.layerRemoved(layer);
    }
    if (layer == editLayer) {
      editLayer = null;
      Main.ds.setSelected();
    }
    layer.destroy();
  }

  private Boolean virtualnodes = false;

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#enableVirtualNodes(java.lang.Boolean)
   */
  @Override
  public void enableVirtualNodes(Boolean state) {
    if (virtualnodes != state) {
      virtualnodes = state;
      repaint();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#useVirtualNodes()
   */
  @Override
  public Boolean useVirtualNodes() {
    return virtualnodes;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#moveLayer(org.openstreetmap.josm.
   * gui.layer.Layer, int)
   */
  @Override
  public void moveLayer(Layer layer, int pos) {
    int curLayerPos = layers.indexOf(layer);
    if (curLayerPos == -1)
      throw new IllegalArgumentException(tr("layer not in list."));
    if (pos == curLayerPos)
      return; // already in place.
    layers.remove(curLayerPos);
    if (pos >= layers.size())
      layers.add(layer);
    else
      layers.add(pos, layer);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#getLayerPos(org.openstreetmap.josm
   * .gui.layer.Layer)
   */
  @Override
  public int getLayerPos(Layer layer) {
    int curLayerPos = layers.indexOf(layer);
    if (curLayerPos == -1)
      throw new IllegalArgumentException(tr("layer not in list."));
    return curLayerPos;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#paint(java.awt.Graphics)
   */
  @Override
  public void paint(Graphics g) {
    if (center == null)
      return; // no data loaded yet.

    // re-create offscreen-buffer if we've been resized, otherwise
    // just re-use it.
    if (null == offscreenBuffer || offscreenBuffer.getWidth() != getWidth()
        || offscreenBuffer.getHeight() != getHeight())
      offscreenBuffer = new BufferedImage(getWidth(), getHeight(),
          BufferedImage.TYPE_INT_ARGB);

    Graphics2D tempG = offscreenBuffer.createGraphics();
    tempG.setColor(Main.pref.getColor("background", Color.BLACK));
    tempG.fillRect(0, 0, getWidth(), getHeight());

    for (int i = layers.size() - 1; i >= 0; --i) {
      Layer l = layers.get(i);
      if (l.visible/* && l != getActiveLayer() */)
        l.paint(tempG, this);
    }

    /*
     * if (getActiveLayer() != null && getActiveLayer().visible)
     * getActiveLayer().paint(tempG, this);
     */

    for (MapViewPaintable mvp : temporaryLayers) {
      mvp.paint(tempG, this);
    }

    // draw world borders
    tempG.setColor(Color.WHITE);
    Bounds b = new Bounds();
    Point min = getPoint(getProjection().latlon2eastNorth(b.min));
    Point max = getPoint(getProjection().latlon2eastNorth(b.max));
    int x1 = Math.min(min.x, max.x);
    int y1 = Math.min(min.y, max.y);
    int x2 = Math.max(min.x, max.x);
    int y2 = Math.max(min.y, max.y);
    if (x1 > 0 || y1 > 0 || x2 < getWidth() || y2 < getHeight())
      tempG.drawRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);

    if (playHeadMarker != null)
      playHeadMarker.paint(tempG, this);

    g.drawImage(offscreenBuffer, 0, 0, null);
    super.paint(g);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#recalculateCenterScale(org.openstreetmap
   * .josm.data.osm.visitor.BoundingXYVisitor)
   */
  @Override
  public void recalculateCenterScale(BoundingXYVisitor box) {
    // -20 to leave some border
    int w = getWidth() - 20;
    if (w < 20)
      w = 20;
    int h = getHeight() - 20;
    if (h < 20)
      h = 20;

    EastNorth oldCenter = center;
    double oldScale = this.scale;

    if (box == null || box.min == null || box.max == null) {
      // no bounds means whole world
      center = getProjection().latlon2eastNorth(new LatLon(0, 0));
      EastNorth world = getProjection().latlon2eastNorth(
          new LatLon(Projection.MAX_LAT, Projection.MAX_LON));
      double scaleX = world.east() * 2 / w;
      double scaleY = world.north() * 2 / h;
      scale = Math.max(scaleX, scaleY); // minimum scale to see all of the
                        // screen
    } else {
      if (box.min.equals(box.max))
        box.enlargeBoundingBox();
      center = new EastNorth(box.min.east() / 2 + box.max.east() / 2,
          box.min.north() / 2 + box.max.north() / 2);
      double scaleX = (box.max.east() - box.min.east()) / w;
      double scaleY = (box.max.north() - box.min.north()) / h;
      scale = Math.max(scaleX, scaleY); // minimum scale to see all of the
                        // screen
    }

    if (!center.equals(oldCenter))
      firePropertyChange("center", oldCenter, center);
    if (oldScale != scale)
      firePropertyChange("scale", oldScale, scale);
    repaint();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#getAllLayers()
   */
  @Override
  public Collection<Layer> getAllLayers() {
    return Collections.unmodifiableCollection(layers);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#setActiveLayer(org.openstreetmap.
   * josm.gui.layer.Layer)
   */
  @Override
  public void setActiveLayer(Layer layer) {
    if (!layers.contains(layer))
      throw new IllegalArgumentException("Layer must be in layerlist");
    if (layer instanceof OsmDataLayer) {
      editLayer = (OsmDataLayer) layer;
      Main.ds = editLayer.data;
    } else
      Main.ds.setSelected();
    DataSet.fireSelectionChanged(Main.ds.getSelected());
    Layer old = activeLayer;
    activeLayer = layer;
    if (old != layer) {
      for (Layer.LayerChangeListener l : Layer.listeners)
        l.activeLayerChange(old, layer);
    }

    /*
     * This only makes the buttons look disabled. Disabling the actions as
     * well requires the user to re-select the tool after i.e. moving a
     * layer. While testing I found that I switch layers and actions at the
     * same time and it was annoying to mind the order. This way it works as
     * visual clue for new users
     */
    for (Enumeration<AbstractButton> e = Main.map.toolGroup.getElements(); e
        .hasMoreElements();) {
      AbstractButton x = e.nextElement();
      x.setEnabled(((MapMode) x.getAction()).layerIsSupported(layer));
    }
    repaint();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#getActiveLayer()
   */
  @Override
  public Layer getActiveLayer() {
    return activeLayer;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#zoomTo(org.openstreetmap.josm.data
   * .coor.EastNorth, double)
   */
  @Override
  public void zoomTo(EastNorth newCenter, double scale) {
    EastNorth oldCenter = center;
    double oldScale = this.scale;
    super.zoomTo(newCenter, scale);
    if ((oldCenter == null && center != null) || !oldCenter.equals(center))
      firePropertyChange("center", oldCenter, center);
    if (oldScale != scale)
      firePropertyChange("scale", oldScale, scale);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.openstreetmap.josm.gui.IMapView#zoomToEditLayerBoundingBox()
   */
  @Override
  public boolean zoomToEditLayerBoundingBox() {
    // workaround for #1461 (zoom to download bounding box instead of all
    // data)
    // In case we already have an existing data layer ...
    Collection<DataSource> dataSources = Main.main.editLayer().data.dataSources;
    // ... with bounding box[es] of data loaded from OSM or a file...
    BoundingXYVisitor bbox = new BoundingXYVisitor();
    for (DataSource ds : dataSources) {
      if (ds.bounds != null) {
        bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.max));
        bbox.visit(Main.proj.latlon2eastNorth(ds.bounds.min));
      }
      if (bbox.max != null && bbox.min != null
          && !bbox.max.equals(bbox.min)) {
        // ... we zoom to it's bounding box
        recalculateCenterScale(bbox);
        return true;
      }
    }
    return false;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#addTemporaryLayer(org.openstreetmap
   * .josm.gui.layer.MapViewPaintable)
   */
  @Override
  public boolean addTemporaryLayer(MapViewPaintable mvp) {
    if (temporaryLayers.contains(mvp))
      return false;
    return temporaryLayers.add(mvp);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.openstreetmap.josm.gui.IMapView#removeTemporaryLayer(org.openstreetmap
   * .josm.gui.layer.MapViewPaintable)
   */
  @Override
  public boolean removeTemporaryLayer(MapViewPaintable mvp) {
    return temporaryLayers.remove(mvp);
  }
}
TOP

Related Classes of org.openstreetmap.josm.gui.MapView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.