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