Package org.openstreetmap.josm.gui.layer.markerlayer

Source Code of org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer

// License: GPL. Copyright 2007 by Immanuel Scholz and others
package org.openstreetmap.josm.gui.layer.markerlayer;

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

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;

import javax.swing.Icon;
import javax.swing.JColorChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.RenameLayerAction;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.data.gpx.GpxLink;
import org.openstreetmap.josm.data.gpx.WayPoint;
import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.tools.AudioPlayer;
import org.openstreetmap.josm.tools.ImageProvider;

/**
* A layer holding markers.
*
* Markers are GPS points with a name and, optionally, a symbol code attached;
* marker layers can be created from waypoints when importing raw GPS data, but
* they may also come from other sources.
*
* The symbol code is for future use.
*
* The data is read only.
*/
public class MarkerLayer extends Layer {

  /**
   * A list of markers.
   */
  public Collection<Marker> data;
  private boolean mousePressed = false;
  public GpxLayer fromLayer = null;
  private MapView mapView = null;

  /*
   * private Icon audioTracerIcon = null; private EastNorth playheadPosition =
   * null; private static Timer timer = null; private static double
   * audioAnimationInterval = 0.0; // seconds private static double
   * playheadTime = -1.0;
   */
  public MarkerLayer(GpxData indata, String name, File associatedFile,
      GpxLayer fromLayer, MapView mapView) {

    super(name);
    this.setAssociatedFile(associatedFile);
    this.data = new ArrayList<Marker>();
    this.fromLayer = fromLayer;
    this.setMapView(mapView);
    double firstTime = -1.0;
    String lastLinkedFile = "";

    for (WayPoint wpt : indata.waypoints) {
      /* calculate time differences in waypoints */
      double time = wpt.time;
      boolean wpt_has_link = wpt.attr.containsKey(GpxData.META_LINKS);
      if (firstTime < 0 && wpt_has_link) {
        firstTime = time;
        for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr
            .get(GpxData.META_LINKS)) {
          lastLinkedFile = oneLink.uri;
          break;
        }
      }
      if (wpt_has_link) {
        for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr
            .get(GpxData.META_LINKS)) {
          if (!oneLink.uri.equals(lastLinkedFile))
            firstTime = time;
          lastLinkedFile = oneLink.uri;
          break;
        }
      }
      Marker m = Marker.createMarker(wpt, indata.storageFile, this, time,
          time - firstTime);
      if (m != null)
        data.add(m);
    }

    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MarkerLayer.this.mapView.addMouseListener(new MouseAdapter() {
          @Override
          public void mousePressed(MouseEvent e) {
            if (e.getButton() != MouseEvent.BUTTON1)
              return;
            boolean mousePressedInButton = false;
            if (e.getPoint() != null) {
              for (Marker mkr : data) {
                if (mkr.containsPoint(e.getPoint())) {
                  mousePressedInButton = true;
                  break;
                }
              }
            }
            if (!mousePressedInButton)
              return;
            mousePressed = true;
            if (visible)
              MarkerLayer.this.mapView.repaint();
          }

          @Override
          public void mouseReleased(MouseEvent ev) {
            if (ev.getButton() != MouseEvent.BUTTON1
                || !mousePressed)
              return;
            mousePressed = false;
            if (!visible)
              return;
            if (ev.getPoint() != null) {
              for (Marker mkr : data) {
                if (mkr.containsPoint(ev.getPoint()))
                  mkr.actionPerformed(new ActionEvent(this,
                      0, null));
              }
            }
            MarkerLayer.this.mapView.repaint();
          }
        });
      }
    });
  }

  /**
   * Return a static icon.
   */
  @Override
  public Icon getIcon() {
    return ImageProvider.get("layer", "marker_small");
  }

  public void setMapView(MapView mapView) {
    this.mapView = mapView;
  }

  static public Color getColor(String name) {
    return Main.pref.getColor(marktr("gps marker"), name != null ? "layer "
        + name : null, Color.gray);
  }

  @Override
  public void paint(Graphics g, MapView mv) {
    boolean mousePressedTmp = mousePressed;
    Point mousePos = mv.getMousePosition();
    String mkrTextShow = Main.pref.get("marker.show " + name, "show");

    // g.setColor(getColor(name));
    g.setColor(Color.RED);
    for (Marker mkr : data) {
      Point p = mv.getPoint(mkr.eastNorth);

      // g.drawLine(0, 0, p.x, p.y);
      if (mousePos != null && mkr.containsPoint(mousePos)) {
        mkr.paint(g, mv, mousePressedTmp, mkrTextShow);
        mousePressedTmp = false;
      } else {
        mkr.paint(g, mv, false, mkrTextShow);
      }
    }
  }

  @Override
  public String getToolTipText() {
    return data.size() + " " + trn("marker", "markers", data.size());
  }

  @Override
  public void mergeFrom(Layer from) {
    MarkerLayer layer = (MarkerLayer) from;
    data.addAll(layer.data);
  }

  @Override
  public boolean isMergable(Layer other) {
    return other instanceof MarkerLayer;
  }

  @Override
  public void visitBoundingBox(BoundingXYVisitor v) {
    for (Marker mkr : data)
      v.visit(mkr.eastNorth);
  }

  @Override
  public Object getInfoComponent() {
    return "<html>"
        + trn("{0} consists of {1} marker",
            "{0} consists of {1} markers", data.size(), name,
            data.size()) + "</html>";
  }

  @Override
  public Component[] getMenuEntries() {
    JMenuItem color = new JMenuItem(tr("Customize Color"),
        ImageProvider.get("colorchooser"));
    color.putClientProperty("help", "Action/LayerCustomizeColor");
    color.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JColorChooser c = new JColorChooser(getColor(name));
        Object[] options = new Object[] { tr("OK"), tr("Cancel"),
            tr("Default") };
        int answer = JOptionPane.showOptionDialog(Main.parent, c,
            tr("Choose a color"), JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
        switch (answer) {
        case 0:
          Main.pref.putColor("layer " + name, c.getColor());
          break;
        case 1:
          return;
        case 2:
          Main.pref.putColor("layer " + name, null);
          break;
        }
        Main.map.repaint();
      }
    });

    JMenuItem syncaudio = new JMenuItem(tr("Synchronize Audio"),
        ImageProvider.get("audio-sync"));
    syncaudio.putClientProperty("help", "Action/SynchronizeAudio");
    syncaudio.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (!AudioPlayer.paused()) {
          JOptionPane
              .showMessageDialog(
                  Main.parent,
                  tr("You need to pause audio at the moment when you hear your synchronization cue."));
          return;
        }
        AudioMarker recent = AudioMarker.recentlyPlayedMarker();
        if (synchronizeAudioMarkers(recent)) {
          JOptionPane
              .showMessageDialog(
                  Main.parent,
                  tr("Audio synchronized at point {0}.",
                      recent.text));
        } else {
          JOptionPane.showMessageDialog(Main.parent,
              tr("Unable to synchronize in layer being played."));
        }
      }
    });

    JMenuItem moveaudio = new JMenuItem(
        tr("Make Audio Marker at Play Head"),
        ImageProvider.get("addmarkers"));
    moveaudio.putClientProperty("help", "Action/MakeAudioMarkerAtPlayHead");
    moveaudio.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        if (!AudioPlayer.paused()) {
          JOptionPane
              .showMessageDialog(
                  Main.parent,
                  tr("You need to have paused audio at the point on the track where you want the marker."));
          return;
        }
        PlayHeadMarker playHeadMarker = MarkerLayer.this.mapView.playHeadMarker;
        if (playHeadMarker == null)
          return;
        addAudioMarker(playHeadMarker.time, playHeadMarker.eastNorth);
        MarkerLayer.this.mapView.repaint();
      }
    });

    Collection<Component> components = new ArrayList<Component>();
    components.add(new JMenuItem(new LayerListDialog.ShowHideLayerAction(
        this)));
    components.add(new JMenuItem(new LayerListDialog.ShowHideMarkerText(
        this)));
    components.add(new JMenuItem(
        new LayerListDialog.DeleteLayerAction(this)));
    components.add(new JSeparator());
    components.add(color);
    components.add(new JSeparator());
    components.add(syncaudio);
    if (Main.pref.getBoolean("marker.traceaudio", true)) {
      components.add(moveaudio);
    }
    components.add(new JMenuItem(new RenameLayerAction(getAssociatedFile(),
        this)));
    components.add(new JSeparator());
    components.add(new JMenuItem(new LayerListPopup.InfoAction(this)));
    return components.toArray(new Component[0]);
  }

  public boolean synchronizeAudioMarkers(AudioMarker startMarker) {
    if (startMarker != null && !data.contains(startMarker)) {
      startMarker = null;
    }
    if (startMarker == null) {
      // find the first audioMarker in this layer
      for (Marker m : data) {
        if (m instanceof AudioMarker) {
          startMarker = (AudioMarker) m;
          break;
        }
      }
    }
    if (startMarker == null)
      return false;

    // apply adjustment to all subsequent audio markers in the layer
    double adjustment = AudioPlayer.position() - startMarker.offset; // in
                                      // seconds
    boolean seenStart = false;
    URL url = startMarker.url();
    for (Marker m : data) {
      if (m == startMarker)
        seenStart = true;
      if (seenStart) {
        AudioMarker ma = (AudioMarker) m; // it must be an AudioMarker
        if (ma.url().equals(url))
          ma.adjustOffset(adjustment);
      }
    }
    return true;
  }

  public AudioMarker addAudioMarker(double time, EastNorth en) {
    // find first audio marker to get absolute start time
    double offset = 0.0;
    AudioMarker am = null;
    for (Marker m : data) {
      if (m.getClass() == AudioMarker.class) {
        am = (AudioMarker) m;
        offset = time - am.time;
        break;
      }
    }
    if (am == null) {
      JOptionPane
          .showMessageDialog(
              Main.parent,
              tr("No existing audio markers in this layer to offset from."));
      return null;
    }

    // make our new marker
    AudioMarker newAudioMarker = AudioMarker.create(
        Main.proj.eastNorth2latlon(en), AudioMarker.inventName(offset),
        AudioPlayer.url().toString(), this, time, offset);

    // insert it at the right place in a copy the collection
    Collection<Marker> newData = new ArrayList<Marker>();
    am = null;
    AudioMarker ret = newAudioMarker; // save to have return value
    for (Marker m : data) {
      if (m.getClass() == AudioMarker.class) {
        am = (AudioMarker) m;
        if (newAudioMarker != null && offset < am.offset) {
          newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same
                                  // as
                                  // predecessor
          newData.add(newAudioMarker);
          newAudioMarker = null;
        }
      }
      newData.add(m);
    }

    if (newAudioMarker != null) {
      if (am != null)
        newAudioMarker.adjustOffset(am.syncOffset()); // i.e. same as
                                // predecessor
      newData.add(newAudioMarker); // insert at end
    }

    // replace the collection
    data.clear();
    data.addAll(newData);
    return ret;
  }

  public void playAudio() {
    if (Main.map == null || mapView == null)
      return;
    for (Layer layer : mapView.getAllLayers()) {
      if (layer.getClass() == MarkerLayer.class) {
        MarkerLayer markerLayer = (MarkerLayer) layer;
        for (Marker marker : markerLayer.data) {
          if (marker.getClass() == AudioMarker.class) {
            ((AudioMarker) marker).play();
            break;
          }
        }
      }
    }
  }

  public void playNextMarker() {
    playAdjacentMarker(true);
  }

  public void playPreviousMarker() {
    playAdjacentMarker(false);
  }

  private void playAdjacentMarker(boolean next) {
    Marker startMarker = AudioMarker.recentlyPlayedMarker();
    if (startMarker == null) {
      // message?
      return;
    }
    Marker previousMarker = null;
    boolean nextTime = false;
    if (Main.map == null || mapView == null)
      return;
    for (Layer layer : mapView.getAllLayers()) {
      if (layer.getClass() == MarkerLayer.class) {
        MarkerLayer markerLayer = (MarkerLayer) layer;
        for (Marker marker : markerLayer.data) {
          if (marker == startMarker) {
            if (next) {
              nextTime = true;
            } else {
              if (previousMarker == null)
                previousMarker = startMarker; // if no previous
                                // one, play the
                                // first one
                                // again
              ((AudioMarker) previousMarker).play();
              break;
            }
          } else if (nextTime
              && marker.getClass() == AudioMarker.class) {
            ((AudioMarker) marker).play();
            return;
          }
          if (marker.getClass() == AudioMarker.class)
            previousMarker = marker;
        }
        if (nextTime) {
          // there was no next marker in that layer, so play the last
          // one again
          ((AudioMarker) startMarker).play();
          return;
        }
      }
    }
  }

}
TOP

Related Classes of org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer

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.