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