001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.tagging;
003
004import java.awt.BorderLayout;
005import java.awt.Component;
006import java.awt.GridBagConstraints;
007import java.awt.GridBagLayout;
008import java.awt.Insets;
009import java.awt.event.FocusAdapter;
010import java.awt.event.FocusEvent;
011import java.util.EnumSet;
012import javax.swing.AbstractAction;
013
014import javax.swing.BoxLayout;
015import javax.swing.JButton;
016import javax.swing.JPanel;
017import javax.swing.JScrollPane;
018import javax.swing.event.TableModelEvent;
019import javax.swing.event.TableModelListener;
020
021import org.openstreetmap.josm.gui.dialogs.properties.PresetListPanel;
022import org.openstreetmap.josm.gui.layer.OsmDataLayer;
023import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionList;
024import org.openstreetmap.josm.gui.tagging.ac.AutoCompletionManager;
025import org.openstreetmap.josm.tools.CheckParameterUtil;
026
027/**
028 * TagEditorPanel is a {@link JPanel} which can be embedded as UI component in
029 * UIs. It provides a spreadsheet like tabular control for editing tag names
030 * and tag values. Two action buttons are placed on the left, one for adding
031 * a new tag and one for deleting the currently selected tags.
032 *
033 */
034public class TagEditorPanel extends JPanel {
035    /** the tag editor model */
036    private TagEditorModel model;
037    /** the tag table */
038    private TagTable tagTable;
039
040    private PresetListPanel presetListPanel;
041    private final PresetHandler presetHandler;
042
043    /**
044     * builds the panel with the table for editing tags
045     *
046     * @return the panel
047     */
048    protected JPanel buildTagTableEditorPanel() {
049        JPanel pnl = new JPanel();
050        tagTable = new TagTable(model);
051        pnl.setLayout(new BorderLayout());
052        pnl.add(new JScrollPane(tagTable), BorderLayout.CENTER);
053        if (presetHandler != null) {
054            presetListPanel = new PresetListPanel();
055            pnl.add(presetListPanel, BorderLayout.NORTH);
056        }
057        return pnl;
058    }
059
060    public void setNextFocusComponent(Component nextFocusComponent) {
061        tagTable.setNextFocusComponent(nextFocusComponent);
062    }
063
064    /**
065     * builds the panel with the button row
066     *
067     * @return the panel
068     */
069    protected JPanel buildButtonsPanel() {
070        JPanel pnl = new JPanel();
071        pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
072
073        // add action
074        //
075        JButton btn;
076        pnl.add(btn = new JButton(tagTable.getAddAction()));
077        btn.setMargin(new Insets(0,0,0,0));
078        tagTable.addComponentNotStoppingCellEditing(btn);
079
080        // delete action
081        pnl.add(btn = new JButton(tagTable.getDeleteAction()));
082        btn.setMargin(new Insets(0,0,0,0));
083        tagTable.addComponentNotStoppingCellEditing(btn);
084
085        // paste action
086        pnl.add(btn = new JButton(tagTable.getPasteAction()));
087        btn.setMargin(new Insets(0,0,0,0));
088        tagTable.addComponentNotStoppingCellEditing(btn);
089        return pnl;
090    }
091
092    public AbstractAction getPasteAction() {
093        return tagTable.getPasteAction();
094    }
095
096    /**
097     * builds the GUI
098     */
099    protected final void build() {
100        setLayout(new GridBagLayout());
101        JPanel tablePanel = buildTagTableEditorPanel();
102        JPanel buttonPanel = buildButtonsPanel();
103
104        GridBagConstraints gc = new GridBagConstraints();
105
106        // -- buttons panel
107        //
108        gc.fill = GridBagConstraints.VERTICAL;
109        gc.weightx = 0.0;
110        gc.weighty = 1.0;
111        gc.anchor = GridBagConstraints.NORTHWEST;
112        add(buttonPanel,gc);
113
114        // -- the panel with the editor table
115        //
116        gc.gridx = 1;
117        gc.fill = GridBagConstraints.BOTH;
118        gc.weightx = 1.0;
119        gc.weighty = 1.0;
120        gc.anchor = GridBagConstraints.CENTER;
121        add(tablePanel,gc);
122
123        if (presetHandler != null) {
124            model.addTableModelListener(new TableModelListener() {
125                @Override
126                public void tableChanged(TableModelEvent e) {
127                    updatePresets();
128                }
129            });
130        }
131
132        addFocusListener(new FocusAdapter() {
133            @Override public void focusGained(FocusEvent e) {
134                tagTable.requestFocusInCell(0, 0);
135            }
136        });
137    }
138
139    /**
140     * Creates a new tag editor panel. The editor model is created
141     * internally and can be retrieved with {@link #getModel()}.
142     */
143    public TagEditorPanel(PresetHandler presetHandler) {
144        this(null, presetHandler);
145    }
146
147    /**
148     * Creates a new tag editor panel with a supplied model. If
149     * {@code model} is null, a new model is created.
150     *
151     * @param model the tag editor model
152     */
153    public TagEditorPanel(TagEditorModel model, PresetHandler presetHandler) {
154        this.model = model;
155        this.presetHandler = presetHandler;
156        if (this.model == null) {
157            this.model = new TagEditorModel();
158        }
159        build();
160    }
161
162    /**
163     * Replies the tag editor model used by this panel.
164     *
165     * @return the tag editor model used by this panel
166     */
167    public TagEditorModel getModel() {
168        return model;
169    }
170
171    /**
172     * Initializes the auto completion infrastructure used in this
173     * tag editor panel. {@code layer} is the data layer from whose data set
174     * tag values are proposed as auto completion items.
175     *
176     * @param layer the data layer. Must not be null.
177     * @throws IllegalArgumentException thrown if {@code layer} is null
178     */
179    public void initAutoCompletion(OsmDataLayer layer) throws IllegalArgumentException{
180        CheckParameterUtil.ensureParameterNotNull(layer, "layer");
181
182        AutoCompletionManager autocomplete = layer.data.getAutoCompletionManager();
183        AutoCompletionList acList = new AutoCompletionList();
184
185        TagCellEditor editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(0).getCellEditor());
186        editor.setAutoCompletionManager(autocomplete);
187        editor.setAutoCompletionList(acList);
188        editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(1).getCellEditor());
189        editor.setAutoCompletionManager(autocomplete);
190        editor.setAutoCompletionList(acList);
191    }
192
193    @Override
194    public void setEnabled(boolean enabled) {
195        tagTable.setEnabled(enabled);
196        super.setEnabled(enabled);
197    }
198
199    private void updatePresets() {
200        presetListPanel.updatePresets(
201                EnumSet.of(TaggingPresetType.RELATION),
202                model.getTags(), presetHandler);
203        validate();
204    }
205}