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