1 package com.cosylab.gui;
2
3 import java.awt.Component;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.MouseAdapter;
7 import java.awt.event.MouseEvent;
8 import java.beans.Beans;
9 import java.beans.PropertyVetoException;
10 import java.util.Map;
11
12 import javax.swing.AbstractAction;
13 import javax.swing.JButton;
14 import javax.swing.JDialog;
15
16 import com.cosylab.gui.adapters.Converter;
17 import com.cosylab.gui.components.customizer.AbstractCustomizerPanel;
18 import com.cosylab.gui.components.util.PopupManager;
19 import com.cosylab.gui.displayers.ConvertibleDisplayer;
20 import com.cosylab.gui.displayers.DataConsumer;
21 import com.cosylab.gui.displayers.DataSource;
22 import com.cosylab.gui.displayers.DataSourceSupport;
23 import com.cosylab.gui.displayers.DataState;
24 import com.cosylab.gui.displayers.DisplayerUtilities;
25 import com.cosylab.gui.displayers.DoubleConsumer;
26 import com.cosylab.gui.displayers.DoubleConsumerMulticaster;
27 import com.cosylab.gui.displayers.DoubleDisplayer;
28 import com.cosylab.gui.displayers.NonblockingNumberConsumer;
29 import com.cosylab.util.CommonException;
30
31
32
33
34
35
36
37 public class ButtonController extends JButton implements DoubleDisplayer, DataSource, ConvertibleDisplayer {
38 private static final long serialVersionUID = -1687661677561683031L;
39
40
41 public static final String ACTION_VALUE = "actionValue";
42
43
44 protected static final String DEFAULT_TEXT = "Ok";
45
46 private String title;
47 private DataSource dataSource;
48 private DataState dataState = new DataState(DataState.UNDEFINED);
49 private int suspendCount = 0;
50 private PopupManager popupManager;
51 private InfoDialog infoDialog;
52 private AbstractCustomizerPanel customizer;
53 @SuppressWarnings("unchecked")
54 private DataSourceSupport support = new DataSourceSupport(new Class[]{
55 NonblockingNumberConsumer.class
56 });
57 private Converter converter;
58 private Number actionValue = 0;
59
60 private boolean popupEnabled = false;
61
62 private double minimum;
63
64 private double maximum;
65
66 private String units;
67
68 private double value;
69
70 private String format;
71
72
73
74
75 private class ButtonActionListener implements ActionListener{
76
77 public boolean skipFirst = false;
78
79 public void actionPerformed(ActionEvent e) {
80 if (skipFirst){
81 skipFirst = false;
82 return;
83 }
84
85 DataConsumer[] d = getConsumers();
86
87 for (int i = 0; i < d.length; i++) {
88 NonblockingNumberConsumer dd = (NonblockingNumberConsumer)d[i];
89
90 if (dd != null) {
91 dd.updateNonblocking(actionValue);
92 }
93 }
94
95 }
96
97 }
98 private ButtonActionListener buttonActionListener = new ButtonActionListener();
99
100
101
102
103
104 public ButtonController() {
105 this(DEFAULT_TEXT);
106 }
107
108
109
110
111
112
113 public ButtonController(String text) {
114 setText(text);
115 initialize();
116 }
117
118 protected void initialize(){
119 addActionListener(buttonActionListener);
120
121 addMouseMotionListener(new MouseAdapter() {
122 public void mouseDragged(MouseEvent e) {
123
124 buttonActionListener.skipFirst = true;
125 processMouseEvent(new MouseEvent((Component)e.getSource(), MouseEvent.MOUSE_RELEASED, e.getWhen(),
126 e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), false));
127 }
128 });
129
130 setPopupEnabled(true);
131 }
132
133
134
135
136 public void setActionValue(Number value){
137 if (actionValue == value) return;
138
139 Number old = actionValue;
140 actionValue = value;
141
142 firePropertyChange(ACTION_VALUE,old,actionValue);
143 }
144
145
146
147
148 public Number getActionValue(){
149 return actionValue;
150 }
151
152
153
154
155
156 public String getFormat() {
157 return format;
158 }
159
160
161
162
163
164 public double getMaximum() {
165 return maximum;
166 }
167
168
169
170
171
172 public double getMinimum() {
173 return minimum;
174 }
175
176
177
178
179
180 public String getUnits() {
181 return units;
182 }
183
184
185
186
187
188 public double getValue() {
189 return value;
190 }
191
192
193
194
195
196 public void setFormat(String value) {
197 if (format == null) {
198 if (value == null) return;
199 } else if (format.equals(value)) return;
200
201 String oldValue = format;
202 format = value;
203
204 firePropertyChange("format", oldValue, format);
205 }
206
207
208
209
210
211 public void setMaximum(double value) {
212 if (value == maximum) return;
213
214 double oldValue = maximum;
215 maximum = value;
216
217 firePropertyChange("maximum", oldValue, maximum);
218 }
219
220
221
222
223
224 public void setMinimum(double value) {
225 if (value == minimum) return;
226
227 double oldValue = minimum;
228 minimum = value;
229
230 firePropertyChange("minimum", oldValue, minimum);
231 }
232
233
234
235
236
237 public void setUnits(String value) {
238 if (units == null) {
239 if (value == null) return;
240 } else if (units.equals(value)) return;
241
242 String oldValue = units;
243 units = value;
244
245 firePropertyChange("units", oldValue, units);
246 }
247
248
249
250
251
252 public void setValue(double val) {
253 if (val == value) return;
254
255 double oldValue = value;
256 value = val;
257
258 firePropertyChange("value", oldValue, value);
259 }
260
261
262
263
264
265 public DataSource getDataSource() {
266 return dataSource;
267 }
268
269
270
271
272
273 public String getTitle() {
274 return title;
275 }
276
277
278
279
280
281 public boolean isEditable() {
282 return true;
283 }
284
285
286
287
288
289 public void setDataSource(DataSource dataSource)
290 throws PropertyVetoException {
291 DisplayerUtilities.prepareNewDataSource(dataSource,this);
292
293 DataSource old= this.dataSource;
294 this.dataSource = dataSource;
295
296 firePropertyChange(DATA_SOURCE,old,dataSource);
297 }
298
299 protected void internalSetTitle()
300 {
301 String value = title;
302
303 if (value == null && Beans.isDesignTime()) {
304 value = "<title>";
305 }
306 }
307
308
309
310
311
312 public void setTitle(String value) {
313 String oldVal = title;
314 title = value;
315 internalSetTitle();
316 firePropertyChange("title", oldVal, value);
317 }
318
319
320
321
322
323 @SuppressWarnings("unchecked")
324 public DataConsumer getDataConsumer(Class type) {
325 if (type == DoubleConsumer.class) {
326 return this;
327 }
328
329 return DoubleConsumerMulticaster.createDataConsumer(type, this);
330 }
331
332
333
334
335
336 public DataConsumer getDefaultDataConsumer() {
337 return this;
338 }
339
340
341
342
343
344 public String[] getSupportedCharacteristics() {
345 return DisplayerUtilities.COMMON_NUMERIC_DISPLAYER_CHARACTERISTICS;
346 }
347
348
349
350
351
352 @SuppressWarnings("unchecked")
353 public Class<DataConsumer>[] getSupportedConsumerTypes() {
354 return DoubleConsumerMulticaster.PREFERED_CONSUMER_TYPES;
355 }
356
357
358
359
360
361 @SuppressWarnings("unchecked")
362 public void setCharacteristics(Map characteristics) {
363 if (characteristics == null) {
364 throw new NullPointerException("characteristics");
365 }
366
367 DisplayerUtilities.setCharacteristics(characteristics, this);
368 }
369
370
371
372
373
374 public void updateDataState(DataState state) {
375 DataState old = dataState;
376 dataState = state;
377 firePropertyChange(DATA_STATE, old, dataState);
378 }
379
380 private void internalCleanup() {
381 setText(DEFAULT_TEXT);
382 setTitle(null);
383 }
384
385
386
387
388
389 public void cleanup() {
390 internalCleanup();
391 updateDataState(new DataState(DataState.NOT_INITIALIZED));
392 }
393
394
395
396
397
398 public boolean isSuspended() {
399 return suspendCount > 0;
400 }
401
402
403
404
405
406 public void resume() {
407 if (suspendCount > 0) {
408 suspendCount--;
409 }
410
411 if (suspendCount == 0) {
412 setEnabled(true);
413 }
414 }
415
416
417
418
419
420 public void suspend() {
421 setEnabled(false);
422 suspendCount++;
423 }
424
425
426
427
428
429 public PopupManager getPopupManager() {
430 if (popupManager == null) {
431 popupManager = new PopupManager(this, false);
432 popupManager.addAction(new AbstractAction("Preferences...") {
433 private static final long serialVersionUID = 1L;
434 public void actionPerformed(ActionEvent e)
435 {
436 getCustomizer().showDialog();
437 }
438 });
439
440 popupManager.addAction(new AbstractAction("Info...") {
441 private static final long serialVersionUID = 1L;
442
443 public void actionPerformed(ActionEvent e)
444 {
445 getInfoDialog().setVisible(true);
446 }
447 });
448 }
449
450 return popupManager;
451 }
452
453
454
455
456
457
458 public boolean isPopupEnabled() {
459 return popupEnabled;
460 }
461
462
463
464
465
466
467 public void setPopupEnabled(boolean enabled) {
468 if (popupEnabled == enabled) return;
469 popupEnabled = enabled;
470 if (enabled) {
471 addMouseListener(getPopupManager().getMouseHook());
472 } else {
473 removeMouseListener(getPopupManager().getMouseHook());
474 }
475 firePropertyChange("popupEnabled",!popupEnabled,popupEnabled);
476 }
477
478 protected JDialog getInfoDialog() {
479 if (infoDialog == null) {
480 infoDialog = new InfoDialog(this);
481 }
482 return infoDialog;
483 }
484
485 protected AbstractCustomizerPanel getCustomizer() {
486 if (customizer == null) {
487 customizer = AbstractCustomizerPanel.findCustomizer(this);
488 }
489 return customizer;
490 }
491
492
493
494
495
496 public DataState getDataState() {
497 return dataState;
498 }
499
500
501
502
503
504 public void updateValue(long timestamp, double value)
505 throws CommonException {
506 }
507
508
509
510
511
512
513
514
515 public void addConsumer(DataConsumer consumer) throws PropertyVetoException {
516 if (consumer == null) {
517 throw new NullPointerException("consumer");
518 }
519
520 NonblockingNumberConsumer c = (NonblockingNumberConsumer)consumer
521 .getDataConsumer(NonblockingNumberConsumer.class);
522
523 if (c == null) {
524 throw new PropertyVetoException("Consumer '" + consumer
525 + "' must support NonblockingNumberConsumer.", null);
526 }
527
528 support.addConsumer(c);
529 }
530
531
532
533
534
535 public Class<DataConsumer>[] getAcceptableConsumerTypes() {
536 return support.getAcceptableConsumerTypes();
537 }
538
539
540
541
542
543 public DataConsumer[] getConsumers() {
544 return support.getConsumers();
545 }
546
547
548
549
550
551 public void removeAllConsumers() {
552 support.removeAllConsumers();
553 }
554
555
556
557
558
559 public void removeConsumer(DataConsumer consumer) {
560 support.removeConsumer(consumer);
561 }
562
563
564
565
566
567 public Converter getConverter() {
568 return converter;
569 }
570
571
572
573
574
575 public void setConverter(Converter converter) throws PropertyVetoException {
576 if (this.converter != null && this.converter.equals(converter) ||
577 (this.converter == null && converter == null)) return;
578 DisplayerUtilities.prepareNewConverter(converter,this);
579
580 Converter old= this.converter;
581 this.converter = converter;
582
583 firePropertyChange(CONVERTER_PROPERTY,old,this.converter);
584 }
585
586 }