    001// License: GPL. For details, see LICENSE file.
    002package org.openstreetmap.josm.plugins.streetside.mode;
    003
    004import static org.openstreetmap.josm.tools.I18n.tr;
    005
    006import java.awt.Graphics2D;
    007import java.awt.Point;
    008import java.awt.event.InputEvent;
    009import java.awt.event.MouseEvent;
    010import java.util.Objects;
    011import java.util.concurrent.ConcurrentSkipListSet;
    012
    013import javax.swing.SwingUtilities;
    014
    015import org.openstreetmap.josm.data.Bounds;
    016import org.openstreetmap.josm.data.coor.LatLon;
    017import org.openstreetmap.josm.data.osm.OsmPrimitive;
    018import org.openstreetmap.josm.gui.MainApplication;
    019import org.openstreetmap.josm.gui.MapView;
    020import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    021import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage;
    022import org.openstreetmap.josm.plugins.streetside.StreetsideData;
    023import org.openstreetmap.josm.plugins.streetside.StreetsideImage;
    024import org.openstreetmap.josm.plugins.streetside.StreetsideLayer;
    025import org.openstreetmap.josm.plugins.streetside.gui.StreetsideMainDialog;
    026import org.openstreetmap.josm.plugins.streetside.history.StreetsideRecord;
    027import org.openstreetmap.josm.plugins.streetside.history.commands.CommandMove;
    028import org.openstreetmap.josm.plugins.streetside.history.commands.CommandTurn;
    029import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
    030
    031/**
    032 * Handles the input event related with the layer. Mainly clicks.
    033 *
    034 * @author nokutu
    035 */
    036public class SelectMode extends AbstractMode {
    037  private StreetsideAbstractImage closest;
    038  private StreetsideAbstractImage lastClicked;
    039  private final StreetsideRecord record;
    040  private boolean nothingHighlighted;
    041  private boolean imageHighlighted;
    042
    043  /**
    044   * Main constructor.
    045   */
    046  public SelectMode() {
    047    record = StreetsideRecord.getInstance();
    048  }
    049
    050  @Override
    051  public void mousePressed(MouseEvent e) {
    052    if (e.getButton() != MouseEvent.BUTTON1) {
    053      return;
    054    }
    055    StreetsideAbstractImage closest = getClosest(e.getPoint());
    056    if (!(MainApplication.getLayerManager().getActiveLayer() instanceof StreetsideLayer)
    057            && closest != null && MainApplication.getMap().mapMode == MainApplication.getMap().mapModeSelect) {
    058      lastClicked = this.closest;
    059      StreetsideLayer.getInstance().getData().setSelectedImage(closest);
    060      return;
    061    } else if (MainApplication.getLayerManager().getActiveLayer() != StreetsideLayer.getInstance()) {
    062      return;
    063    }
    064    // Double click
    065    if (e.getClickCount() == 2 && StreetsideLayer.getInstance().getData().getSelectedImage() != null && closest != null) {
    066      closest.getSequence().getImages().forEach(StreetsideLayer.getInstance().getData()::addMultiSelectedImage);
    067    }
    068    lastClicked = this.closest;
    069    this.closest = closest;
    070    if (closest != null && StreetsideLayer.getInstance().getData().getMultiSelectedImages().contains(closest)) {
    071      return;
    072    }
    073    // ctrl+click
    074    if (e.getModifiers() == (InputEvent.BUTTON1_MASK | InputEvent.CTRL_MASK) && closest != null) {
    075      StreetsideLayer.getInstance().getData().addMultiSelectedImage(closest);
    076      // shift + click
    077    } else if (
    078            e.getModifiers() == (InputEvent.BUTTON1_MASK | InputEvent.SHIFT_MASK)
    079                    && lastClicked instanceof StreetsideImage
    080            ) {
    081      if (this.closest != null
    082              && this.closest.getSequence() == (lastClicked).getSequence()) {
    083        int i = this.closest.getSequence().getImages().indexOf(this.closest);
    084        int j = lastClicked.getSequence().getImages().indexOf(lastClicked);
    085        StreetsideLayer.getInstance().getData().addMultiSelectedImage(
    086                i < j
    087                        ? new ConcurrentSkipListSet<>(this.closest.getSequence().getImages().subList(i, j + 1))
    088                        : new ConcurrentSkipListSet<>(this.closest.getSequence().getImages().subList(j, i + 1))
    089        );
    090      }
    091      // click
    092    } else {
    093      StreetsideLayer.getInstance().getData().setSelectedImage(closest);
    094    }
    095  }
    096
    097  @Override
    098  public void mouseDragged(MouseEvent e) {
    099    StreetsideAbstractImage highlightImg = StreetsideLayer.getInstance().getData().getHighlightedImage();
    100    if (
    101            MainApplication.getLayerManager().getActiveLayer() == StreetsideLayer.getInstance()
    102                && SwingUtilities.isLeftMouseButton(e)
    103                && highlightImg != null && highlightImg.getLatLon() != null
    104            ) {
    105      Point highlightImgPoint = MainApplication.getMap().mapView.getPoint(highlightImg.getTempLatLon());
    106      if (e.isShiftDown()) { // turn
    107        StreetsideLayer.getInstance().getData().getMultiSelectedImages().parallelStream().filter(img -> !(img instanceof StreetsideImage) || StreetsideProperties.DEVELOPER.get())
    108                .forEach(img -> img.turn(Math.toDegrees(Math.atan2(e.getX() - highlightImgPoint.getX(), -e.getY() + highlightImgPoint.getY())) - highlightImg.getTempHe()));
    109      } else { // move
    110        LatLon eventLatLon = MainApplication.getMap().mapView.getLatLon(e.getX(), e.getY());
    111        LatLon imgLatLon = MainApplication.getMap().mapView.getLatLon(highlightImgPoint.getX(), highlightImgPoint.getY());
    112        StreetsideLayer.getInstance().getData().getMultiSelectedImages().parallelStream().filter(img -> !(img instanceof StreetsideImage) || StreetsideProperties.DEVELOPER.get())
    113                .forEach(img -> img.move(eventLatLon.getX() - imgLatLon.getX(), eventLatLon.getY() - imgLatLon.getY()));
    114      }
    115      StreetsideLayer.invalidateInstance();
    116    }
    117  }
    118
    119  @Override
    120  public void mouseReleased(MouseEvent e) {
    121    final StreetsideData data = StreetsideLayer.getInstance().getData();
    122    if (data.getSelectedImage() == null) {
    123      return;
    124    }
    125    if (!Objects.equals(data.getSelectedImage().getTempHe(), data.getSelectedImage().getMovingHe())) {
    126      double from = data.getSelectedImage().getTempHe();
    127      double to = data.getSelectedImage().getMovingHe();
    128      record.addCommand(new CommandTurn(data.getMultiSelectedImages(), to - from));
    129    } else if (!Objects.equals(data.getSelectedImage().getTempLatLon(), data.getSelectedImage().getMovingLatLon())) {
    130      LatLon from = data.getSelectedImage().getTempLatLon();
    131      LatLon to = data.getSelectedImage().getMovingLatLon();
    132      record.addCommand(new CommandMove(data.getMultiSelectedImages(), to.getX() - from.getX(), to.getY() - from.getY()));
    133    }
    134    data.getMultiSelectedImages().parallelStream().filter(Objects::nonNull).forEach(StreetsideAbstractImage::stopMoving);
    135    StreetsideLayer.invalidateInstance();
    136  }
    137
    138  /**
    139   * Checks if the mouse is over pictures.
    140   */
    141  @Override
    142  public void mouseMoved(MouseEvent e) {
    143    if (MainApplication.getLayerManager().getActiveLayer() instanceof OsmDataLayer
    144            && MainApplication.getMap().mapMode != MainApplication.getMap().mapModeSelect) {
    145      return;
    146    }
    147    if (!StreetsideProperties.HOVER_ENABLED.get()) {
    148      return;
    149    }
    150
    151    StreetsideAbstractImage closestTemp = getClosest(e.getPoint());
    152
    153    final OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
    154    if (editLayer != null) {
    155      if (closestTemp != null && !imageHighlighted) {
    156        if (MainApplication.getMap().mapMode != null) {
    157          MainApplication.getMap().mapMode.putValue("active", Boolean.FALSE);
    158        }
    159        imageHighlighted = true;
    160      } else if (closestTemp == null && imageHighlighted && nothingHighlighted) {
    161        if (MainApplication.getMap().mapMode != null) {
    162          MainApplication.getMap().mapMode.putValue("active", Boolean.TRUE);
    163        }
    164        nothingHighlighted = false;
    165      } else if (imageHighlighted && !nothingHighlighted && editLayer.data != null) {
    166        for (OsmPrimitive primivitive : MainApplication.getLayerManager().getEditLayer().data.allPrimitives()) {
    167          primivitive.setHighlighted(false);
    168        }
    169        imageHighlighted = false;
    170        nothingHighlighted = true;
    171      }
    172    }
    173
    174    if (StreetsideLayer.getInstance().getData().getHighlightedImage() != closestTemp && closestTemp != null) {
    175      StreetsideLayer.getInstance().getData().setHighlightedImage(closestTemp);
    176      StreetsideMainDialog.getInstance().setImage(closestTemp);
    177      StreetsideMainDialog.getInstance().updateImage(false);
    178
    179    } else if (StreetsideLayer.getInstance().getData().getHighlightedImage() != closestTemp && closestTemp == null) {
    180      StreetsideLayer.getInstance().getData().setHighlightedImage(null);
    181      StreetsideMainDialog.getInstance().setImage(StreetsideLayer.getInstance().getData().getSelectedImage());
    182      StreetsideMainDialog.getInstance().updateImage();
    183    }
    184
    185    StreetsideLayer.invalidateInstance();
    186  }
    187
    188  @Override
    189  public void paint(Graphics2D g, MapView mv, Bounds box) {
    190  }
    191
    192  @Override
    193  public String toString() {
    194    return tr("Select mode");
    195  }
    196}