001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2015
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 */
028package edu.wisc.ssec.mcidasv.data;
029
030import static javax.swing.GroupLayout.Alignment.BASELINE;
031import static javax.swing.GroupLayout.Alignment.LEADING;
032import static javax.swing.GroupLayout.Alignment.TRAILING;
033import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
034
035import java.awt.Container;
036import java.awt.Dimension;
037import java.awt.EventQueue;
038import java.awt.Font;
039import java.awt.event.ActionEvent;
040import java.awt.event.ActionListener;
041import java.awt.event.WindowEvent;
042import java.awt.event.WindowAdapter;
043import java.awt.event.WindowListener;
044import java.io.ByteArrayInputStream;
045import java.io.ByteArrayOutputStream;
046import java.io.File;
047import java.io.IOException;
048import java.util.Iterator;
049import java.util.LinkedList;
050import java.util.List;
051
052import javax.swing.BoxLayout;
053import javax.swing.GroupLayout;
054import javax.swing.JButton;
055import javax.swing.JCheckBox;
056import javax.swing.JComboBox;
057import javax.swing.JDialog;
058import javax.swing.JEditorPane;
059import javax.swing.JFrame;
060import javax.swing.JLabel;
061import javax.swing.JOptionPane;
062import javax.swing.JPanel;
063import javax.swing.JRadioButton;
064import javax.swing.JScrollPane;
065import javax.swing.JSeparator;
066import javax.swing.JTextField;
067import javax.swing.JTextPane;
068import javax.swing.JToolBar;
069import javax.swing.ScrollPaneConstants;
070import javax.swing.UIManager;
071import javax.swing.WindowConstants;
072import javax.swing.border.EmptyBorder;
073import javax.swing.event.HyperlinkEvent;
074import javax.swing.event.HyperlinkListener;
075import javax.swing.text.PlainDocument;
076
077import org.slf4j.Logger;
078import org.slf4j.LoggerFactory;
079
080import net.miginfocom.swing.MigLayout;
081
082import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
083import edu.wisc.ssec.mcidasv.util.McVGuiUtils.IconPanel;
084import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Prefer;
085import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width;
086import edu.wisc.ssec.mcidasv.util.WebBrowser;
087import edu.wisc.ssec.mcidasv.Constants;
088
089import ucar.ma2.Array;
090import ucar.nc2.Variable;
091import ucar.nc2.dataset.NetcdfDataset;
092import ucar.nc2.ncml.NcMLReader;
093import ucar.nc2.dt.grid.GridDataset;
094
095import ucar.unidata.util.FileManager;
096import ucar.unidata.util.GuiUtils;
097import ucar.unidata.util.IOUtil;
098import ucar.unidata.util.Misc;
099
100import ucar.unidata.data.DataSourceDescriptor;
101import ucar.unidata.data.grid.GeoGridDataSource;
102import ucar.unidata.idv.IntegratedDataViewer;
103
104import visad.ConstantMap;
105import visad.Display;
106import visad.FlatField;
107import visad.python.JPythonMethods;
108import visad.ss.BasicSSCell;
109import visad.ss.FancySSCell;
110
111
112public 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}