source: josm/trunk/src/org/openstreetmap/josm/gui/widgets/QuadStateCheckBox.java@ 8002

Last change on this file since 8002 was 7509, checked in by stoecker, 10 years ago

remove tabs

  • Property svn:eol-style set to native
File size: 8.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.widgets;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.awt.event.ActionListener;
8import java.awt.event.ItemListener;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.awt.event.MouseListener;
12
13import javax.swing.AbstractAction;
14import javax.swing.ActionMap;
15import javax.swing.ButtonGroup;
16import javax.swing.ButtonModel;
17import javax.swing.Icon;
18import javax.swing.JCheckBox;
19import javax.swing.SwingUtilities;
20import javax.swing.event.ChangeListener;
21import javax.swing.plaf.ActionMapUIResource;
22
23import org.openstreetmap.josm.tools.Utils;
24
25/**
26 * A four-state checkbox. The states are enumerated in {@link State}.
27 * @since 591
28 */
29public class QuadStateCheckBox extends JCheckBox {
30
31 /**
32 * The 4 possible states of this checkbox.
33 */
34 public enum State {
35 /** Not selected: the property is explicitly switched off */
36 NOT_SELECTED,
37 /** Selected: the property is explicitly switched on */
38 SELECTED,
39 /** Unset: do not set this property on the selected objects */
40 UNSET,
41 /** Partial: different selected objects have different values, do not change */
42 PARTIAL
43 }
44
45 private final QuadStateDecorator model;
46 private State[] allowed;
47
48 /**
49 * Constructs a new {@code QuadStateCheckBox}.
50 * @param text the text of the check box
51 * @param icon the Icon image to display
52 * @param initial The initial state
53 * @param allowed The allowed states
54 */
55 public QuadStateCheckBox(String text, Icon icon, State initial, State[] allowed) {
56 super(text, icon);
57 this.allowed = Utils.copyArray(allowed);
58 // Add a listener for when the mouse is pressed
59 super.addMouseListener(new MouseAdapter() {
60 @Override public void mousePressed(MouseEvent e) {
61 grabFocus();
62 model.nextState();
63 }
64 });
65 // Reset the keyboard action map
66 ActionMap map = new ActionMapUIResource();
67 map.put("pressed", new AbstractAction() {
68 @Override
69 public void actionPerformed(ActionEvent e) {
70 grabFocus();
71 model.nextState();
72 }
73 });
74 map.put("released", null);
75 SwingUtilities.replaceUIActionMap(this, map);
76 // set the model to the adapted model
77 model = new QuadStateDecorator(getModel());
78 setModel(model);
79 setState(initial);
80 }
81
82 /**
83 * Constructs a new {@code QuadStateCheckBox}.
84 * @param text the text of the check box
85 * @param initial The initial state
86 * @param allowed The allowed states
87 */
88 public QuadStateCheckBox(String text, State initial, State[] allowed) {
89 this(text, null, initial, allowed);
90 }
91
92 /** Do not let anyone add mouse listeners */
93 @Override
94 public void addMouseListener(MouseListener l) { }
95
96 /**
97 * Set the new state.
98 * @param state The new state
99 */
100 public final void setState(State state) {
101 model.setState(state);
102 }
103
104 /**
105 * Return the current state, which is determined by the selection status of the model.
106 * @return The current state
107 */
108 public State getState() {
109 return model.getState();
110 }
111
112 @Override
113 public void setSelected(boolean b) {
114 if (b) {
115 setState(State.SELECTED);
116 } else {
117 setState(State.NOT_SELECTED);
118 }
119 }
120
121 private final class QuadStateDecorator implements ButtonModel {
122 private final ButtonModel other;
123
124 private QuadStateDecorator(ButtonModel other) {
125 this.other = other;
126 }
127
128 private void setState(State state) {
129 if (state == State.NOT_SELECTED) {
130 other.setArmed(false);
131 other.setPressed(false);
132 other.setSelected(false);
133 setToolTipText(tr("false: the property is explicitly switched off"));
134 } else if (state == State.SELECTED) {
135 other.setArmed(false);
136 other.setPressed(false);
137 other.setSelected(true);
138 setToolTipText(tr("true: the property is explicitly switched on"));
139 } else if (state == State.PARTIAL) {
140 other.setArmed(true);
141 other.setPressed(true);
142 other.setSelected(true);
143 setToolTipText(tr("partial: different selected objects have different values, do not change"));
144 } else {
145 other.setArmed(true);
146 other.setPressed(true);
147 other.setSelected(false);
148 setToolTipText(tr("unset: do not set this property on the selected objects"));
149 }
150 }
151
152 /**
153 * The current state is embedded in the selection / armed
154 * state of the model.
155 *
156 * We return the SELECTED state when the checkbox is selected
157 * but not armed, PARTIAL state when the checkbox is
158 * selected and armed (grey) and NOT_SELECTED when the
159 * checkbox is deselected.
160 */
161 private State getState() {
162 if (isSelected() && !isArmed()) {
163 // normal black tick
164 return State.SELECTED;
165 } else if (isSelected() && isArmed()) {
166 // don't care grey tick
167 return State.PARTIAL;
168 } else if (!isSelected() && !isArmed()) {
169 return State.NOT_SELECTED;
170 } else {
171 return State.UNSET;
172 }
173 }
174 /** Rotate to the next allowed state.*/
175 private void nextState() {
176 State current = getState();
177 for (int i = 0; i < allowed.length; i++) {
178 if (allowed[i] == current) {
179 setState((i == allowed.length-1) ? allowed[0] : allowed[i+1]);
180 break;
181 }
182 }
183 }
184 /** Filter: No one may change the armed/selected/pressed status except us. */
185 @Override public void setArmed(boolean b) { }
186 @Override public void setSelected(boolean b) { }
187 @Override public void setPressed(boolean b) { }
188 /** We disable focusing on the component when it is not enabled. */
189 @Override public void setEnabled(boolean b) {
190 setFocusable(b);
191 other.setEnabled(b);
192 }
193 /** All these methods simply delegate to the "other" model
194 * that is being decorated. */
195 @Override public boolean isArmed() { return other.isArmed(); }
196 @Override public boolean isSelected() { return other.isSelected(); }
197 @Override public boolean isEnabled() { return other.isEnabled(); }
198 @Override public boolean isPressed() { return other.isPressed(); }
199 @Override public boolean isRollover() { return other.isRollover(); }
200 @Override public void setRollover(boolean b) { other.setRollover(b); }
201 @Override public void setMnemonic(int key) { other.setMnemonic(key); }
202 @Override public int getMnemonic() { return other.getMnemonic(); }
203 @Override public void setActionCommand(String s) {
204 other.setActionCommand(s);
205 }
206 @Override public String getActionCommand() {
207 return other.getActionCommand();
208 }
209 @Override public void setGroup(ButtonGroup group) {
210 other.setGroup(group);
211 }
212 @Override public void addActionListener(ActionListener l) {
213 other.addActionListener(l);
214 }
215 @Override public void removeActionListener(ActionListener l) {
216 other.removeActionListener(l);
217 }
218 @Override public void addItemListener(ItemListener l) {
219 other.addItemListener(l);
220 }
221 @Override public void removeItemListener(ItemListener l) {
222 other.removeItemListener(l);
223 }
224 @Override public void addChangeListener(ChangeListener l) {
225 other.addChangeListener(l);
226 }
227 @Override public void removeChangeListener(ChangeListener l) {
228 other.removeChangeListener(l);
229 }
230 @Override public Object[] getSelectedObjects() {
231 return other.getSelectedObjects();
232 }
233 }
234}
Note: See TracBrowser for help on using the repository browser.