001    // License: GPL. For details, see LICENSE file.
002    package org.openstreetmap.josm.gui.dialogs.properties;
003    
004    import java.awt.Cursor;
005    import java.awt.Dimension;
006    import java.awt.Font;
007    import java.awt.GridBagLayout;
008    import java.awt.event.MouseEvent;
009    import java.awt.event.MouseListener;
010    import java.awt.font.TextAttribute;
011    import java.util.Collection;
012    import java.util.Collections;
013    import java.util.List;
014    import java.util.Map;
015    
016    import javax.swing.Action;
017    import javax.swing.Icon;
018    import javax.swing.JLabel;
019    import javax.swing.JPanel;
020    
021    import org.openstreetmap.josm.data.osm.OsmPrimitive;
022    import org.openstreetmap.josm.data.osm.Tag;
023    import org.openstreetmap.josm.gui.preferences.map.TaggingPresetPreference;
024    import org.openstreetmap.josm.gui.tagging.TaggingPreset;
025    import org.openstreetmap.josm.gui.tagging.TaggingPreset.PresetType;
026    import org.openstreetmap.josm.tools.GBC;
027    
028    public class PresetListPanel extends JPanel {
029    
030        public PresetListPanel() {
031            super(new GridBagLayout());
032        }
033    
034        public interface PresetHandler {
035            Collection<OsmPrimitive> getSelection();
036            void updateTags(List<Tag> tags);
037        }
038    
039        /**
040         * Small helper class that manages the highlighting of the label on hover as well as opening
041         * the corresponding preset when clicked
042         */
043        private static class PresetLabelML implements MouseListener {
044            final JLabel label;
045            final Font hover;
046            final Font normal;
047            final TaggingPreset tag;
048            final PresetHandler presetHandler;
049    
050            PresetLabelML(JLabel lbl, TaggingPreset t, PresetHandler presetHandler) {
051                super();
052                label = lbl;
053                lbl.setCursor(new Cursor(Cursor.HAND_CURSOR));
054                normal = label.getFont();
055                hover = normal.deriveFont(Collections.singletonMap(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_DOTTED));
056                tag = t;
057                this.presetHandler = presetHandler;
058            }
059            public void mouseClicked(MouseEvent arg0) {
060                Collection<OsmPrimitive> selection = tag.createSelection(presetHandler.getSelection());
061                if (selection == null || selection.isEmpty())
062                    return;
063                int answer = tag.showDialog(selection, false);
064    
065                if (answer == TaggingPreset.DIALOG_ANSWER_APPLY) {
066                    presetHandler.updateTags(tag.getChangedTags());
067                }
068    
069            }
070            public void mouseEntered(MouseEvent arg0) {
071                label.setFont(hover);
072            }
073            public void mouseExited(MouseEvent arg0) {
074                label.setFont(normal);
075            }
076            public void mousePressed(MouseEvent arg0) {}
077            public void mouseReleased(MouseEvent arg0) {}
078        }
079    
080        public void updatePresets(final Collection<PresetType> types, final Map<String, String> tags, PresetHandler presetHandler) {
081    
082            removeAll();
083            if (types.isEmpty()) {
084                setVisible(false);
085                return;
086            }
087    
088            for (TaggingPreset t : TaggingPresetPreference.taggingPresets) {
089                if (!t.matches(types, tags, true)) {
090                    continue;
091                }
092    
093                JLabel lbl = new JLabel(t.getName() + " ???");
094                lbl.setIcon((Icon) t.getValue(Action.SMALL_ICON));
095                lbl.addMouseListener(new PresetLabelML(lbl, t, presetHandler));
096                add(lbl, GBC.eol().fill(GBC.HORIZONTAL));
097            }
098    
099            if (getComponentCount() > 0) {
100                setVisible(true);
101                // This ensures the presets are exactly as high as needed.
102                int height = getComponentCount() * getComponent(0).getHeight();
103                Dimension size = new Dimension(getWidth(), height);
104                setMaximumSize(size);
105                setMinimumSize(size);
106            } else {
107                setVisible(false);
108            }
109        }
110    }