001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.history; 003 004import java.awt.event.FocusEvent; 005import java.awt.event.FocusListener; 006import java.util.Collection; 007import java.util.Collections; 008import java.util.Map; 009import java.util.function.IntFunction; 010import java.util.function.Supplier; 011 012import javax.swing.JPopupMenu; 013import javax.swing.JTable; 014import javax.swing.ListSelectionModel; 015 016import org.openstreetmap.josm.actions.RestorePropertyAction; 017import org.openstreetmap.josm.data.osm.OsmPrimitive; 018import org.openstreetmap.josm.data.osm.Tagged; 019import org.openstreetmap.josm.gui.dialogs.properties.CopyAllKeyValueAction; 020import org.openstreetmap.josm.gui.dialogs.properties.CopyKeyValueAction; 021import org.openstreetmap.josm.gui.dialogs.properties.CopyValueAction; 022import org.openstreetmap.josm.gui.dialogs.properties.HelpTagAction; 023import org.openstreetmap.josm.gui.dialogs.properties.TaginfoAction; 024import org.openstreetmap.josm.gui.util.TableHelper; 025import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher; 026 027/** 028 * TagInfoViewer is a UI component which displays the list of tags of two 029 * version of a {@link org.openstreetmap.josm.data.osm.OsmPrimitive} in a {@link org.openstreetmap.josm.data.osm.history.History}. 030 * 031 * <ul> 032 * <li>on the left, it displays the list of tags for the version at {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li> 033 * <li>on the right, it displays the list of tags for the version at {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li> 034 * </ul> 035 * @since 1709 036 */ 037public class TagInfoViewer extends HistoryViewerPanel { 038 private static final class RepaintOnFocusChange implements FocusListener { 039 @Override 040 public void focusLost(FocusEvent e) { 041 repaintSelected(e); 042 } 043 044 @Override 045 public void focusGained(FocusEvent e) { 046 repaintSelected(e); 047 } 048 049 private static void repaintSelected(FocusEvent e) { 050 // we would only need the selected rows, but this is easier: 051 e.getComponent().repaint(); 052 } 053 } 054 055 /** 056 * Constructs a new {@code TagInfoViewer}. 057 * @param model The history browsing model 058 */ 059 public TagInfoViewer(HistoryBrowserModel model) { 060 super(model); 061 } 062 063 @Override 064 protected JTable buildReferenceTable() { 065 return buildTable(PointInTimeType.REFERENCE_POINT_IN_TIME); 066 } 067 068 @Override 069 protected JTable buildCurrentTable() { 070 return buildTable(PointInTimeType.CURRENT_POINT_IN_TIME); 071 } 072 073 private JTable buildTable(PointInTimeType pointInTime) { 074 TagTableModel tagTableModel = model.getTagTableModel(pointInTime); 075 JTable table = new JTable(tagTableModel, new TagTableColumnModel()); 076 TableHelper.setFont(table, getClass()); 077 table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 078 selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel()); 079 table.getTableHeader().setReorderingAllowed(false); 080 table.setTransferHandler(new TagInfoTransferHandler()); 081 table.addFocusListener(new RepaintOnFocusChange()); 082 JPopupMenu tagMenu = new JPopupMenu(); 083 084 IntFunction<String> tagKeyFn = x -> (String) table.getValueAt(x, 0); 085 IntFunction<String> tagValueFn = x -> tagTableModel.getValue(tagKeyFn.apply(x)); 086 IntFunction<Map<String, Integer>> tagValuesFn = x -> { 087 String value = tagValueFn.apply(x); 088 return value != null ? Collections.singletonMap(value, 1) : Collections.emptyMap(); 089 }; 090 Supplier<Collection<? extends Tagged>> objectSp = () -> Collections.singletonList(model.getPointInTime(pointInTime)); 091 Supplier<OsmPrimitive> primitiveSupplier = () -> getPrimitiveFromDataSet(pointInTime); 092 093 tagMenu.add(trackJosmAction(new CopyValueAction(table, tagKeyFn, objectSp))); 094 final CopyKeyValueAction copyKeyValueAction = new CopyKeyValueAction(table, tagKeyFn, objectSp); 095 tagMenu.add(trackJosmAction(copyKeyValueAction)); 096 tagMenu.addPopupMenuListener(copyKeyValueAction); 097 tagMenu.add(trackJosmAction(new CopyAllKeyValueAction(table, tagKeyFn, objectSp))); 098 tagMenu.add(new RestorePropertyAction(tagKeyFn, tagValueFn, primitiveSupplier, table.getSelectionModel())); 099 tagMenu.addSeparator(); 100 tagMenu.add(trackJosmAction(new HelpTagAction(table, tagKeyFn, tagValuesFn))); 101 TaginfoAction taginfoAction = new TaginfoAction(table, tagKeyFn, tagValuesFn, null, null); 102 tagMenu.add(trackJosmAction(taginfoAction.toTagHistoryAction())); 103 tagMenu.add(trackJosmAction(taginfoAction)); 104 105 table.addMouseListener(new PopupMenuLauncher(tagMenu)); 106 return table; 107 } 108}