001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.history; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Rectangle; 007import java.awt.event.ActionEvent; 008import java.text.MessageFormat; 009import java.util.Arrays; 010import java.util.List; 011 012import javax.swing.AbstractAction; 013import javax.swing.Action; 014import javax.swing.JComponent; 015import javax.swing.JPopupMenu; 016 017import org.openstreetmap.josm.Main; 018import org.openstreetmap.josm.data.StructUtils; 019import org.openstreetmap.josm.data.StructUtils.StructEntry; 020import org.openstreetmap.josm.spi.preferences.Config; 021import org.openstreetmap.josm.tools.ImageProvider; 022import org.openstreetmap.josm.tools.OpenBrowser; 023 024/** 025 * A menu displaying links to external history viewers for a changeset. 026 * 027 * @since 12871 028 */ 029public class OpenChangesetPopupMenu extends JPopupMenu { 030 031 /** 032 * Constructs a new {@code OpenChangesetPopupMenu} for the given changeset id. 033 * 034 * @param changesetId the changeset id 035 */ 036 public OpenChangesetPopupMenu(final long changesetId) { 037 StructUtils.getListOfStructs(Config.getPref(), "history-dialog.tools", DEFAULT_ENTRIES, ChangesetViewerEntry.class) 038 .stream() 039 .map(entry -> entry.toAction(changesetId)) 040 .forEach(this::add); 041 } 042 043 /** 044 * Displays the popup menu at the lower-left corner of {@code parent}. 045 * 046 * @param parent the parent component to use for positioning this menu 047 */ 048 public void show(final JComponent parent) { 049 final Rectangle r = parent.getBounds(); 050 show(parent.getParent(), r.x, r.y + r.height); 051 } 052 053 private static final List<ChangesetViewerEntry> DEFAULT_ENTRIES = Arrays.asList( 054 new ChangesetViewerEntry(tr("View changeset in web browser"), Main.getBaseBrowseUrl() + "/changeset/{0}"), 055 new ChangesetViewerEntry(tr("Open {0}", "achavi (Augmented OSM Change Viewer)"), "https://overpass-api.de/achavi/?changeset={0}"), 056 new ChangesetViewerEntry(tr("Open {0}", "OSMCha (OSM Changeset Analyzer)"), "https://osmcha.mapbox.com/changesets/{0}"), 057 new ChangesetViewerEntry(tr("Open {0}", "OSM History Viewer"), "http://osmhv.openstreetmap.de/changeset.jsp?id={0}"), 058 new ChangesetViewerEntry(tr("Open {0}", "WhoDidIt (OSM Changeset Analyzer)"), 059 "http://simon04.dev.openstreetmap.org/whodidit/index.html?changeset={0}&show=1") 060 ); 061 062 /** 063 * Auxiliary class to save a link to a history viewer in the preferences. 064 */ 065 public static class ChangesetViewerEntry { 066 /** Name to be displayed in popup menu */ 067 @StructEntry 068 public String name; 069 /** Templated service url. <code>{0}</code> will be replaced by changeset id */ 070 @StructEntry 071 public String url; 072 073 /** 074 * Constructs a new {@code ChangesetViewerEntry}. 075 */ 076 public ChangesetViewerEntry() { 077 } 078 079 ChangesetViewerEntry(String name, String url) { 080 this.name = name; 081 this.url = url; 082 } 083 084 Action toAction(final long changesetId) { 085 return new OpenBrowserAction(name, MessageFormat.format(this.url, Long.toString(changesetId))); 086 } 087 } 088 089 static class OpenBrowserAction extends AbstractAction { 090 final String url; 091 092 OpenBrowserAction(String name, String url) { 093 super(name); 094 putValue(SHORT_DESCRIPTION, tr("Open {0}", url)); 095 new ImageProvider("help/internet").getResource().attachImageIcon(this, true); 096 this.url = url; 097 } 098 099 @Override 100 public void actionPerformed(ActionEvent e) { 101 OpenBrowser.displayUrl(url); 102 } 103 } 104}