001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv.control;
030    
031    import java.awt.Color;
032    import java.awt.Container;
033    import java.awt.FlowLayout;
034    import java.awt.event.ActionEvent;
035    import java.awt.event.ActionListener;
036    import java.rmi.RemoteException;
037    import java.util.ArrayList;
038    import java.util.HashMap;
039    import java.util.Hashtable;
040    import java.util.List;
041    import java.util.Map;
042    
043    import javax.swing.JButton;
044    import javax.swing.JComboBox;
045    import javax.swing.JComponent;
046    import javax.swing.JLabel;
047    import javax.swing.JPanel;
048    import javax.swing.JTabbedPane;
049    import javax.swing.JTextField;
050    import javax.swing.border.LineBorder;
051    
052    import org.python.core.PyObject;
053    
054    import visad.ConstantMap;
055    import visad.Data;
056    import visad.VisADException;
057    import visad.georef.MapProjection;
058    
059    import ucar.unidata.data.DataChoice;
060    import ucar.unidata.data.DataSource;
061    import ucar.unidata.data.DirectDataChoice;
062    import ucar.unidata.idv.MapViewManager;
063    import ucar.unidata.util.GuiUtils;
064    import ucar.unidata.util.LogUtil;
065    import ucar.unidata.view.geoloc.MapProjectionDisplay;
066    
067    import edu.wisc.ssec.mcidasv.Constants;
068    import edu.wisc.ssec.mcidasv.McIDASV;
069    import edu.wisc.ssec.mcidasv.control.LinearCombo.Combination;
070    import edu.wisc.ssec.mcidasv.control.LinearCombo.Selector;
071    import edu.wisc.ssec.mcidasv.data.hydra.MultiDimensionSubset;
072    import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralData;
073    import edu.wisc.ssec.mcidasv.data.hydra.MultiSpectralDataSource;
074    import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
075    import edu.wisc.ssec.mcidasv.jython.Console;
076    import edu.wisc.ssec.mcidasv.jython.ConsoleCallback;
077    
078    public class HydraCombo extends HydraControl {
079    
080    
081        private MultiSpectralDisplay display;
082    
083        private DataChoice dataChoice = null;
084    
085        private CombinationPanel comboPanel;
086    
087        private final Hashtable<String, Object> persistable = new Hashtable<String, Object>();
088        
089        private MultiSpectralDataSource source;
090     
091        float init_wavenumber;
092    
093        private Map<String, Selector> selectorMap = new HashMap<String, Selector>();
094    
095        private static final String defaultButtonLabel = "Compute New Field";
096        private JButton computeButton = new JButton(defaultButtonLabel);
097    
098        public HydraCombo() {
099            super();
100            setHelpUrl("idv.controls.hydra.channelcombinationcontrol");
101        }
102    
103        @Override public boolean init(final DataChoice choice)
104            throws VisADException, RemoteException {
105            ((McIDASV)getIdv()).getMcvDataManager().setHydraControl(choice, this);
106            dataChoice = choice;
107            List<DataSource> sources = new ArrayList<DataSource>();
108            choice.getDataSources(sources);
109            source = ((MultiSpectralDataSource)sources.get(0));
110    
111            Float fieldSelectorChannel = (Float)getDataSelection().getProperty(Constants.PROP_CHAN);
112            if (fieldSelectorChannel == null)
113                fieldSelectorChannel = 0f;
114            init_wavenumber = fieldSelectorChannel;
115    
116            display = new MultiSpectralDisplay((DirectDataChoice)choice);
117            display.setWaveNumber(fieldSelectorChannel);
118            display.setDisplayControl(this);
119    
120            ((McIDASV)getIdv()).getMcvDataManager().setHydraDisplay(choice, display);
121    
122            comboPanel = new CombinationPanel(this);
123            if (!persistable.isEmpty()) {
124                comboPanel.unpersistData(persistable);
125                persistable.clear();
126            }
127            return true;
128        }
129    
130        @Override public void initDone() {
131            MapViewManager viewManager = (MapViewManager) getViewManager();
132            MapProjectionDisplay dispMaster =
133                (MapProjectionDisplay) viewManager.getMaster();
134            try {
135              dispMaster.setMapProjection(getDataProjection());
136            } catch (Exception e) {
137              logException("problem setting MapProjection", e);
138            }
139    
140            getIdv().getIdvUIManager().showDashboard();
141        }
142    
143        public Hashtable<String, Object> getPersistable() {
144            return comboPanel.persistData();
145        }
146        
147        public void setPersistable(final Hashtable<String, Object> table) {
148            persistable.clear();
149            persistable.putAll(table);
150        }
151        
152        @Override public MapProjection getDataProjection() {
153            MapProjection mp = null;
154            HashMap subset = null;
155            Hashtable table = dataChoice.getProperties();
156            MultiDimensionSubset dataSel =
157               (MultiDimensionSubset) table.get(MultiDimensionSubset.key);
158            if (dataSel != null) {
159              subset = dataSel.getSubset();
160            }
161            mp = source.getDataProjection(subset);
162            return mp;
163        }
164    
165        @Override public Container doMakeContents() {
166            JTabbedPane pane = new JTabbedPane();
167            pane.add("Channel Combination Tool", GuiUtils.inset(getComboTab(), 5));
168            GuiUtils.handleHeavyWeightComponentsInTabs(pane);
169            return pane;
170        }
171    
172        public void updateComboPanel(final String id, final float value) {
173            if (comboPanel == null)
174                return;
175            comboPanel.updateSelector(id, value);
176        }
177    
178        protected void enableSelectorForWrapper(final SelectorWrapper wrapper) {
179            if (comboPanel == null)
180                return;
181            comboPanel.enableSelector(wrapper, false);
182        }
183    
184        protected void disableSelectorForWrapper(final SelectorWrapper wrapper) {
185            if (comboPanel == null)
186                return;
187            comboPanel.disableSelector(wrapper, false);
188        }
189        
190        protected MultiSpectralDisplay getMultiSpectralDisplay() {
191            return display;
192        }
193    
194        protected JButton getComputeButton() {
195            return computeButton;
196        }
197    
198        private JComponent getComboTab() {
199            computeButton.addActionListener(new ActionListener() {
200                public void actionPerformed(final ActionEvent e) {
201                    comboPanel.queueCombination();
202                    computeButton.setEnabled(false);
203                    showWaitCursor();
204                }
205            });
206            // wrap compute button in JPanel to retain preferred size
207            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
208            buttonPanel.add(computeButton);
209            JPanel tmp = GuiUtils.topCenterBottom(display.getDisplayComponent(), comboPanel.getPanel(), buttonPanel);
210            return tmp;
211        }
212    
213        public void addCombination(final String name, final Data combination) {
214            if (combination != null)
215                source.addChoice(name, combination);
216        }
217        
218        public void addCombination(final Combination combination) {
219            if (combination != null)
220                source.addChoice(combination.getName(), combination.getData());
221        }
222    
223        protected void addSelector(final Selector selector) throws Exception {
224            ConstantMap[] mapping = selector.getColor();
225            float r = new Double(mapping[0].getConstant()).floatValue();
226            float g = new Double(mapping[1].getConstant()).floatValue();
227            float b = new Double(mapping[2].getConstant()).floatValue();
228            Color javaColor = new Color(r, g, b);
229            display.createSelector(selector.getId(), javaColor);
230            display.setSelectorValue(selector.getId(), selector.getWaveNumber());
231            selectorMap.put(selector.getId(), selector);
232        }
233    
234        public void moveSelector(final String id, final float wavenum) {
235            if (!selectorMap.containsKey(id))
236                return;
237            display.updateControlSelector(id, wavenum);
238        }
239    
240        public void updateSelector(final String id, final float wavenum) {
241            if (!selectorMap.containsKey(id))
242                return;
243    
244            selectorMap.get(id).setWaveNumber(wavenum);
245        }
246    
247        
248    
249        public enum DataType { HYPERSPECTRAL, MULTISPECTRAL };
250    
251        public enum WrapperState { ENABLED, DISABLED };
252    
253        public static class CombinationPanel implements ConsoleCallback {
254            private final SelectorWrapper a;
255            private final SelectorWrapper b;
256            private final SelectorWrapper c;
257            private final SelectorWrapper d;
258    
259            private final OperationXY ab;
260            private final OperationXY cd;
261    
262            private final CombineOperations abcd;
263    
264            private final MultiSpectralDisplay display;
265    
266            private final HydraCombo control;
267    
268            private final Console console;
269    
270            private final Map<String, Selector> selectorMap = new HashMap<String, Selector>();
271            private final Map<String, SelectorWrapper> wrapperMap = new HashMap<String, SelectorWrapper>();
272    
273            private final DataType dataType;
274    
275            public CombinationPanel(final HydraCombo control) {
276                this.control = control;
277                display = control.getMultiSpectralDisplay();
278                if (display == null)
279                    throw new NullPointerException("Display hasn't been initialized");
280    
281                MultiSpectralData data = display.getMultiSpectralData();
282                if (data.hasBandNames())
283                    dataType = DataType.MULTISPECTRAL;
284                else
285                    dataType = DataType.HYPERSPECTRAL;
286    
287                this.console = new Console();
288                console.setCallbackHandler(this);
289    
290                a = makeWrapper("a", Color.RED);
291                b = makeWrapper("b", Color.GREEN);
292                c = makeWrapper("c", Color.BLUE);
293                d = makeWrapper("d", Color.MAGENTA);
294    
295                enableSelector(a, true);
296    
297                ab = new OperationXY(this, a, b);
298                cd = new OperationXY(this, c, d);
299    
300                abcd = new CombineOperations(this, ab, cd);
301            }
302    
303    //        public Console getConsole() {
304    //            return console;
305    //        }
306    
307            public void ranBlock(final String line) {
308                PyObject jythonObj = console.getJythonObject("combo");
309    //            if (jythonObj instanceof PyJavaInstance) {
310                    Object combination = jythonObj.__tojava__(Object.class);
311                    if (combination instanceof Combination) {
312                        control.addCombination((Combination)combination);
313                        control.getComputeButton().setEnabled(true);
314                        control.showNormalCursor();
315                    }
316    //            }
317            }
318    
319            public void updateSelector(final String id, final float channel) {
320                if (!selectorMap.containsKey(id))
321                    return;
322    
323                Selector selector = selectorMap.get(id);
324                selector.setWaveNumber(channel);
325                wrapperMap.get(id).update();
326            }
327    
328            protected void addSelector(final Selector selector, final boolean enabled) throws Exception {
329                String id = selector.getId();
330                if (enabled) {
331                    display.createSelector(id, selector.getColor());
332                    display.setSelectorValue(id, selector.getWaveNumber());
333                }
334                selectorMap.put(id, selector);
335            }
336    
337            protected void disableSelector(final SelectorWrapper wrapper, final boolean disableWrapper) {
338                if (disableWrapper)
339                    wrapper.disable();
340    
341                try {
342                    display.removeSelector(wrapper.getSelector().getId());
343                } catch (Exception e) {
344                    LogUtil.logException("HydraCombo.disableSelector", e);
345                }
346            }
347    
348            protected void enableSelector(final SelectorWrapper wrapper, final boolean enableWrapper) {
349                if (enableWrapper)
350                    wrapper.enable();
351    
352                try {
353                    Selector selector = wrapper.getSelector();
354                    String id = selector.getId();
355                    display.createSelector(id, selector.getColor());
356                    display.setSelectorValue(id, selector.getWaveNumber());
357                } catch (Exception e) {
358                    LogUtil.logException("HydraCombo.disableSelector", e);
359                }
360            }
361    
362            private SelectorWrapper makeWrapper(final String var, final Color color) {
363                try {
364                    ConstantMap[] mappedColor = MultiSpectralDisplay.makeColorMap(color);
365                    
366                    SelectorWrapper tmp;
367                    if (dataType == DataType.HYPERSPECTRAL)
368                        tmp = new HyperspectralSelectorWrapper(var, mappedColor, control, console);
369                    else
370                        tmp = new MultispectralSelectorWrapper(var, mappedColor, control, console);
371                    addSelector(tmp.getSelector(), false);
372                    wrapperMap.put(tmp.getSelector().getId(), tmp);
373    //                console.injectObject(var, new PyJavaInstance(tmp.getSelector()));
374                    console.injectObject(var, tmp.getSelector());
375                    return tmp;
376                } catch (Exception e) { 
377                    LogUtil.logException("HydraCombo.makeWrapper", e);
378                }
379                return null;
380            }
381    
382            public JPanel getPanel() {
383                JPanel panel = new JPanel(new FlowLayout());
384                panel.add(new JLabel("("));
385                panel.add(a.getPanel());
386                panel.add(ab.getBox());
387                panel.add(b.getPanel());
388                panel.add(new JLabel(")"));
389                panel.add(abcd.getBox());
390                panel.add(new JLabel("("));
391                panel.add(c.getPanel());
392                panel.add(cd.getBox());
393                panel.add(d.getPanel());
394                panel.add(new JLabel(")"));
395                return panel;
396            }
397    
398            public void queueCombination() {
399                String jy = "combo="+abcd.getJython();
400                System.err.println("jython=" + jy);
401                console.queueLine(jy);
402            }
403    
404            public Hashtable<String, Object> persistData() {
405                Hashtable<String, Object> table = new Hashtable<String, Object>();
406                
407                table.put("a", a.persistSelectorWrapper());
408                table.put("b", b.persistSelectorWrapper());
409                table.put("c", c.persistSelectorWrapper());
410                table.put("d", d.persistSelectorWrapper());
411                table.put("ab", ab.getOperation());
412                table.put("cd", cd.getOperation());
413                table.put("abcd", abcd.getOperation());
414                return table;
415            }
416    
417            public void unpersistData(final Hashtable<String, Object> table) {
418                Hashtable<String, String> tableA = (Hashtable<String, String>)table.get("a");
419                Hashtable<String, String> tableB = (Hashtable<String, String>)table.get("b");
420                Hashtable<String, String> tableC = (Hashtable<String, String>)table.get("c");
421                Hashtable<String, String> tableD = (Hashtable<String, String>)table.get("d");
422    
423                a.unpersistSelectorWrapper(tableA);
424                b.unpersistSelectorWrapper(tableB);
425                c.unpersistSelectorWrapper(tableC);
426                d.unpersistSelectorWrapper(tableD);
427    
428                String opAb = (String)table.get("ab");
429                String opCd = (String)table.get("cd");
430                String opAbcd = (String)table.get("abcd");
431    
432                ab.setOperation(opAb);
433                cd.setOperation(opCd);
434                abcd.setOperation(opAbcd);
435            }
436        }
437    
438        private static class OperationXY {
439            private static final String[] OPERATIONS = { "+", "-", "/", "*", " " };
440            private static final String INVALID_OP = " ";
441            private final JComboBox combo = new JComboBox(OPERATIONS);
442    
443            private CombinationPanel comboPanel;
444            private SelectorWrapper x;
445            private SelectorWrapper y;
446    
447            public OperationXY(final CombinationPanel comboPanel, final SelectorWrapper x, final SelectorWrapper y) {
448                this.x = x;
449                this.y = y;
450                this.comboPanel = comboPanel;
451                combo.setSelectedItem(" ");
452                combo.addActionListener(new ActionListener() {
453                    public void actionPerformed(final ActionEvent e) {
454                        if (getOperation().equals(" ")) {
455                            comboPanel.disableSelector(y, true);
456                        } else {
457                            comboPanel.enableSelector(y, true);
458                        }
459                    }
460                });
461            }
462    
463            public void disable() {
464                comboPanel.disableSelector(x, true);
465                combo.setSelectedItem(INVALID_OP);
466                comboPanel.disableSelector(y, true);
467            }
468    
469            public void enable() {
470                comboPanel.enableSelector(x, true);
471            }
472    
473            public String getOperation() {
474                return (String)combo.getSelectedItem();
475            }
476    
477            public void setOperation(final String operation) {
478                combo.setSelectedItem(operation);
479            }
480    
481            public JComboBox getBox() {
482                return combo;
483            }
484    
485            public String getJython() {
486                String operation = getOperation();
487                if (operation.equals(INVALID_OP))
488                    operation = "";
489    
490                String jython = x.getJython() + operation + y.getJython();
491                if (x.isValid() && y.isValid())
492                    return "(" + jython + ")";
493                return jython;
494            }
495        }
496    
497        private static class CombineOperations {
498            private static final String[] OPERATIONS = { "+", "-", "/", "*", " "};
499            private static final String INVALID_OP = " ";
500            private final JComboBox combo = new JComboBox(OPERATIONS);
501    
502            private OperationXY x;
503            private OperationXY y;
504    
505            public CombineOperations(final CombinationPanel comboPanel, final OperationXY x, final OperationXY y) {
506                this.x = x;
507                this.y = y;
508                combo.setSelectedItem(INVALID_OP);
509                combo.addActionListener(new ActionListener() {
510                    public void actionPerformed(final ActionEvent e) {
511                        if (getOperation().equals(" ")) {
512                            y.disable();
513                        } else {
514                            y.enable();
515                        }
516                    }
517                });
518            }
519    
520            public String getOperation() {
521                return (String)combo.getSelectedItem();
522            }
523    
524            public void setOperation(final String operation) {
525                combo.setSelectedItem(operation);
526            }
527    
528            public JComboBox getBox() {
529                return combo;
530            }
531    
532            public String getJython() {
533                String operation = getOperation();
534                if (operation.equals(INVALID_OP))
535                    operation = "";
536    
537                String jython = x.getJython() + operation + y.getJython();
538                return jython;
539            }
540        }
541    
542        private static abstract class SelectorWrapper {
543            protected static final String BLANK = "-----";
544            private String variable;
545            private final ConstantMap[] color;
546            protected final Selector selector;
547            protected final MultiSpectralDisplay display;
548            protected final MultiSpectralData data;
549            private final JTextField scale = new JTextField(String.format("%3.1f", 1.0));
550            protected WrapperState currentState = WrapperState.DISABLED;
551    
552            public SelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
553                this.display = control.getMultiSpectralDisplay();
554                this.data = control.getMultiSpectralDisplay().getMultiSpectralData();
555                this.variable = variable;
556                this.color = color;
557                this.selector = new Selector(control.init_wavenumber, color, control, console);
558                this.selector.addName(variable);
559            }
560    
561            public Selector getSelector() {
562                return selector;
563            }
564    
565            public JPanel getPanel() {
566                JPanel panel = new JPanel(new FlowLayout());
567                JComponent comp = getWavenumberComponent();
568                float r = new Double(color[0].getConstant()).floatValue();
569                float g = new Double(color[1].getConstant()).floatValue();
570                float b = new Double(color[2].getConstant()).floatValue();
571                comp.setBorder(new LineBorder(new Color(r, g, b), 2));
572                panel.add(scale);
573                panel.add(comp);
574                return panel;
575            }
576    
577            public String getJython() {
578                if (!isValid())
579                    return "";
580                return "(" + scale.getText() + "*" + variable + ")";
581            }
582    
583            public boolean isValid() {
584                return !getValue().equals(BLANK);
585            }
586    
587            public void enable() {
588                setValue(Float.toString(selector.getWaveNumber()));
589                currentState = WrapperState.ENABLED;
590            }
591    
592            public void disable() {
593                setValue(BLANK);
594                currentState = WrapperState.DISABLED;
595            }
596    
597            public void update() {
598                setValue(Float.toString(selector.getWaveNumber()));
599            }
600    
601            public Hashtable<String, String> persistSelectorWrapper() {
602                Hashtable<String, String> table = new Hashtable<String, String>(3);
603                String scaleText = scale.getText();
604                String waveText = getValue();
605    
606                if (scaleText == null || scaleText.length() == 0)
607                    scaleText = "1.0";
608                if (waveText == null || waveText.length() == 0 || !isValid())
609                    waveText = BLANK;
610    
611                table.put("variable", variable);
612                table.put("scale", scale.getText());
613                table.put("wave", getValue());
614                return table;
615            }
616    
617            public void unpersistSelectorWrapper(final Hashtable<String, String> table) {
618                variable = table.get("variable");
619                selector.addName(variable);
620                scale.setText(String.format("%3.1f", new Float(table.get("scale"))));
621    
622                String waveText = table.get("wave");
623                if (waveText.equals(BLANK)) {
624                    disable();
625                } else {
626                    float wave = new Float(table.get("wave"));
627                    selector.setWaveNumber(wave);
628                    if (isValid())
629                        update();
630                }
631            }
632    
633            public abstract JComponent getWavenumberComponent();
634    
635            public abstract void setValue(final String value);
636    
637            public abstract String getValue();
638        }
639    
640        private static class HyperspectralSelectorWrapper extends SelectorWrapper {
641            private final JTextField wavenumber;
642            public HyperspectralSelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
643                super(variable, color, control, console);
644                wavenumber = new JTextField(BLANK, 7);
645    
646                wavenumber.addActionListener(new ActionListener() {
647                    public void actionPerformed(final ActionEvent e) {
648                        String textVal = wavenumber.getText();
649                        if (textVal.equals(BLANK))
650                            return;
651    
652                        float wave = Float.parseFloat(textVal.trim());
653                        control.updateComboPanel(getSelector().getId(), wave);
654                    }
655                });
656            }
657    
658            @Override public JComponent getWavenumberComponent() {
659                return wavenumber;
660            }
661    
662            @Override public void setValue(final String value) {
663                if (value == null)
664                    throw new NullPointerException("");
665    
666                if (!value.equals(BLANK)) {
667                    float wave = Float.parseFloat(value);
668                    String fmt = String.format("%7.2f", wave);
669                    wavenumber.setText(fmt);
670                }
671            }
672    
673            public String getValue() {
674                return wavenumber.getText();
675            }
676        }
677    
678        private static class MultispectralSelectorWrapper extends SelectorWrapper {
679    
680            private final JComboBox bands;
681    
682            public MultispectralSelectorWrapper(final String variable, final ConstantMap[] color, final HydraCombo control, final Console console) {
683                super(variable, color, control, console);
684                removeMSDListeners();
685                bands = bigBadBox(control);
686            }
687    
688            private void removeMSDListeners() {
689                JComboBox box = display.getBandSelectComboBox();
690                for (ActionListener l : box.getActionListeners())
691                    box.removeActionListener(l);
692            }
693    
694            private JComboBox bigBadBox(final HydraCombo control) {
695                final JComboBox box = new JComboBox();
696                box.addItem(BLANK);
697    
698                for (String name : data.getBandNames())
699                    box.addItem(name);
700    
701                final SelectorWrapper wrapper = this;
702                box.addActionListener(new ActionListener() {
703                    public void actionPerformed(final ActionEvent e) {
704                        String selected = (String)box.getSelectedItem();
705                        float wave = Float.NaN;
706    
707                        if (!selected.equals(BLANK)) {
708                            Map<String, Float> map = data.getBandNameMap();
709                            if (map.containsKey(selected))
710                                wave = map.get(selected);
711    
712                            if (currentState == WrapperState.DISABLED)
713                                control.enableSelectorForWrapper(wrapper);
714                            control.updateComboPanel(getSelector().getId(), wave);
715                        } else {
716                            control.disableSelectorForWrapper(wrapper);
717                        }
718                    }
719                });
720                
721                return box;
722            }
723            
724            @Override public JComponent getWavenumberComponent() {
725                return bands;
726            }
727    
728            @Override public void setValue(final String value) {
729                if (value == null)
730                    throw new NullPointerException();
731    
732                if (!value.equals(BLANK)) {
733                    String name = data.getBandNameFromWaveNumber(Float.parseFloat(value));
734                    bands.setSelectedItem(name);
735                } else {     
736                    bands.setSelectedItem(BLANK);
737                }
738            }
739    
740            @Override public String getValue() {
741                return (String)bands.getSelectedItem();
742            }
743        }
744    }