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