// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.actions.relation;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.plaf.basic.BasicArrowButton;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.data.UndoRedoHandler.CommandQueueListener;
import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.SideButton;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.Shortcut;
/**
* Action for accessing recent relations.
* @since 9668
*/
public class RecentRelationsAction extends JosmAction implements CommandQueueListener {
private final SideButton editButton;
private final BasicArrowButton arrow;
private final Shortcut shortcut;
private final LaunchEditorAction launchAction;
/**
* Constructs a new RecentRelationsAction
.
* @param editButton edit button
*/
public RecentRelationsAction(SideButton editButton) {
super(RecentRelationsAction.class.getName(), null, null, null, false, true);
this.editButton = editButton;
arrow = editButton.createArrow(this);
arrow.setToolTipText(tr("List of recent relations"));
MainApplication.undoRedo.addCommandQueueListener(this);
enableArrow();
shortcut = Shortcut.registerShortcut(
"relationeditor:editrecentrelation",
tr("Relation Editor: {0}", tr("Open recent relation")),
KeyEvent.VK_ESCAPE,
Shortcut.SHIFT
);
launchAction = new LaunchEditorAction();
MainApplication.registerActionShortcut(launchAction, shortcut);
}
/**
* Enables arrow button.
*/
public void enableArrow() {
if (arrow != null) {
arrow.setVisible(getLastRelation() != null);
}
}
/**
* Returns the last relation.
* @return the last relation
*/
public static Relation getLastRelation() {
List recentRelations = getRecentRelationsOnActiveLayer();
if (recentRelations == null || recentRelations.isEmpty())
return null;
for (Relation relation: recentRelations) {
if (!isRelationListable(relation))
continue;
return relation;
}
return null;
}
/**
* Determines if the given relation is listable in last relations.
* @param relation relation
* @return {@code true} if relation is non null, not deleted, and in current dataset
*/
public static boolean isRelationListable(Relation relation) {
return relation != null &&
!relation.isDeleted() &&
MainApplication.getLayerManager().getEditDataSet().containsRelation(relation);
}
@Override
public void actionPerformed(ActionEvent e) {
RecentRelationsPopupMenu.launch(editButton, shortcut.getKeyStroke());
}
@Override
public void commandChanged(int queueSize, int redoSize) {
enableArrow();
}
@Override
protected void updateEnabledState() {
enableArrow();
}
@Override
public void destroy() {
MainApplication.unregisterActionShortcut(launchAction, shortcut);
super.destroy();
}
/**
* Returns the list of recent relations on active layer.
* @return the list of recent relations on active layer
*/
public static List getRecentRelationsOnActiveLayer() {
if (!MainApplication.isDisplayingMapView())
return Collections.emptyList();
Layer activeLayer = MainApplication.getLayerManager().getActiveLayer();
if (!(activeLayer instanceof OsmDataLayer)) {
return Collections.emptyList();
} else {
return ((OsmDataLayer) activeLayer).getRecentRelations();
}
}
static class LaunchEditorAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
EditRelationAction.launchEditor(getLastRelation());
}
}
static class RecentRelationsPopupMenu extends JPopupMenu {
/**
* Constructs a new {@code RecentRelationsPopupMenu}.
* @param recentRelations list of recent relations
* @param keystroke key stroke for the first menu item
*/
RecentRelationsPopupMenu(List recentRelations, KeyStroke keystroke) {
boolean first = true;
for (Relation relation: recentRelations) {
if (!isRelationListable(relation))
continue;
JMenuItem menuItem = new RecentRelationsMenuItem(relation);
if (first) {
menuItem.setAccelerator(keystroke);
first = false;
}
menuItem.setIcon(ImageProvider.getPadded(relation, ImageProvider.ImageSizes.MENU.getImageDimension()));
add(menuItem);
}
}
static void launch(Component parent, KeyStroke keystroke) {
Rectangle r = parent.getBounds();
new RecentRelationsPopupMenu(getRecentRelationsOnActiveLayer(), keystroke).show(parent, r.x, r.y + r.height);
}
}
/**
* A specialized {@link JMenuItem} for presenting one entry of the relation history
*/
static class RecentRelationsMenuItem extends JMenuItem implements ActionListener {
private final transient Relation relation;
RecentRelationsMenuItem(Relation relation) {
super(relation.getDisplayName(DefaultNameFormatter.getInstance()));
this.relation = relation;
addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
EditRelationAction.launchEditor(relation);
}
}
}