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 package edu.wisc.ssec.mcidasv.data; 029 030 import static javax.swing.GroupLayout.Alignment.BASELINE; 031 import static javax.swing.GroupLayout.Alignment.LEADING; 032 import static javax.swing.GroupLayout.Alignment.TRAILING; 033 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 034 035 import java.awt.Container; 036 import java.awt.Dimension; 037 import java.awt.EventQueue; 038 import java.awt.Font; 039 import java.awt.event.ActionEvent; 040 import java.awt.event.ActionListener; 041 import java.awt.event.WindowEvent; 042 import java.awt.event.WindowAdapter; 043 import java.awt.event.WindowListener; 044 import java.io.ByteArrayInputStream; 045 import java.io.ByteArrayOutputStream; 046 import java.io.File; 047 import java.io.IOException; 048 import java.util.Iterator; 049 import java.util.LinkedList; 050 import java.util.List; 051 052 import javax.swing.BoxLayout; 053 import javax.swing.GroupLayout; 054 import javax.swing.JButton; 055 import javax.swing.JCheckBox; 056 import javax.swing.JComboBox; 057 import javax.swing.JDialog; 058 import javax.swing.JEditorPane; 059 import javax.swing.JFrame; 060 import javax.swing.JLabel; 061 import javax.swing.JOptionPane; 062 import javax.swing.JPanel; 063 import javax.swing.JRadioButton; 064 import javax.swing.JScrollPane; 065 import javax.swing.JSeparator; 066 import javax.swing.JTextField; 067 import javax.swing.JTextPane; 068 import javax.swing.JToolBar; 069 import javax.swing.ScrollPaneConstants; 070 import javax.swing.UIManager; 071 import javax.swing.WindowConstants; 072 import javax.swing.border.EmptyBorder; 073 import javax.swing.event.HyperlinkEvent; 074 import javax.swing.event.HyperlinkListener; 075 import javax.swing.text.PlainDocument; 076 077 import org.slf4j.Logger; 078 import org.slf4j.LoggerFactory; 079 080 import net.miginfocom.swing.MigLayout; 081 082 import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 083 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.IconPanel; 084 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Prefer; 085 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 086 import edu.wisc.ssec.mcidasv.util.WebBrowser; 087 import edu.wisc.ssec.mcidasv.Constants; 088 089 import ucar.ma2.Array; 090 import ucar.nc2.Variable; 091 import ucar.nc2.dataset.NetcdfDataset; 092 import ucar.nc2.ncml.NcMLReader; 093 import ucar.nc2.dt.grid.GridDataset; 094 095 import ucar.unidata.util.FileManager; 096 import ucar.unidata.util.GuiUtils; 097 import ucar.unidata.util.IOUtil; 098 import ucar.unidata.util.Misc; 099 100 import ucar.unidata.data.DataSourceDescriptor; 101 import ucar.unidata.data.grid.GeoGridDataSource; 102 import ucar.unidata.idv.IntegratedDataViewer; 103 104 import visad.ConstantMap; 105 import visad.Display; 106 import visad.FlatField; 107 import visad.python.JPythonMethods; 108 import visad.ss.BasicSSCell; 109 import visad.ss.FancySSCell; 110 111 112 public class BadNetCDFWidget implements Constants { 113 114 private static final Logger logger = LoggerFactory.getLogger(BadNetCDFWidget.class); 115 116 private IntegratedDataViewer idv; 117 118 private NetcdfDataset ncFile; 119 private List<Variable> varList; 120 private List<String> varNames; 121 122 123 // For NcML Editor 124 private JEditorPane NcMLeditor; 125 126 127 // For variable display 128 BasicSSCell display; 129 ConstantMap[] cmaps; 130 131 132 // For nav specification 133 private JRadioButton radioLatLonVars = new JRadioButton("Variables", true); 134 private JRadioButton radioLatLonBounds = new JRadioButton("Bounds", false); 135 136 private JComboBox refComboBox = new JComboBox(); 137 private JComboBox latComboBox = new JComboBox(); 138 private JComboBox lonComboBox = new JComboBox(); 139 140 private JPanel panelLatLonVars = new JPanel(); 141 private JPanel panelLatLonBounds = new JPanel(); 142 143 private JTextField textLatUL = new JTextField(); 144 private JTextField textLonUL = new JTextField(); 145 private JTextField textLatLR = new JTextField(); 146 private JTextField textLonLR = new JTextField(); 147 148 149 // TODO: DO WE NEED THESE? 150 private JTextField textLatLonScale = new JTextField(); 151 private JCheckBox checkEastPositive = new JCheckBox("East positive"); 152 153 154 155 156 public BadNetCDFWidget(NetcdfDataset ncFile, IntegratedDataViewer idv) 157 { 158 this.idv = idv; 159 this.ncFile = ncFile; 160 varList = ncFile.getVariables(); 161 162 varNames = new LinkedList<String>(); 163 164 //System.out.println("Our file has " + varList.size() + " variables named:"); 165 Iterator <Variable> varIt = varList.iterator(); 166 while(varIt.hasNext()) 167 { 168 Variable ourVar = varIt.next(); 169 varNames.add(ourVar.getFullName()); 170 //System.out.println("Name: " + ourVar.getName()); 171 } 172 } 173 174 175 // Passes through any exception from openDataset - this function 176 // doesn't provide an IDV and should only be used for testing. (Some functionality 177 // using the rest of the IDV won't work.) 178 public BadNetCDFWidget(String filepath) throws IOException 179 { 180 this(NetcdfDataset.openDataset(filepath), null); 181 } 182 183 184 185 // Tester function to pick a file and send it through the paces. 186 public static void main(String[] args) 187 { 188 String testfile = FileManager.getReadFile(); 189 System.out.println(testfile); 190 191 //String testfile = "/Users/nickb/testdata/tester.nc"; 192 193 194 BadNetCDFWidget bfReader; 195 try { bfReader = new BadNetCDFWidget(testfile); } 196 catch (Exception exe) 197 { 198 //System.out.println("This file cannot be read by the BadFileReader!"); 199 exe.printStackTrace(); 200 return; 201 } 202 203 bfReader.showChoices(); 204 //bfReader.showNavChooser(); 205 } 206 207 208 209 ///////////////////////////////////////////////////////// 210 // Displays our "main menu" of choices to fix the given file! 211 // Everything else needed can get called from here. 212 ///////////////////////////////////////////////////////// 213 public void showChoices() 214 { 215 EventQueue.invokeLater(new Runnable() { 216 public void run() { 217 try { 218 BadNetCDFDialog dialog = new BadNetCDFDialog(); 219 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 220 dialog.setVisible(true); 221 dialog.toFront(); 222 } catch (Exception e) { 223 e.printStackTrace(); 224 } 225 } 226 }); 227 } 228 229 ///////////////////////////////////////////////////////// 230 // Creates an editor for NcML and displays it in a window - includes buttons for saving just 231 // the NcML and the full NetCDF file with the changes made. 232 ///////////////////////////////////////////////////////// 233 private void showNcMLEditor() 234 { 235 NcMLeditor = new JEditorPane(); 236 237 // We use this to store the actual ncml - 10000 is just the number toolsUI used 238 ByteArrayOutputStream bos = new ByteArrayOutputStream(10000); 239 try 240 { 241 ncFile.writeNcML(bos, null); 242 NcMLeditor.setText(bos.toString()); 243 NcMLeditor.setCaretPosition(0); 244 245 } catch (IOException ioe) 246 { 247 ioe.printStackTrace(); 248 //setInError(true, false, ""); DataSourceImpl - doesn't work if we're not a data source 249 return; 250 } 251 252 NcMLeditor.setEditable(true); 253 254 // Set the font style. 255 NcMLeditor.setFont(new Font("Courier", Font.PLAIN, 12)); 256 257 // Set the tab size 258 NcMLeditor.getDocument().putProperty(PlainDocument.tabSizeAttribute, 2); 259 260 261 // Button to save NcML as text, 262 // popup allows them to specify where. 263 JButton saveNcMLBtn = new JButton("Save NcML as text"); 264 ActionListener saveAction = new ActionListener() 265 { 266 public void actionPerformed(ActionEvent ae) 267 { 268 // Begin with getting the filename we want to write to. 269 String ncLocation = ncFile.getLocation(); 270 271 if (ncLocation == null) ncLocation = "test"; 272 int pos = ncLocation.lastIndexOf("."); 273 if (pos > 0) 274 ncLocation = ncLocation.substring(0, pos); 275 276 String filename = FileManager.getWriteFile(ncLocation + ".ncml"); 277 if (filename == null) return; 278 // System.out.println("Write NcML to filename:" + filename); 279 280 281 // Once we have that, we can actually write to the file! 282 try{ 283 IOUtil.writeFile(new File(filename), NcMLeditor.getText()); 284 } catch(Exception exc) 285 { 286 // TODO: Should probably add some kind of exception handling. 287 exc.printStackTrace(); 288 return; 289 } 290 } 291 }; 292 saveNcMLBtn.addActionListener(saveAction); 293 294 295 // Button to merge the NcML with NetCDF 296 // a'la ToolsUI and write it back out as NetCDF3. 297 JButton saveNetCDFBtn = new JButton("Merge and save NetCDF"); 298 ActionListener saveNetCDFAction = new ActionListener() 299 { 300 public void actionPerformed(ActionEvent ae) 301 { 302 // Begin with getting the filename we want to write to. 303 String ncLocation = ncFile.getLocation(); 304 305 if (ncLocation == null) ncLocation = "test"; 306 int pos = ncLocation.lastIndexOf("."); 307 if (pos > 0) 308 ncLocation = ncLocation.substring(0, pos); 309 310 String filename = FileManager.getWriteFile(ncLocation + ".nc"); 311 if (filename == null) return; 312 // System.out.println("Write NetCDF to filename:" + filename); 313 314 315 // Once we have that, we can actually write to the file! 316 try { 317 ByteArrayInputStream bis = new ByteArrayInputStream(NcMLeditor.getText().getBytes()); 318 NcMLReader.writeNcMLToFile(bis, filename); 319 } catch(Exception exc) 320 { 321 // TODO: Should probably add some kind of exception handling. 322 exc.printStackTrace(); 323 return; 324 } 325 } 326 }; 327 saveNetCDFBtn.addActionListener(saveNetCDFAction); 328 329 330 // Button to load this data into McV from NcML 331 JButton sendToMcVBtn = new JButton("Attempt to load with this NcML"); 332 ActionListener sendToMcVAction = new ActionListener() 333 { 334 public void actionPerformed(ActionEvent ae) 335 { 336 // TODO: save the current NcML into the NetcdfDataSource 337 createIDVdisplay(); 338 return; 339 } 340 }; 341 sendToMcVBtn.addActionListener(sendToMcVAction); 342 343 344 JToolBar toolbar = new JToolBar("NcML Editor Controls"); 345 346 toolbar.add(saveNcMLBtn); 347 toolbar.add(saveNetCDFBtn); 348 toolbar.add(sendToMcVBtn); 349 350 351 JScrollPane scrollPane = new JScrollPane(NcMLeditor, 352 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 353 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 354 355 scrollPane.setPreferredSize(new Dimension(600, 600)); // TODO: PREFERRED SIZE? 356 357 JPanel panel = GuiUtils.topCenter(toolbar, scrollPane); 358 JFrame editorWindow = GuiUtils.makeWindow("NcML Editor", GuiUtils.inset(panel, 10), 0, 0); 359 editorWindow.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 360 editorWindow.setVisible(true); 361 editorWindow.toFront(); 362 363 // System.out.println("NcML Editor Created!"); 364 } 365 366 367 368 369 370 ///////////////////////////////////////////////////////// 371 // Takes our ncFile and puts it back into IDV (McV) 372 ///////////////////////////////////////////////////////// 373 private void createIDVdisplay() 374 { 375 376 // Make a NetcdfDataset from our NcML 377 378 ByteArrayInputStream bis = new ByteArrayInputStream(NcMLeditor.getText().getBytes()); 379 380 try { 381 ncFile = NcMLReader.readNcML(bis, null); 382 } catch (IOException e1) { 383 // TODO Auto-generated catch block 384 e1.printStackTrace(); 385 return; 386 } 387 388 389 // Now try to turn that NetcdfDataset into a legitimate DataSource! 390 GridDataset gd; 391 392 // System.out.println("Creating the grid dataset..."); 393 394 try { 395 gd = new GridDataset(ncFile); 396 } catch (IOException e) { 397 // TODO Auto-generated catch block 398 e.printStackTrace(); 399 return; 400 } 401 402 ncFile.getLocation(); 403 // System.out.println("Grid dataset created! Adding to data manager..."); 404 // GeoGridDataSource ggds = new GeoGridDataSource(gd); 405 DataSourceDescriptor dsd = new DataSourceDescriptor(); 406 dsd.setLabel("NcML DS Label"); 407 GeoGridDataSource ggds = new GeoGridDataSource(dsd, gd, "NcML Data Source", ncFile.getLocation()); 408 ggds.initAfterCreation(); 409 this.idv.getDataManager().addDataSource(ggds); 410 } 411 412 413 414 415 416 ///////////////////////////////////////////////////////// 417 // Shows a window that gives a choice of variables! 418 ///////////////////////////////////////////////////////// 419 private void showVarPicker() 420 { 421 // DataImpl 422 //Array arr = var.read(); 423 424 JComboBox varDD = new JComboBox(); 425 GuiUtils.setListData(varDD, varNames); 426 427 ActionListener getVarAction = new ActionListener() 428 { 429 public void actionPerformed(ActionEvent ae) 430 { 431 JComboBox cb = (JComboBox)ae.getSource(); 432 Variable plotVar = varList.get(cb.getSelectedIndex()); 433 String varName = (String) cb.getSelectedItem(); 434 435 436 float [] varVals; 437 try{ 438 // TODO: Is there a better way to convert this? Is there another function like reshape? 439 Array varArray = plotVar.read(); 440 varVals = (float[]) varArray.get1DJavaArray(float.class); 441 // TODO: Better exception handling 442 } 443 catch (IOException IOexe) 444 { 445 IOexe.printStackTrace(); 446 return; 447 } 448 449 int size = plotVar.getDimensions().size(); 450 if( size != 2) 451 { 452 //System.err.println("We should fail here because size != 2, size ==" + size); 453 JOptionPane.showMessageDialog(null, 454 ("<html>Variables must have 2 dimensions to be displayed here.<br><br>\"" + varName + "\" has " + size + ".</html>"), 455 "Invalid Dimensions", 456 JOptionPane.ERROR_MESSAGE); 457 return; 458 } 459 460 int xdim = plotVar.getDimensions().get(0).getLength(); 461 int ydim = plotVar.getDimensions().get(1).getLength(); 462 463 // System.out.println("xdim: " + xdim + " ydim: " + ydim); 464 465 float[][] var2D = reshape(varVals, ydim, xdim); 466 467 //JPythonMethods.plot(varVals); 468 //JPythonMethods.plot(var2D); 469 470 try { 471 FlatField varField = JPythonMethods.field(var2D); 472 473 474 ConstantMap[] cmaps = { 475 new ConstantMap(1.0, Display.Red), 476 new ConstantMap(1.0, Display.Green), 477 new ConstantMap(1.0, Display.Blue) 478 }; 479 480 // Clear out the display or we get some weird stuff going on. 481 display.clearCell(); 482 display.clearMaps(); 483 display.clearDisplay(); 484 485 display.addData(varField, cmaps); 486 487 /* // Make sure data isn't lingering around: 488 String[] dataSources = display.getDataSources(); 489 System.out.println("Data sources: " + dataSources.length); */ 490 } 491 // TODO: Better exception handling - throughout this whole file, really. 492 catch (Exception exe) 493 { 494 exe.printStackTrace(); 495 return; 496 497 } 498 } 499 }; 500 varDD.addActionListener(getVarAction); 501 502 //BasicSSCell display = new FancySSCell("Variable!"); 503 //display.setDimension(BasicSSCell.JAVA3D_3D); 504 505 // TODO: exception handling 506 try 507 { 508 // Heavily borrowed from VISAD's JPythonMethods 509 display = new FancySSCell("Variable Viewer"); 510 display.setDimension(BasicSSCell.JAVA3D_3D); 511 display.setPreferredSize(new Dimension(256, 256)); 512 JFrame frame = new JFrame("Variable Viewer"); 513 JPanel pane = new JPanel(); 514 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 515 frame.setContentPane(pane); 516 pane.add(varDD); 517 pane.add(display); 518 JButton controls = new JButton("Controls"); 519 JPanel buttons = new JPanel(); 520 buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS)); 521 buttons.add(controls); 522 pane.add(buttons); 523 final FancySSCell fdisp = (FancySSCell) display; 524 fdisp.setAutoShowControls(false); 525 526 controls.addActionListener(new ActionListener() { 527 public void actionPerformed(ActionEvent e) { 528 fdisp.showWidgetFrame(); 529 } 530 }); 531 532 frame.pack(); 533 // frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 534 frame.setVisible(true); 535 frame.toFront(); 536 537 } 538 // TODO: Exception handling 539 catch (Exception exe) { 540 exe.printStackTrace(); 541 return; 542 } 543 544 } 545 546 547 548 // Quick and dirty function to reshape a 1D float array into a 2D 549 private static float[][] reshape(float[] arr, int m, int n) 550 { 551 float[][] newArr = new float[m][n]; 552 553 int index=0; 554 for (int i = 0; i < n; i++) 555 { 556 for(int j = 0; j< m; j++) 557 { 558 newArr[j][i] = arr[index++]; 559 } 560 } 561 return newArr; 562 } 563 564 565 566 ///////////////////////////////////////////////////////// 567 // Shows a window that gives the opportunity to either define 568 // coordinate variables or specify corner points. 569 // 570 // Borrowed heavily from FlatFileChooser's makeNavigationPanel for style 571 ///////////////////////////////////////////////////////// 572 private void showNavChooser() 573 { 574 JPanel midPanel = new JPanel(); 575 midPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Navigation")); 576 577 GuiUtils.setListData(refComboBox, varNames); 578 GuiUtils.setListData(latComboBox, varNames); 579 GuiUtils.setListData(lonComboBox, varNames); 580 581 McVGuiUtils.setComponentWidth(latComboBox, Width.QUADRUPLE); 582 McVGuiUtils.setComponentWidth(lonComboBox, Width.QUADRUPLE); 583 McVGuiUtils.setComponentWidth(refComboBox, Width.QUADRUPLE); 584 585 //panelLatLonVars = McVGuiUtils.topBottom(latComboBox, lonComboBox, Prefer.NEITHER); 586 panelLatLonVars = McVGuiUtils.topBottom(McVGuiUtils.makeLabeledComponent("Latitude:",latComboBox), 587 McVGuiUtils.makeLabeledComponent("Longitude:",lonComboBox), 588 Prefer.NEITHER); 589 590 591 GuiUtils.buttonGroup(radioLatLonVars, radioLatLonBounds); 592 593 // Images to make the bounds more clear 594 IconPanel urPanel = new IconPanel("/edu/wisc/ssec/mcidasv/images/upper_right.gif"); 595 IconPanel llPanel = new IconPanel("/edu/wisc/ssec/mcidasv/images/lower_left.gif"); 596 597 McVGuiUtils.setComponentWidth(textLatUL); 598 McVGuiUtils.setComponentWidth(textLonUL); 599 McVGuiUtils.setComponentWidth(textLatLR); 600 McVGuiUtils.setComponentWidth(textLonLR); 601 panelLatLonBounds = McVGuiUtils.topBottom( 602 McVGuiUtils.makeLabeledComponent("UL Lat/Lon:", GuiUtils.leftRight(GuiUtils.hbox(textLatUL, textLonUL), urPanel)), 603 McVGuiUtils.makeLabeledComponent("LR Lat/Lon:", GuiUtils.leftRight(llPanel, GuiUtils.hbox(textLatLR, textLonLR))), 604 Prefer.NEITHER); 605 606 panelLatLonBounds = McVGuiUtils.topBottom(panelLatLonBounds, McVGuiUtils.makeLabeledComponent("Reference:", refComboBox), Prefer.NEITHER); 607 608 609 McVGuiUtils.setComponentWidth(radioLatLonVars); 610 McVGuiUtils.setComponentWidth(radioLatLonBounds); 611 612 613 // Add a bit of a buffer to both 614 panelLatLonVars = GuiUtils.inset(panelLatLonVars, 5); 615 panelLatLonBounds = GuiUtils.inset(panelLatLonBounds, 5); 616 617 GroupLayout layout = new GroupLayout(midPanel); 618 midPanel.setLayout(layout); 619 layout.setHorizontalGroup( 620 layout.createParallelGroup(LEADING) 621 .addGroup(layout.createSequentialGroup() 622 .addContainerGap() 623 .addGroup(layout.createParallelGroup(LEADING) 624 .addGroup(layout.createSequentialGroup() 625 .addComponent(radioLatLonVars) 626 .addGap(GAP_RELATED) 627 .addComponent(panelLatLonVars)) 628 .addGroup(layout.createSequentialGroup() 629 .addComponent(radioLatLonBounds) 630 .addGap(GAP_RELATED) 631 .addComponent(panelLatLonBounds))) 632 .addContainerGap()) 633 ); 634 layout.setVerticalGroup( 635 layout.createParallelGroup(LEADING) 636 .addGroup(TRAILING, layout.createSequentialGroup() 637 .addContainerGap() 638 .addGroup(layout.createParallelGroup(BASELINE) 639 .addComponent(radioLatLonVars) 640 .addComponent(panelLatLonVars)) 641 .addPreferredGap(RELATED) 642 .addGroup(layout.createParallelGroup(BASELINE) 643 .addComponent(radioLatLonBounds) 644 .addComponent(panelLatLonBounds)) 645 .addPreferredGap(RELATED) 646 .addContainerGap()) 647 ); 648 649 650 651 radioLatLonVars.addActionListener(new ActionListener(){ 652 public void actionPerformed(ActionEvent e) { 653 checkSetLatLon(); 654 } 655 }); 656 657 radioLatLonBounds.addActionListener(new ActionListener(){ 658 public void actionPerformed(ActionEvent e) { 659 checkSetLatLon(); 660 } 661 }); 662 663 664 JButton goBtn = new JButton("Go!"); 665 ActionListener goBtnAction = new ActionListener() 666 { 667 public void actionPerformed(ActionEvent ae) 668 { 669 boolean isVar = radioLatLonVars.isSelected(); 670 if (isVar) 671 navVarAction(); 672 else 673 navCornersAction(); 674 } 675 }; 676 goBtn.addActionListener(goBtnAction); 677 678 679 JPanel wholePanel = McVGuiUtils.topBottom(midPanel, goBtn, Prefer.NEITHER); 680 681 JFrame myWindow = GuiUtils.makeWindow("Pick Your Navigation!", GuiUtils.inset(wholePanel, 10), 0, 0); 682 checkSetLatLon(); 683 myWindow.setVisible(true); 684 myWindow.toFront(); 685 } 686 687 688 /** 689 * enable/disable widgets for navigation 690 */ 691 private void checkSetLatLon() { 692 boolean isVar = radioLatLonVars.isSelected(); 693 GuiUtils.enableTree(panelLatLonVars, isVar); 694 GuiUtils.enableTree(panelLatLonBounds, !isVar); 695 } 696 697 698 /** 699 * 700 * One of the two workhorses of our nav chooser, it alters the chosen 701 * (existing) variables so they can be used as lat/lon pairs. 702 * 703 */ 704 private void navVarAction() 705 { 706 707 } 708 709 710 711 /** 712 * 713 * One of the two workhorses of our nav chooser, it creates new 714 * variables for lat/lon based on the specified cornerpoints and 715 * reference variable (for dimensions.) 716 * 717 */ 718 719 private void navCornersAction() 720 { 721 722 } 723 724 public class BadNetCDFDialog extends JDialog { 725 726 /** 727 * Create the dialog. 728 */ 729 public BadNetCDFDialog() { 730 setTitle("Non-Compliant NetCDF Tool"); 731 setMinimumSize(new Dimension(705, 320)); 732 setBounds(100, 100, 705, 320); 733 Container contentPane = getContentPane(); 734 735 JLabel headerLabel = new JLabel("McIDAS-V is unable to read your file."); 736 headerLabel.setFont(UIManager.getFont("OptionPane.font")); 737 headerLabel.setBorder(new EmptyBorder(0, 0, 4, 0)); 738 739 JTextPane messageTextPane = new JTextPane(); 740 Font textPaneFont = UIManager.getFont("TextPane.font"); 741 String fontCss = String.format("style=\"font-family: '%s'; font-size: %d;\"", textPaneFont.getFamily(), textPaneFont.getSize()); 742 messageTextPane.setBackground(UIManager.getColor("Label.background")); 743 messageTextPane.setContentType("text/html"); 744 messageTextPane.setDragEnabled(false); 745 messageTextPane.setText("<html>\n<body "+fontCss +">To verify if your file is CF-compliant, you can run your file through an online compliance checker (<a href=\"http://titania.badc.rl.ac.uk/cgi-bin/cf-checker.pl\">example CF-compliance utility</a>).<br/><br/> \n\nIf the checker indicates that your file is not compliant you can attempt to fix it using the NcML Editor provided in this window.<br/><br/>\n\nIn a future release of McIDAS-V, this interface will present you with choices for the variables necessary for McIDAS-V to display your data.<br/></font></body></html>"); 746 messageTextPane.setEditable(false); 747 messageTextPane.addHyperlinkListener(new HyperlinkListener() { 748 public void hyperlinkUpdate(HyperlinkEvent e) { 749 if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) { 750 return; 751 } 752 String url = null; 753 if (e.getURL() == null) { 754 url = e.getDescription(); 755 } else { 756 url = e.getURL().toString(); 757 } 758 WebBrowser.browse(url); 759 } 760 }); 761 762 763 JSeparator separator = new JSeparator(); 764 // seems pretty dumb to have to do this sizing business in order to get the separator to appear, right? 765 // check out: http://docs.oracle.com/javase/tutorial/uiswing/components/separator.html 766 // "Separators have almost no API and are extremely easy to use as 767 // long as you keep one thing in mind: In most implementations, 768 // a vertical separator has a preferred height of 0, and a 769 // horizontal separator has a preferred width of 0. This means a 770 // separator is not visible unless you either set its preferred 771 // size or put it in under the control of a layout manager such as 772 // BorderLayout or BoxLayout that stretches it to fill its 773 // available display area." 774 // WHO ON EARTH DECIDED THAT WAS SENSIBLE DEFAULT BEHAVIOR FOR A SEPARATOR WIDGET!? 775 separator.setMinimumSize(new Dimension(1, 12)); 776 separator.setPreferredSize(new Dimension(1, 12)); 777 778 779 JLabel editorLabel = new JLabel("Open the file in the NcML editor:"); 780 781 JButton editorButton = new JButton("NcML Editor"); 782 editorButton.addActionListener(new ActionListener() { 783 @Override public void actionPerformed(ActionEvent e) { 784 showNcMLEditor(); 785 } 786 }); 787 788 JLabel viewLabel = new JLabel("I just want to view one of the variables:"); 789 790 JButton viewButton = new JButton("View Variable"); 791 viewButton.addActionListener(new ActionListener() { 792 @Override public void actionPerformed(ActionEvent e) { 793 showVarPicker(); 794 } 795 }); 796 797 JLabel noncompliantLabel = new JLabel("I have navigation variables, they just aren't CF-compliant: (FEATURE INCOMPLETE)"); 798 799 JButton noncompliantButton = new JButton("Choose Nav"); 800 noncompliantButton.addActionListener(new ActionListener() { 801 public void actionPerformed(ActionEvent e) { 802 showNavChooser(); 803 } 804 }); 805 this.addWindowListener(new WindowAdapter() { 806 public void windowClosing(WindowEvent e) { 807 logger.trace("disposing of dialog"); 808 BadNetCDFDialog.this.dispose(); 809 } 810 }); 811 812 contentPane.setLayout(new MigLayout( 813 "", 814 "[grow][]", 815 "[][grow][][][][][][]")); 816 contentPane.add(headerLabel, "spanx 2, alignx left, aligny top, wrap"); 817 contentPane.add(messageTextPane, "spanx 2, grow, wrap"); 818 contentPane.add(separator, "spanx 2, growx, aligny top, wrap"); 819 contentPane.add(editorLabel, "alignx left, aligny baseline"); 820 contentPane.add(editorButton, "growx, aligny baseline, wrap"); 821 contentPane.add(viewLabel, "alignx left, aligny baseline"); 822 contentPane.add(viewButton, "growx, aligny baseline, wrap"); 823 contentPane.add(noncompliantLabel, "alignx left, aligny baseline"); 824 contentPane.add(noncompliantButton, "growx, aligny baseline, wrap"); 825 826 } 827 } 828 }