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 }