source: josm/trunk/src/org/openstreetmap/josm/gui/conflict/tags/MultiValueCellEditor.java@ 12620

Last change on this file since 12620 was 12620, checked in by Don-vip, 7 years ago

see #15182 - deprecate all Main logging methods and introduce suitable replacements in Logging for most of them

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.conflict.tags;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Component;
7import java.awt.Font;
8import java.awt.event.FocusAdapter;
9import java.awt.event.FocusEvent;
10import java.awt.event.ItemEvent;
11import java.awt.event.KeyEvent;
12import java.util.concurrent.CopyOnWriteArrayList;
13
14import javax.swing.AbstractCellEditor;
15import javax.swing.DefaultComboBoxModel;
16import javax.swing.JLabel;
17import javax.swing.JList;
18import javax.swing.JTable;
19import javax.swing.ListCellRenderer;
20import javax.swing.UIManager;
21import javax.swing.table.TableCellEditor;
22
23import org.openstreetmap.josm.gui.widgets.JosmComboBox;
24import org.openstreetmap.josm.tools.Logging;
25
26/**
27 * This is a table cell editor for selecting a possible tag value from a list of
28 * proposed tag values. The editor also allows to select all proposed valued or
29 * to remove the tag.
30 *
31 * The editor responds intercepts some keys and interprets them as navigation keys. It
32 * forwards navigation events to {@link NavigationListener}s registred with this editor.
33 * You should register the parent table using this editor as {@link NavigationListener}.
34 *
35 * {@link KeyEvent#VK_ENTER} and {@link KeyEvent#VK_TAB} trigger a {@link NavigationListener#gotoNextDecision()}.
36 */
37public class MultiValueCellEditor extends AbstractCellEditor implements TableCellEditor {
38
39 /**
40 * Defines the interface for an object implementing navigation between rows
41 */
42 public interface NavigationListener {
43 /** Call when need to go to next row */
44 void gotoNextDecision();
45
46 /** Call when need to go to previous row */
47 void gotoPreviousDecision();
48 }
49
50 /** the combo box used as editor */
51 private final JosmComboBox<Object> editor;
52 private final DefaultComboBoxModel<Object> editorModel;
53 private final CopyOnWriteArrayList<NavigationListener> listeners;
54
55 /**
56 * Adds a navigation listener.
57 * @param listener navigation listener to add
58 */
59 public void addNavigationListener(NavigationListener listener) {
60 if (listener != null) {
61 listeners.addIfAbsent(listener);
62 }
63 }
64
65 /**
66 * Removes a navigation listener.
67 * @param listener navigation listener to remove
68 */
69 public void removeNavigationListener(NavigationListener listener) {
70 listeners.remove(listener);
71 }
72
73 protected void fireGotoNextDecision() {
74 for (NavigationListener l: listeners) {
75 l.gotoNextDecision();
76 }
77 }
78
79 protected void fireGotoPreviousDecision() {
80 for (NavigationListener l: listeners) {
81 l.gotoPreviousDecision();
82 }
83 }
84
85 /**
86 * Construct a new {@link MultiValueCellEditor}
87 */
88 public MultiValueCellEditor() {
89 editorModel = new DefaultComboBoxModel<>();
90 editor = new JosmComboBox<Object>(editorModel) {
91 @Override
92 public void processKeyEvent(KeyEvent e) {
93 if (e.getID() == KeyEvent.KEY_PRESSED) {
94 int keyCode = e.getKeyCode();
95 if (keyCode == KeyEvent.VK_ENTER) {
96 fireGotoNextDecision();
97 } else if (keyCode == KeyEvent.VK_TAB) {
98 if (e.isShiftDown()) {
99 fireGotoPreviousDecision();
100 } else {
101 fireGotoNextDecision();
102 }
103 } else if (keyCode == KeyEvent.VK_DELETE || keyCode == KeyEvent.VK_BACK_SPACE) {
104 if (editorModel.getIndexOf(MultiValueDecisionType.KEEP_NONE) > 0) {
105 editorModel.setSelectedItem(MultiValueDecisionType.KEEP_NONE);
106 fireGotoNextDecision();
107 }
108 } else if (keyCode == KeyEvent.VK_ESCAPE) {
109 cancelCellEditing();
110 }
111 }
112 super.processKeyEvent(e);
113 }
114 };
115 editor.addFocusListener(
116 new FocusAdapter() {
117 @Override
118 public void focusGained(FocusEvent e) {
119 editor.showPopup();
120 }
121 }
122 );
123 editor.addItemListener(e -> {
124 if (e.getStateChange() == ItemEvent.SELECTED)
125 fireEditingStopped();
126 });
127 editor.setRenderer(new EditorCellRenderer());
128 listeners = new CopyOnWriteArrayList<>();
129 }
130
131 /**
132 * Populate model with possible values for a decision, and select current choice.
133 * @param decision The {@link MultiValueResolutionDecision} to proceed
134 */
135 protected void initEditor(MultiValueResolutionDecision decision) {
136 editorModel.removeAllElements();
137 if (!decision.isDecided()) {
138 editorModel.addElement(MultiValueDecisionType.UNDECIDED);
139 }
140 for (String value: decision.getValues()) {
141 editorModel.addElement(value);
142 }
143 if (decision.canSumAllNumeric()) {
144 editorModel.addElement(MultiValueDecisionType.SUM_ALL_NUMERIC);
145 }
146 if (decision.canKeepNone()) {
147 editorModel.addElement(MultiValueDecisionType.KEEP_NONE);
148 }
149 if (decision.canKeepAll()) {
150 editorModel.addElement(MultiValueDecisionType.KEEP_ALL);
151 }
152 switch(decision.getDecisionType()) {
153 case UNDECIDED:
154 editor.setSelectedItem(MultiValueDecisionType.UNDECIDED);
155 break;
156 case KEEP_ONE:
157 editor.setSelectedItem(decision.getChosenValue());
158 break;
159 case KEEP_NONE:
160 editor.setSelectedItem(MultiValueDecisionType.KEEP_NONE);
161 break;
162 case KEEP_ALL:
163 editor.setSelectedItem(MultiValueDecisionType.KEEP_ALL);
164 break;
165 case SUM_ALL_NUMERIC:
166 editor.setSelectedItem(MultiValueDecisionType.SUM_ALL_NUMERIC);
167 break;
168 default:
169 Logging.error("Unknown decision type in initEditor(): "+decision.getDecisionType());
170 }
171 }
172
173 @Override
174 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
175 MultiValueResolutionDecision decision = (MultiValueResolutionDecision) value;
176 initEditor(decision);
177 editor.requestFocus();
178 return editor;
179 }
180
181 @Override
182 public Object getCellEditorValue() {
183 return editor.getSelectedItem();
184 }
185
186 /**
187 * The cell renderer used in the edit combo box
188 *
189 */
190 private static class EditorCellRenderer extends JLabel implements ListCellRenderer<Object> {
191
192 /**
193 * Construct a new {@link EditorCellRenderer}.
194 */
195 EditorCellRenderer() {
196 setOpaque(true);
197 }
198
199 /**
200 * Set component color.
201 * @param selected true if is selected
202 */
203 protected void renderColors(boolean selected) {
204 if (selected) {
205 setForeground(UIManager.getColor("ComboBox.selectionForeground"));
206 setBackground(UIManager.getColor("ComboBox.selectionBackground"));
207 } else {
208 setForeground(UIManager.getColor("ComboBox.foreground"));
209 setBackground(UIManager.getColor("ComboBox.background"));
210 }
211 }
212
213 /**
214 * Set text for a value
215 * @param value {@link String} or {@link MultiValueDecisionType}
216 */
217 protected void renderValue(Object value) {
218 setFont(UIManager.getFont("ComboBox.font"));
219 if (String.class.isInstance(value)) {
220 setText(String.class.cast(value));
221 } else if (MultiValueDecisionType.class.isInstance(value)) {
222 switch(MultiValueDecisionType.class.cast(value)) {
223 case UNDECIDED:
224 setText(tr("Choose a value"));
225 setFont(UIManager.getFont("ComboBox.font").deriveFont(Font.ITALIC + Font.BOLD));
226 break;
227 case KEEP_NONE:
228 setText(tr("none"));
229 setFont(UIManager.getFont("ComboBox.font").deriveFont(Font.ITALIC + Font.BOLD));
230 break;
231 case KEEP_ALL:
232 setText(tr("all"));
233 setFont(UIManager.getFont("ComboBox.font").deriveFont(Font.ITALIC + Font.BOLD));
234 break;
235 case SUM_ALL_NUMERIC:
236 setText(tr("sum"));
237 setFont(UIManager.getFont("ComboBox.font").deriveFont(Font.ITALIC + Font.BOLD));
238 break;
239 default:
240 // don't display other values
241 }
242 }
243 }
244
245 @Override
246 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
247 renderColors(isSelected);
248 renderValue(value);
249 return this;
250 }
251 }
252}
Note: See TracBrowser for help on using the repository browser.