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 }