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.Arrays;
007import java.util.Collection;
008import java.util.HashMap;
009import java.util.Map;
010import java.util.function.IntFunction;
011import java.util.function.Supplier;
012
013import javax.swing.JPopupMenu;
014import javax.swing.JTable;
015import javax.swing.ListSelectionModel;
016
017import org.openstreetmap.josm.data.osm.Tagged;
018import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
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.HelpAction;
023import org.openstreetmap.josm.gui.dialogs.properties.TaginfoAction;
024import org.openstreetmap.josm.gui.widgets.PopupMenuLauncher;
025
026/**
027 * TagInfoViewer is a UI component which displays the list of tags of two
028 * version of a {@link org.openstreetmap.josm.data.osm.OsmPrimitive} in a {@link org.openstreetmap.josm.data.osm.history.History}.
029 *
030 * <ul>
031 *   <li>on the left, it displays the list of tags for the version at {@link PointInTimeType#REFERENCE_POINT_IN_TIME}</li>
032 *   <li>on the right, it displays the list of tags for the version at {@link PointInTimeType#CURRENT_POINT_IN_TIME}</li>
033 * </ul>
034 * @since 1709
035 */
036public class TagInfoViewer extends HistoryViewerPanel {
037    private static final class RepaintOnFocusChange implements FocusListener {
038        @Override
039        public void focusLost(FocusEvent e) {
040            repaintSelected(e);
041        }
042
043        @Override
044        public void focusGained(FocusEvent e) {
045            repaintSelected(e);
046        }
047
048        private static void repaintSelected(FocusEvent e) {
049            // we would only need the selected rows, but this is easier:
050            e.getComponent().repaint();
051        }
052    }
053
054    /**
055     * Constructs a new {@code TagInfoViewer}.
056     * @param model The history browsing model
057     */
058    public TagInfoViewer(HistoryBrowserModel model) {
059        super(model);
060    }
061
062    @Override
063    protected JTable buildReferenceTable() {
064        return buildTable(PointInTimeType.REFERENCE_POINT_IN_TIME, "table.referencetagtable", model::getReferencePointInTime);
065    }
066
067    @Override
068    protected JTable buildCurrentTable() {
069        return buildTable(PointInTimeType.CURRENT_POINT_IN_TIME, "table.currenttagtable", model::getCurrentPointInTime);
070    }
071
072    private JTable buildTable(PointInTimeType pointInTime, String name, Supplier<HistoryOsmPrimitive> histoSp) {
073        TagTableModel tagTableModel = model.getTagTableModel(pointInTime);
074        JTable table = new JTable(tagTableModel, new TagTableColumnModel());
075        table.setName(name);
076        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
077        selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
078        table.setTransferHandler(new TagInfoTransferHandler());
079        table.addFocusListener(new RepaintOnFocusChange());
080        JPopupMenu tagMenu = new JPopupMenu();
081
082        IntFunction<String> tagKeyFn = x -> (String) table.getValueAt(x, 0);
083        IntFunction<Map<String, Integer>> tagValuesFn = x -> {
084            Map<String, Integer> map = new HashMap<>();
085            String key = tagTableModel.getValue((String) table.getValueAt(x, 0));
086            if (key != null) {
087                map.put(key, 1);
088            }
089            return map;
090        };
091        Supplier<Collection<? extends Tagged>> objectSp = () -> Arrays.asList(histoSp.get());
092
093        tagMenu.add(new CopyValueAction(table, tagKeyFn, objectSp));
094        tagMenu.add(new CopyKeyValueAction(table, tagKeyFn, objectSp));
095        tagMenu.add(new CopyAllKeyValueAction(table, tagKeyFn, objectSp));
096        tagMenu.addSeparator();
097        tagMenu.add(new HelpAction(table, tagKeyFn, tagValuesFn, null, null));
098        tagMenu.add(new TaginfoAction(table, tagKeyFn, tagValuesFn, null, null));
099
100        table.addMouseListener(new PopupMenuLauncher(tagMenu));
101        return table;
102    }
103}