1 //------------------------------------------------------------------------------
2 // ssgui: a Java GUI interface for viewing, selecting, and downloading matrices
3 // from the SuiteSparse Matrix Collection.  To compile this program, type the
4 // following in your OS command window:
5 //
6 //      javac ssgui.java
7 //      jar cfe ssgui.jar ssgui *.class sshelp.html
8 //
9 // You can then delete the *.class files.  To run the program, type:
10 //
11 //      java -jar ssgui.jar
12 //
13 // In all platforms except Windows (Mac, Linux, Solaris, ...) compile with:
14 //
15 //      make
16 //
17 // and run with
18 //
19 //      make run
20 //
21 //------------------------------------------------------------------------------
22 // Changing the default parameters for ssgui:
23 //------------------------------------------------------------------------------
24 //
25 // The following parameters of ssgui can be changed by editing this file and
26 // recompiling (see the comments "default settings" below in the code).
27 // Each setting is a string:
28 //
29 //      sssite: URL for the SuiteSparse Matrix Collection
30 //      default is sssite = "https://sparse.tamu.edu" ;
31 //
32 //      ssarchive: directory containing your copy of the collection.
33 //      If blank, then it defaults to the directory containing ssgui.
34 //
35 //      refresh: refresh time, in days, for updating the index.  use INF to
36 //      never refresh
37 //
38 //      proxy_server: HTTP proxy server. If none (default), then leave blank.
39 //
40 //      proxy port: default is 80 if left blank
41 //
42 // Copyright (c) 2009-2019, Timothy A. Davis.  See sshelp.html for the license,
43 // and for help on how to use this program, or click "Help" in the GUI.
44 //------------------------------------------------------------------------------
45 
46 import java.io.* ;
47 import java.util.* ;
48 import java.text.* ;
49 import java.net.* ;
50 import javax.swing.* ;
51 import javax.swing.table.* ;
52 import javax.swing.event.* ;
53 import java.awt.* ;
54 import java.awt.event.* ;
55 
56 public class ssgui extends JFrame
57 {
58 
59     //--------------------------------------------------------------------------
60     // private variables, accessible to all methods in this class
61     //--------------------------------------------------------------------------
62 
63     private static final String
64         ssstats = "files/ssstats.csv",
65         ssindex = "files/ss_index.mat",
66         all_kinds = "(all kinds)", all_groups = "(all groups)" ;
67     private static final int K = 1024, M = K*K, buffersize = K,
68         MSEC_PER_DAY = 86400000 ;
69 
70     private static long INF = Long.MAX_VALUE ;
71 
72     private long refresh ;
73     private int nselected ;
74     private int [ ] download_ids = null ;
75     private boolean gui_ready, downloading, cancel, get_icons ;
76     private boolean debug = false ;
77 
78     private matrix_Table_Model matrix_model = null ;
79 
80     private File mat, MM, RB, iconDir ;
81     private String [ ] Kinds, Groups ;
82     private Object [ ][ ] Stats ;
83 
84     private Date today, last_download ;
85 
86     // files and input/output streams
87     private static String ftemp_name = null ;
88     private static BufferedOutputStream ftemp_out = null ;
89     private static BufferedInputStream url_in = null ;
90     private static BufferedReader in_reader = null ;
91     private static PrintWriter print_out = null ;
92     private static String sssite, ssarchive, proxy_server, proxy_port ;
93 
94     // Java Swing components available to all methods in this class:
95     private JTable matrix_Table ;
96     private JButton download_Button, cancel_Button ;
97     private JTextField minrow_Field, maxrow_Field, mincol_Field, maxcol_Field,
98         minnentries_Field, maxnentries_Field, minpsym_Field, maxpsym_Field,
99         minnsym_Field, maxnsym_Field ;
100     private JRadioButton posdef_yes_Button, posdef_no_Button,
101         posdef_either_Button, nd_yes_Button, nd_no_Button, nd_either_Button,
102         real_yes_Button, real_no_Button, real_either_Button,
103         shape_square_Button, shape_rect_Button, shape_either_Button ;
104     private JLabel nselected_Label, progress_size_Label, icon_Label ;
105     private JCheckBox format_mat_Button, format_mm_Button, format_rb_Button ;
106     private JProgressBar progress1_Bar, progress2_Bar ;
107     private JFileChooser chooser ;
108     private JList Group_List, Kind_List ;
109 
110     //--------------------------------------------------------------------------
111     // create the GUI
112     //--------------------------------------------------------------------------
113 
ssgui( )114     private ssgui ( )
115     {
116         gui_ready = false ;
117         downloading = false ;
118         cancel = false ;
119         final Font plain_Font = new Font ("SansSerif", Font.PLAIN, 12) ;
120         final Font small_Font = new Font ("SansSerif", Font.PLAIN, 10) ;
121         today = new Date ( ) ;
122         last_download = new Date ( ) ;
123 
124         //----------------------------------------------------------------------
125         // default settings.  Edit this file and recompile to change them.
126         //----------------------------------------------------------------------
127 
128         // If ssarchive is blank, then it defaults to the current directory.
129         ssarchive = "" ;
130 
131         // URL for the SuiteSparse Matrix Collection
132         sssite = "https://sparse.tamu.edu" ;
133 
134         // refresh time, in days.  use INF to never refresh
135         refresh = 30 ;
136 
137         // HTTP proxy server. If none (default), then leave blank.
138         proxy_server = "" ;
139 
140         // proxy port (default is 80 if left blank)
141         proxy_port = "" ;
142 
143         //----------------------------------------------------------------------
144         //----------------------------------------------------------------------
145 
146         // set up the HTTP proxy
147         if (proxy_server.length ( ) > 0)
148         {
149             if (proxy_port.length ( ) == 0)
150             {
151                 proxy_port = "80" ;
152             }
153             // set the proxy server and port
154             System.setProperty ("proxySet", "true" ) ;
155             System.setProperty ("http.proxyHost", proxy_server) ;
156             System.setProperty ("http.proxyPort", proxy_port) ;
157         }
158 
159         // ssarchive defaults to current working directory, if empty
160         if (ssarchive.length ( ) == 0)
161         {
162             ssarchive = System.getProperty ("user.dir") ;
163         }
164         ssarchive = ssarchive.replace ('\\', File.separatorChar) ;
165         ssarchive = ssarchive.replace ('/', File.separatorChar) ;
166         char c = ssarchive.charAt (ssarchive.length ( ) - 1) ;
167         if (c != File.separatorChar)
168         {
169             ssarchive += File.separatorChar ;
170         }
171 
172         if (debug)
173         {
174             System.out.println ("") ;
175             System.out.println ("ssgui, debugging enabled.") ;
176             System.out.println ("local archive: [" + ssarchive    + "]") ;
177             System.out.println ("ss url:        [" + sssite       + "]") ;
178             System.out.println ("refresh:       [" + refresh      + "]") ;
179             System.out.println ("proxy server:  [" + proxy_server + "]") ;
180             System.out.println ("proxy port:    [" + proxy_port   + "]") ;
181         }
182 
183         //----------------------------------------------------------------------
184         // make sure the top-level directories exist
185 
186         mat = CheckDir ("mat") ;
187         MM = CheckDir ("MM") ;
188         RB = CheckDir ("RB") ;
189         iconDir = CheckDir ("files") ;
190 
191         //----------------------------------------------------------------------
192         // read in the matrix statistics
193 
194         Stats = load_ssstats ( ) ;
195 
196         if (Stats == null ||
197             ((today.getTime ( ) - last_download.getTime ( )) / MSEC_PER_DAY
198             > refresh))
199         {
200             // ssstats file is missing, or old.  Download both
201             // files/ssstats.csv and mat/ss_index.mat.
202             Stats = download_matrix_stats ( ) ;
203             if (debug) System.out.println ("downloading new ssstats.csv file") ;
204         }
205 
206         if (Stats == null)
207         {
208             // display error dialog and quit
209             JOptionPane.showMessageDialog (this,
210                 "Download of matrix statistics file failed.",
211                 "Error", JOptionPane.ERROR_MESSAGE) ;
212             System.exit (-1) ;
213         }
214 
215         //----------------------------------------------------------------------
216         // set the title, and close on [x]
217 
218         setTitle ("ssgui: SuiteSparse Matrix Collection") ;
219         setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE) ;
220 
221         //----------------------------------------------------------------------
222         // selection buttons
223 
224         JPanel select_Button_Panel = new JPanel ( ) ;
225 
226         JButton select_Button = new JButton ("Select") ;
227         JButton unselect_Button = new JButton ("Deselect") ;
228         JButton reset_Button = new JButton ("Reset criteria") ;
229         JButton clear_Button = new JButton ("Clear selections") ;
230         JButton help_Button = new JButton ("Help") ;
231 
232         select_Button_Panel.add (select_Button) ;
233         select_Button_Panel.add (unselect_Button) ;
234         select_Button_Panel.add (reset_Button) ;
235         select_Button_Panel.add (clear_Button) ;
236         select_Button_Panel.add (help_Button) ;
237 
238         select_Button.setToolTipText
239         ("Click to add matrices that fit the criteria to your selection.") ;
240         unselect_Button.setToolTipText ("Click to remove matrices " +
241             "that fit the criteria from your selection.") ;
242         reset_Button.setToolTipText ("Click to reset criteria, above.  " +
243             "Prior selections, below, are not cleared.") ;
244         clear_Button.setToolTipText ("Click to clear selections, below.  " +
245             "Criteria, above, is not reset).") ;
246         help_Button.setToolTipText ("For help, click here") ;
247 
248         select_Button.addActionListener
249         (
250             new ActionListener ( )
251             {
252                 public void actionPerformed (ActionEvent e)
253                 {
254                     make_selection (true) ;
255                 }
256             }
257         ) ;
258 
259         unselect_Button.addActionListener
260         (
261             new ActionListener ( )
262             {
263                 public void actionPerformed (ActionEvent e)
264                 {
265                     make_selection (false) ;
266                 }
267             }
268         ) ;
269 
270         reset_Button.addActionListener
271         (
272             new ActionListener ( )
273             {
274                 public void actionPerformed (ActionEvent e)
275                 {
276                     reset_Button_action (e) ;
277                 }
278             }
279         ) ;
280 
281         clear_Button.addActionListener
282         (
283             new ActionListener ( )
284             {
285                 public void actionPerformed (ActionEvent e)
286                 {
287                     clear_Button_action (e) ;
288                 }
289             }
290         ) ;
291 
292         help_Button.addActionListener
293         (
294             new ActionListener ( )
295             {
296                 public void actionPerformed (ActionEvent e)
297                 {
298                     help_Button_action (e) ;
299                 }
300             }
301         ) ;
302 
303         //----------------------------------------------------------------------
304         // download button and format options
305 
306         JPanel format_Panel = new JPanel ( ) ;
307 
308         format_mat_Button = new JCheckBox ("MATLAB (mat)") ;
309         format_mm_Button = new JCheckBox ("Matrix Market (MM)") ;
310         format_rb_Button = new JCheckBox ("Rutherford/Boeing (RB)    ") ;
311 
312         format_mat_Button.setSelected (true) ;
313 
314         format_mat_Button.setToolTipText ("Download in MATLAB *.mat format.") ;
315         format_mm_Button.setToolTipText ("Download in Matrix Market.") ;
316         format_rb_Button.setToolTipText
317             ("Download in Rutherford/Boeing format.") ;
318 
319         nselected = 0 ;
320         nselected_Label = new JLabel ( ) ;
321         download_Button = new JButton ("Download") ;
322 
323         format_Panel.add (download_Button) ;
324         format_Panel.add (format_mat_Button) ;
325         format_Panel.add (format_mm_Button) ;
326         format_Panel.add (format_rb_Button) ;
327         format_Panel.add (nselected_Label) ;
328         format_Panel.setMaximumSize (new Dimension (0,0)) ;
329 
330         // progress bar and cancel button
331         FlowLayout progress_Layout = new FlowLayout (FlowLayout.LEADING) ;
332         JPanel progress_Panel = new JPanel (progress_Layout) ;
333 
334         cancel_Button = new JButton ("Cancel") ;
335         cancel_Button.setEnabled (false) ;
336         progress1_Bar = new JProgressBar ( ) ;
337         progress2_Bar = new JProgressBar ( ) ;
338         progress_size_Label = new JLabel ("") ;
339         progress1_Bar.setMinimumSize (new Dimension (200,16)) ;
340         progress2_Bar.setMinimumSize (new Dimension (200,16)) ;
341         progress_Panel.add (cancel_Button) ;
342         progress_Panel.add (new JLabel ("   Overall progress:")) ;
343         progress_Panel.add (progress1_Bar) ;
344         progress_Panel.add (new JLabel ("   Current file:")) ;
345         progress_Panel.add (progress2_Bar) ;
346         progress_Panel.add (progress_size_Label) ;
347         progress_Panel.setMaximumSize (new Dimension (0,0)) ;
348         cancel_Button.setToolTipText ("No downloads in progress.") ;
349 
350         download_Button.addActionListener
351         (
352             new ActionListener ( )
353             {
354                 public void actionPerformed (ActionEvent e)
355                 {
356                     download_Button_action (e) ;
357                 }
358             }
359         ) ;
360 
361         cancel_Button.addActionListener
362         (
363             new ActionListener ( )
364             {
365                 public void actionPerformed (ActionEvent e)
366                 {
367                     cancel_Button_action (e) ;
368                 }
369             }
370         ) ;
371 
372         JPanel download_Panel = new JPanel ( ) ;
373         GroupLayout layout3 = new GroupLayout (download_Panel) ;
374         download_Panel.setLayout (layout3) ;
375 
376         layout3.setAutoCreateGaps (true) ;
377         layout3.setAutoCreateContainerGaps (false) ;
378 
379         layout3.setHorizontalGroup
380         (
381             layout3.createParallelGroup (GroupLayout.Alignment.LEADING)
382                 .addComponent (format_Panel)
383                 .addComponent (progress_Panel)
384         ) ;
385 
386         layout3.setVerticalGroup
387         (
388             layout3.createSequentialGroup ( )
389                 .addComponent (format_Panel)
390                 .addComponent (progress_Panel)
391         ) ;
392 
393         download_Panel.setBorder
394             (BorderFactory.createTitledBorder ("download")) ;
395         download_Panel.setMaximumSize (new Dimension (0,0)) ;
396 
397         //----------------------------------------------------------------------
398         // panel for m, n, nentries, psym, and nsym
399 
400         // # of rows
401         minrow_Field = new JTextField ("") ;
402         JLabel rowlabel = new JLabel (" \u2264 number of rows \u2264 ") ;
403         maxrow_Field = new JTextField ("") ;
404         minrow_Field.setColumns (16) ;
405         maxrow_Field.setColumns (16) ;
406         minrow_Field.setToolTipText ("Leave blank for 'zero'.") ;
407         maxrow_Field.setToolTipText ("Leave blank for 'infinite'.") ;
408         minrow_Field.setMinimumSize (new Dimension (120,0)) ;
409         maxrow_Field.setMinimumSize (new Dimension (120,0)) ;
410 
411         // # of columns
412         mincol_Field = new JTextField ("") ;
413         JLabel collabel = new JLabel (" \u2264 number of columns \u2264 ") ;
414         maxcol_Field = new JTextField ("") ;
415         mincol_Field.setColumns (16) ;
416         maxcol_Field.setColumns (16) ;
417         mincol_Field.setToolTipText ("Leave blank for 'zero'.") ;
418         maxcol_Field.setToolTipText ("Leave blank for 'infinite'.") ;
419         mincol_Field.setMinimumSize (new Dimension (120,0)) ;
420         maxcol_Field.setMinimumSize (new Dimension (120,0)) ;
421 
422         // # of entries
423         minnentries_Field = new JTextField ("") ;
424         JLabel nentrieslabel = new JLabel (" \u2264 number of entries \u2264 ");
425         maxnentries_Field = new JTextField ("") ;
426         minnentries_Field.setColumns (16) ;
427         maxnentries_Field.setColumns (16) ;
428         minnentries_Field.setToolTipText ("Leave blank for 'zero'.") ;
429         maxnentries_Field.setToolTipText ("Leave blank for 'infinite'.") ;
430         minnentries_Field.setMinimumSize (new Dimension (120,0)) ;
431         maxnentries_Field.setMinimumSize (new Dimension (120,0)) ;
432 
433         // pattern symmetry
434         minpsym_Field = new JTextField ("0.0") ;
435         JLabel psymlabel = new JLabel (" \u2264 pattern symmetry \u2264 ") ;
436         maxpsym_Field = new JTextField ("1.0") ;
437         minpsym_Field.setColumns (16) ;
438         maxpsym_Field.setColumns (16) ;
439         maxpsym_Field.setToolTipText (
440         "Refers to position of entries, not their values.\n" +
441         "1 = perfectly symmetric pattern, 0 = perfectly unsymmetric pattern.") ;
442         minpsym_Field.setMinimumSize (new Dimension (120,0)) ;
443         maxpsym_Field.setMinimumSize (new Dimension (120,0)) ;
444 
445         // numerical symmetry
446         minnsym_Field = new JTextField ("0.0") ;
447         JLabel nsymlabel = new JLabel (" \u2264 numerical symmetry \u2264 ") ;
448         maxnsym_Field = new JTextField ("1.0") ;
449         minnsym_Field.setColumns (16) ;
450         maxnsym_Field.setColumns (16) ;
451         maxnsym_Field.setToolTipText (
452         "1 means A=A', 0 means no nonzero entry A(i,j) = A(j,i).") ;
453         minnsym_Field.setMinimumSize (new Dimension (120,0)) ;
454         maxnsym_Field.setMinimumSize (new Dimension (120,0)) ;
455 
456         JPanel range_Panel = new JPanel ( ) ;
457         GroupLayout layout5 = new GroupLayout (range_Panel) ;
458         range_Panel.setLayout (layout5) ;
459         layout5.setAutoCreateGaps (false) ;
460         layout5.setAutoCreateContainerGaps (false) ;
461 
462         layout5.setHorizontalGroup
463         (
464             layout5.createSequentialGroup ( )
465                 .addGroup
466                 (
467                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
468                         .addComponent (minrow_Field)
469                         .addComponent (mincol_Field)
470                         .addComponent (minnentries_Field)
471                         .addComponent (minpsym_Field)
472                         .addComponent (minnsym_Field)
473                 )
474                 .addGroup
475                 (
476                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
477                         .addComponent (rowlabel)
478                         .addComponent (collabel)
479                         .addComponent (nentrieslabel)
480                         .addComponent (psymlabel)
481                         .addComponent (nsymlabel)
482                 )
483                 .addGroup
484                 (
485                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
486                         .addComponent (maxrow_Field)
487                         .addComponent (maxcol_Field)
488                         .addComponent (maxnentries_Field)
489                         .addComponent (maxpsym_Field)
490                         .addComponent (maxnsym_Field)
491                 )
492         ) ;
493 
494         layout5.setVerticalGroup
495         (
496             layout5.createSequentialGroup ( )
497 
498                 .addGroup
499                 (
500                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
501                         .addComponent (minrow_Field)
502                         .addComponent (rowlabel)
503                         .addComponent (maxrow_Field)
504                 )
505                 .addGroup
506                 (
507                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
508                         .addComponent (mincol_Field)
509                         .addComponent (collabel)
510                         .addComponent (maxcol_Field)
511                 )
512                 .addGroup
513                 (
514                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
515                         .addComponent (minnentries_Field)
516                         .addComponent (nentrieslabel)
517                         .addComponent (maxnentries_Field)
518                 )
519                 .addGroup
520                 (
521                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
522                         .addComponent (minpsym_Field)
523                         .addComponent (psymlabel)
524                         .addComponent (maxpsym_Field)
525                 )
526                 .addGroup
527                 (
528                     layout5.createParallelGroup (GroupLayout.Alignment.LEADING)
529                         .addComponent (minnsym_Field)
530                         .addComponent (nsymlabel)
531                         .addComponent (maxnsym_Field)
532                 )
533 
534         ) ;
535 
536         range_Panel.setMaximumSize (new Dimension (0,0)) ;
537         // range_Panel.setBorder (BorderFactory.createTitledBorder ("range")) ;
538 
539         //----------------------------------------------------------------------
540         // checkbox panel for posdef, ND, real, and format
541 
542         // square or rectangular
543         JLabel shape_label = new JLabel ("shape ") ;
544         shape_square_Button = new JRadioButton ("square   ") ;
545         shape_rect_Button = new JRadioButton ("rectangular   ") ;
546         shape_either_Button = new JRadioButton ("either   ") ;
547         shape_either_Button.setSelected (true) ;
548         ButtonGroup shape_group = new ButtonGroup ( ) ;
549         shape_group.add (shape_square_Button) ;
550         shape_group.add (shape_rect_Button) ;
551         shape_group.add (shape_either_Button) ;
552         shape_square_Button.setToolTipText
553             ("Select 'yes' for square matrices.") ;
554         shape_rect_Button.setToolTipText
555             ("Select 'no' for rectangular matrices only.") ;
556         shape_either_Button.setToolTipText
557             ("Select 'either' for any matrix.") ;
558 
559         // positive definite
560         JLabel posdef_label = new JLabel ("positive definite? ") ;
561         posdef_yes_Button = new JRadioButton ("yes") ;
562         posdef_no_Button = new JRadioButton ("no") ;
563         posdef_either_Button = new JRadioButton ("either") ;
564         posdef_either_Button.setSelected (true) ;
565         ButtonGroup posdef_group = new ButtonGroup ( ) ;
566         posdef_group.add (posdef_yes_Button) ;
567         posdef_group.add (posdef_no_Button) ;
568         posdef_group.add (posdef_either_Button) ;
569 
570         posdef_yes_Button.setToolTipText
571             ("Select 'yes' for symmetric positive definite matrices only.") ;
572         posdef_no_Button.setToolTipText
573             ("Select 'no' for non-positive definite matrices only.") ;
574         posdef_either_Button.setToolTipText
575             ("Select 'either' for any matrix.") ;
576 
577         // 2D/3D
578         JLabel nd_label = new JLabel ("2D/3D discretization?    ") ;
579         nd_yes_Button = new JRadioButton ("yes") ;
580         nd_no_Button = new JRadioButton ("no") ;
581         nd_either_Button = new JRadioButton ("either") ;
582         nd_either_Button.setSelected (true) ;
583         ButtonGroup nd_group = new ButtonGroup ( ) ;
584         nd_group.add (nd_yes_Button) ;
585         nd_group.add (nd_no_Button) ;
586         nd_group.add (nd_either_Button) ;
587 
588         nd_yes_Button.setToolTipText
589             ("Select 'yes' for matrices " +
590             "arising from 2D or 3D discretizations only.") ;
591         nd_no_Button.setToolTipText
592             ("Select 'no' to exclude matrices " +
593             "arising from 2D or 3D discretizations.") ;
594         nd_either_Button.setToolTipText ("Select 'either' for any matrix.") ;
595 
596         // real or complex
597         JLabel real_label = new JLabel ("real or complex? ") ;
598         real_yes_Button = new JRadioButton ("real") ;
599         real_no_Button = new JRadioButton ("complex") ;
600         real_either_Button = new JRadioButton ("either") ;
601         real_either_Button.setSelected (true) ;
602         ButtonGroup real_group = new ButtonGroup ( ) ;
603         real_group.add (real_yes_Button) ;
604         real_group.add (real_no_Button) ;
605         real_group.add (real_either_Button) ;
606 
607         real_yes_Button.setToolTipText
608             ("Select 'real' for real matrices only (includes integer and binary).") ;
609         real_no_Button.setToolTipText
610             ("Select 'complex' for complex matrices only.") ;
611         real_either_Button.setToolTipText
612             ("Select 'either' for any matrix.") ;
613 
614         JPanel check_Panel = new JPanel ( ) ;
615         GroupLayout layout4 = new GroupLayout (check_Panel) ;
616         check_Panel.setLayout (layout4) ;
617         layout4.setAutoCreateGaps (false) ;
618         layout4.setAutoCreateContainerGaps (false) ;
619 
620         layout4.setHorizontalGroup
621         (
622             layout4.createSequentialGroup ( )
623                 .addGroup
624                 (
625                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
626                         .addComponent (shape_label)
627                         .addComponent (posdef_label)
628                         .addComponent (nd_label)
629                         .addComponent (real_label)
630                 )
631                 .addGroup
632                 (
633                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
634                         .addComponent (shape_square_Button)
635                         .addComponent (posdef_yes_Button)
636                         .addComponent (nd_yes_Button)
637                         .addComponent (real_yes_Button)
638                 )
639                 .addGroup
640                 (
641                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
642                         .addComponent (shape_rect_Button)
643                         .addComponent (posdef_no_Button)
644                         .addComponent (nd_no_Button)
645                         .addComponent (real_no_Button)
646                 )
647                 .addGroup
648                 (
649                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
650                         .addComponent (shape_either_Button)
651                         .addComponent (posdef_either_Button)
652                         .addComponent (nd_either_Button)
653                         .addComponent (real_either_Button)
654                 )
655         ) ;
656 
657         layout4.setVerticalGroup
658         (
659             layout4.createSequentialGroup ( )
660                 .addGroup
661                 (
662                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
663                         .addComponent (shape_label)
664                         .addComponent (shape_square_Button)
665                         .addComponent (shape_rect_Button)
666                         .addComponent (shape_either_Button)
667                 )
668                 .addGroup
669                 (
670                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
671                         .addComponent (posdef_label)
672                         .addComponent (posdef_yes_Button)
673                         .addComponent (posdef_no_Button)
674                         .addComponent (posdef_either_Button)
675                 )
676                 .addGroup
677                 (
678                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
679                         .addComponent (nd_label)
680                         .addComponent (nd_yes_Button)
681                         .addComponent (nd_no_Button)
682                         .addComponent (nd_either_Button)
683                 )
684                 .addGroup
685                 (
686                     layout4.createParallelGroup (GroupLayout.Alignment.LEADING)
687                         .addComponent (real_label)
688                         .addComponent (real_yes_Button)
689                         .addComponent (real_no_Button)
690                         .addComponent (real_either_Button)
691                 )
692         ) ;
693 
694         check_Panel.setMaximumSize (new Dimension (0,0)) ;
695 
696         //----------------------------------------------------------------------
697         // Group and Kind lists
698 
699         Kinds = FindKinds ( ) ;
700         Groups = FindGroups ( ) ;
701 
702         // Group_List = new JList ((Object [ ]) Groups) ;
703         // Kind_List = new JList ((Object [ ]) Kinds) ;
704         Group_List = new JList<String> (Groups) ;
705         Kind_List = new JList<String> (Kinds) ;
706 
707         JScrollPane Group_Pane = new JScrollPane (Group_List) ;
708         JScrollPane Kind_Pane = new JScrollPane (Kind_List) ;
709 
710         Kind_Pane.setBorder (BorderFactory.createTitledBorder ("kind")) ;
711         Group_Pane.setBorder (BorderFactory.createTitledBorder ("group")) ;
712 
713         Group_List.setFont (plain_Font) ;
714         Kind_List.setFont (plain_Font) ;
715 
716         Group_Pane.setVerticalScrollBarPolicy
717             (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) ;
718         Kind_Pane.setVerticalScrollBarPolicy
719             (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) ;
720 
721         Group_List.setVisibleRowCount (5) ;
722         Kind_List.setVisibleRowCount (5) ;
723 
724         JPanel list_Panel = new JPanel ( ) ;
725         GroupLayout layout9 = new GroupLayout (list_Panel) ;
726         list_Panel.setLayout (layout9) ;
727 
728         layout9.setAutoCreateGaps (true) ;
729         layout9.setAutoCreateContainerGaps (false) ;
730 
731         layout9.setHorizontalGroup
732         (
733             layout9.createSequentialGroup ( )
734                 .addComponent (Group_Pane)
735                 .addComponent (Kind_Pane)
736         ) ;
737 
738         layout9.setVerticalGroup
739         (
740             layout9.createParallelGroup (GroupLayout.Alignment.LEADING)
741                 .addComponent (Group_Pane)
742                 .addComponent (Kind_Pane)
743         ) ;
744 
745         list_Panel.setMinimumSize (new Dimension (450,150)) ;
746 
747         //----------------------------------------------------------------------
748         // selection panel
749         JPanel selection_Panel = new JPanel ( ) ;
750         GroupLayout layout2 = new GroupLayout (selection_Panel) ;
751         selection_Panel.setLayout (layout2) ;
752         layout2.setAutoCreateGaps (true) ;
753         layout2.setAutoCreateContainerGaps (false) ;
754         layout2.setHorizontalGroup
755         (
756             layout2.createParallelGroup (GroupLayout.Alignment.LEADING)
757                 .addComponent (range_Panel)
758                 .addComponent (check_Panel)
759                 .addComponent (list_Panel)
760                 .addComponent (select_Button_Panel)
761         ) ;
762         layout2.setVerticalGroup
763         (
764             layout2.createSequentialGroup ( )
765                 .addComponent (range_Panel)
766                 .addComponent (check_Panel)
767                 .addComponent (list_Panel)
768                 .addComponent (select_Button_Panel)
769         ) ;
770         selection_Panel.setBorder
771             (BorderFactory.createTitledBorder ("selection criteria")) ;
772         selection_Panel.setMaximumSize (new Dimension (0,0)) ;
773 
774         //----------------------------------------------------------------------
775         // create the table of matrices
776 
777         matrix_model = new matrix_Table_Model ( ) ;
778         matrix_Table = new JTable (matrix_model)
779         {
780             // table header tool tips
781             protected JTableHeader createDefaultTableHeader ( )
782             {
783                 return new JTableHeader (columnModel)
784                 {
785                     public String getToolTipText (MouseEvent e)
786                     {
787                         String tip = null ;
788                         java.awt.Point p = e.getPoint ( ) ;
789                         int i = columnModel.getColumnIndexAtX (p.x) ;
790                         int j = columnModel.getColumn (i).getModelIndex ( ) ;
791                         return matrix_column_tooltips [j] ;
792                     }
793                 } ;
794             }
795         } ;
796 
797         JTableHeader header = matrix_Table.getTableHeader ( ) ;
798         final TableCellRenderer hr = header.getDefaultRenderer ( ) ;
799         header.setDefaultRenderer
800         (
801             new TableCellRenderer ( )
802             {
803                 public Component getTableCellRendererComponent (JTable table,
804                     Object value, boolean isSelected, boolean hasFocus,
805                     int row, int column)
806                 {
807                     Component co = hr.getTableCellRendererComponent (
808                         table, value, isSelected, hasFocus, row, column) ;
809                     co.setFont (small_Font) ;
810                     return (co) ;
811                 }
812             }
813         ) ;
814 
815         matrix_model.load_data (Stats) ;
816 
817         //----------------------------------------------------------------------
818         // popup menu for the table
819 
820         JPopupMenu popup = new JPopupMenu ( ) ;
821 
822         JMenuItem select_menuItem =
823             new JMenuItem ("Select highlighted matrices") ;
824         select_menuItem.addActionListener
825         (
826             new ActionListener ( )
827             {
828                 public void actionPerformed (ActionEvent e)
829                 {
830                     popup_action (e, true) ;
831                 }
832             }
833         ) ;
834 
835         JMenuItem unselect_menuItem =
836             new JMenuItem ("Deselect highlighted matrices") ;
837         unselect_menuItem.addActionListener
838         (
839             new ActionListener ( )
840             {
841                 public void actionPerformed (ActionEvent e)
842                 {
843                     popup_action (e, false) ;
844                 }
845             }
846         ) ;
847 
848         JMenuItem exportcsv_menuItem =
849             new JMenuItem ("Export selected matrices as CSV file") ;
850         exportcsv_menuItem.addActionListener
851         (
852             new ActionListener ( )
853             {
854                 public void actionPerformed (ActionEvent e)
855                 {
856                     export_list_action (e, true) ;
857                 }
858             }
859         ) ;
860 
861         JMenuItem exportm_menuItem =
862             new JMenuItem ("Export selected matrices as MATLAB *.m file") ;
863         exportm_menuItem.addActionListener
864         (
865             new ActionListener ( )
866             {
867                 public void actionPerformed (ActionEvent e)
868                 {
869                     export_list_action (e, false) ;
870                 }
871             }
872         ) ;
873 
874         popup.add (select_menuItem) ;
875         popup.add (unselect_menuItem) ;
876         popup.add (exportcsv_menuItem) ;
877         popup.add (exportm_menuItem) ;
878 
879         // Add listener to components that can bring up popup menus.
880         matrix_Table.addMouseListener (new matrix_Table_PopupListener (popup)) ;
881 
882         //----------------------------------------------------------------------
883         // set default column widths
884 
885         int [ ] columnwidth = {
886             40,     // 0:select
887             30,     // 1:mat
888             25,     // 2:MM
889             25,     // 3:RB
890             38,     // 4:id
891             110,    // 5:Group
892             150,    // 6:Name
893             70,     // 7:nrows
894             70,     // 8:ncols
895             70,     // 9:nentries
896             40,     // 10:isReal
897             40,     // 11:isBinary
898             40,     // 12:isND
899             40,     // 13:posdef
900             50,     // 14:psym
901             50,     // 15:nsym
902             200 } ; // 16:kind
903 
904         TableColumn column = null ;
905         for (int col = 0 ; col < 17 ; col++)
906         {
907             column = matrix_Table.getColumnModel ( ).getColumn (col) ;
908             column.setPreferredWidth (columnwidth [col]) ;
909         }
910 
911         //----------------------------------------------------------------------
912         // set the view size, sort by id, and add the table to a scroll pane
913 
914         matrix_Table.setPreferredScrollableViewportSize
915             (new Dimension (500,70)) ;
916         matrix_Table.setFillsViewportHeight (true) ;
917         matrix_Table.setAutoCreateRowSorter (true) ;
918 
919         matrix_Table.getSelectionModel ( )
920             .addListSelectionListener (new matrix_Table_RowListener ( )) ;
921 
922         // sort by id
923         java.util.List <RowSorter.SortKey> sortKeys =
924             new ArrayList<RowSorter.SortKey> ( ) ;
925         sortKeys.add (new RowSorter.SortKey (4, SortOrder.ASCENDING)) ;
926         (matrix_Table.getRowSorter ( )).setSortKeys (sortKeys) ;
927 
928         matrix_Table.getTableHeader ( ).setReorderingAllowed (false) ;
929         JScrollPane scroll_Pane = new JScrollPane (matrix_Table) ;
930         scroll_Pane.setBorder (BorderFactory.createTitledBorder (ssarchive)) ;
931 
932         //----------------------------------------------------------------------
933         // create the icon and display the default matrix
934 
935         icon_Label = new JLabel ( ) ;
936         icon_Label.setFont (plain_Font) ;
937         icon_Label.setVerticalTextPosition (JLabel.BOTTOM) ;
938         icon_Label.setHorizontalTextPosition (JLabel.CENTER) ;
939         icon_Label.setBorder (BorderFactory.createTitledBorder ("matrix icon"));
940         update_icon ("HB/west0479") ;
941 
942         //----------------------------------------------------------------------
943         // create the top panel (selection panel and icon)
944 
945         JPanel top_Panel = new JPanel ( ) ;
946         GroupLayout layout8 = new GroupLayout (top_Panel) ;
947         top_Panel.setLayout (layout8) ;
948 
949         layout8.setAutoCreateGaps (true) ;
950         layout8.setAutoCreateContainerGaps (false) ;
951 
952         layout8.setHorizontalGroup
953         (
954             layout8.createSequentialGroup ( )
955                 .addComponent (selection_Panel)
956                 .addComponent (icon_Label)
957         ) ;
958 
959         layout8.setVerticalGroup
960         (
961             layout8.createParallelGroup (GroupLayout.Alignment.LEADING)
962                 .addComponent (selection_Panel)
963                 .addComponent (icon_Label)
964         ) ;
965 
966         top_Panel.setMaximumSize (new Dimension (0,0)) ;
967 
968         //----------------------------------------------------------------------
969         // create the root layout manager
970 
971         Container pane = getContentPane ( ) ;
972         GroupLayout layout = new GroupLayout (pane) ;
973         pane.setLayout (layout) ;
974         layout.setAutoCreateGaps (true) ;
975         layout.setAutoCreateContainerGaps (false) ;
976 
977         layout.setHorizontalGroup
978         (
979             layout.createParallelGroup (GroupLayout.Alignment.LEADING)
980                 .addComponent (top_Panel)
981                 .addComponent (scroll_Pane)
982                 .addComponent (download_Panel)
983         ) ;
984 
985         layout.setVerticalGroup
986         (
987             layout.createSequentialGroup ( )
988                 .addComponent (top_Panel)
989                 .addComponent (scroll_Pane)
990                 .addComponent (download_Panel)
991         ) ;
992 
993         setSize (1100,750) ;
994 
995         //----------------------------------------------------------------------
996         // create the file chooser; not shown until "export" is chosen
997 
998         chooser = new JFileChooser ( ) ;
999         chooser.setFileSelectionMode (JFileChooser.FILES_AND_DIRECTORIES) ;
1000 
1001         gui_ready = true ;
1002         set_selected_label (true) ;
1003 
1004         //----------------------------------------------------------------------
1005         // start a thread to download any icons not present
1006 
1007         get_all_icons ( ) ;
1008     }
1009 
1010     //--------------------------------------------------------------------------
1011     // yes/no/unknown
1012     //--------------------------------------------------------------------------
1013 
yes_no(int k)1014     private String yes_no (int k)
1015     {
1016         if (k < 0)
1017         {
1018             return ("?") ;
1019         }
1020         else if (k == 0)
1021         {
1022             return ("no") ;
1023         }
1024         else
1025         {
1026             return ("yes") ;
1027         }
1028     }
1029 
1030     //--------------------------------------------------------------------------
1031     // ternary
1032     //--------------------------------------------------------------------------
1033 
ternary(String s)1034     private int ternary (String s)
1035     {
1036         long k = Long.parseLong (s) ;
1037         if (k < 0)
1038         {
1039             return (-1) ;
1040         }
1041         else if (k == 0)
1042         {
1043             return (0) ;
1044         }
1045         else
1046         {
1047             return (1) ;
1048         }
1049     }
1050 
1051     //--------------------------------------------------------------------------
1052     // read the ssstats file
1053     //--------------------------------------------------------------------------
1054 
load_ssstats( )1055     private Object [ ][ ] load_ssstats ( )
1056     {
1057         if (debug) System.out.println ("reading ssstats.csv file") ;
1058         Object [ ][ ] S = null ;
1059         int nmatrices = 0 ;
1060         in_reader = null ;
1061         try
1062         {
1063             // get the number of matrices in the ss Sparse Matrix Collection
1064             in_reader = new BufferedReader (new FileReader
1065                 (fix_name (ssstats))) ;
1066             nmatrices = Integer.parseInt (in_reader.readLine ( )) ;
1067             // skip past the creation date and time
1068             String ignore = in_reader.readLine ( ) ;
1069             // get the time of last download from the file modification time
1070             last_download =
1071                 new Date (new File (fix_name (ssstats)).lastModified ( )) ;
1072         }
1073         catch (Exception e)
1074         {
1075             // this is OK, for now, since we can try to download a new one
1076             if (debug) System.out.println ("reading ssstats.csv file failed") ;
1077             return (null) ;
1078         }
1079         try
1080         {
1081             // read the rest of the file
1082             S = new Object [nmatrices][13] ;
1083             for (int id = 1 ; id <= nmatrices ; id++)
1084             {
1085                 // split the tokens by comma
1086                 String [ ] r = (in_reader.readLine ( )).split (",") ;
1087                 S [id-1][0]  = id ;                             // id
1088                 S [id-1][1]  = r [0] ;                          // Group
1089                 S [id-1][2]  = r [1] ;                          // Name
1090                 S [id-1][3]  = Long.parseLong (r [2]) ;         // nrows
1091                 S [id-1][4]  = Long.parseLong (r [3]) ;         // ncols
1092                 // NOTE: r [4] = nnz is now ignored, and r [12] used instead
1093                 S [id-1][5]  = Long.parseLong (r [12]) ;        // nentries
1094 
1095                 S [id-1][6]  = ternary (r [5]) ;                // isReal
1096                 S [id-1][7]  = ternary (r [6]) ;                // isBinary
1097                 S [id-1][8]  = ternary (r [7]) ;                // isND
1098                 S [id-1][9]  = ternary (r [8]) ;                // posdef
1099 
1100                 S [id-1][10] = Double.parseDouble (r [9]) ;     // psym
1101                 S [id-1][11] = Double.parseDouble (r [10]) ;    // nsym
1102                 S [id-1][12] = r [11] ;                         // kind
1103             }
1104         }
1105         catch (Exception e)
1106         {
1107             // this is OK, for now, since we can try to download a new one
1108             if (debug) System.out.println ("reading ssstats.csv file failed") ;
1109             return (null) ;
1110         }
1111         finally
1112         {
1113             close_reader (in_reader) ;
1114         }
1115         return (S) ;
1116     }
1117 
1118     //--------------------------------------------------------------------------
1119     // tool tips for each column of the matrix table
1120     //--------------------------------------------------------------------------
1121 
1122     protected String [ ] matrix_column_tooltips =
1123     {
1124         // 0:select:
1125         "Click to select a matrix.  This is the only column you can edit.",
1126         "'x' if MAT format already downloaded",                 // 1:mat
1127         "'x' if MM format already downloaded",                  // 2:MM
1128         "'x' if RB format already downloaded",                  // 3:MM
1129         "matrix id",                                        // 4:id
1130         "matrix group (typically a person or organization)",// 5:Group
1131         "matrix name (full name is Group/Name)",            // 6:Name
1132         "# of rows in the matrix",                          // 7:nrows
1133         "# of columns in the matrix",                       // 8:ncols
1134         "# of entries in the matrix (both nonzeros and explicit zeros)",
1135                                                             // 9:nentries
1136         "if the matrix is real (not complex)",              // 10:isReal
1137         "if the matrix is binary",                          // 11:isBinary
1138         "if the matrix arises from a 2D/3D discretization", // 12:isND
1139         "if the matrix is symmetric positive definite",     // 13:posdef
1140         // 14:psym:
1141         "symmetry of pattern (0: none, 1: pattern(A)=pattern(A')",
1142         "symmetry of nonzero values (0: none, 1: A=A'",     // 15:nsym
1143         // 16:kind:
1144         "the matrix 'kind' is the problem domain from which it arises"
1145     } ;
1146 
1147     //--------------------------------------------------------------------------
1148     // control whether changes to the table cause updates to fire
1149     //--------------------------------------------------------------------------
1150 
1151     public boolean fire_status = true ;
1152 
fire_updates(boolean fire)1153     public void fire_updates (boolean fire)
1154     {
1155         fire_status = fire ;
1156         if (fire)
1157         {
1158             // touch the table to force a fire
1159             set_table_value (get_table_value (1, 0), 1, 0) ;
1160         }
1161     }
1162 
1163     //--------------------------------------------------------------------------
1164     // table of matrix statistics
1165     //--------------------------------------------------------------------------
1166 
1167     class matrix_Table_Model extends AbstractTableModel
1168     {
1169         private String [ ] columnNames =
1170             {
1171             "select", "mat", "MM", "RB",
1172             "id", "Group", "Name", "# rows", "# cols", "# entries", "real",
1173             "binary", "2D/3D", "posdef", "psym", "nsym", "kind" } ;
1174 
1175         private Object [ ][ ] data = null ;
1176 
getColumnCount( )1177         public int getColumnCount ( )
1178         {
1179             return (columnNames.length) ;
1180         }
1181 
getRowCount( )1182         public int getRowCount ( )
1183         {
1184             return (data.length) ;
1185         }
1186 
getColumnName(int col)1187         public String getColumnName (int col)
1188         {
1189             return (columnNames [col]) ;
1190         }
1191 
getValueAt(int row, int col)1192         public Object getValueAt (int row, int col)
1193         {
1194             return (data [row][col]) ;
1195         }
1196 
isCellEditable(int row, int col)1197         public boolean isCellEditable (int row, int col)
1198         {
1199             // only the "select" column is edittable
1200             return (col == 0) ;
1201         }
1202 
setValueAt(Object value, int row, int col)1203         public void setValueAt (Object value, int row, int col)
1204         {
1205             if (col == 0 && gui_ready && ((Boolean) data [row][0]) != value)
1206             {
1207                 if ((Boolean) value == false)
1208                 {
1209                     // changing from selected to unselected
1210                     nselected-- ;
1211                 }
1212                 else
1213                 {
1214                     // changing from unselected to selected
1215                     nselected++ ;
1216                 }
1217                 set_selected_label (download_Button.isEnabled ( )) ;
1218             }
1219             data [row][col] = value ;
1220             if (fire_status) fireTableDataChanged ( ) ;
1221         }
1222 
getColumnClass(int col)1223         public Class getColumnClass (int col)
1224         {
1225             return (getValueAt (0, col).getClass ( )) ;
1226         }
1227 
load_data(Object [ ][ ] newstats)1228         public void load_data (Object [ ][ ] newstats)
1229         {
1230             // load the matrix table with all matrix statistics
1231             data = new Object [newstats.length][17] ;
1232             nselected = 0 ;
1233             for (int i = 0 ; i < newstats.length ; i++)
1234             {
1235                 // i and j are in terms of the view, but the table is not yet
1236                 // sorted because it is not yet visible
1237                 data [i][0] = false ;   // select column is false
1238                 for (int j = 1 ; j < 4 ; j++)
1239                 {
1240                     // mat, MM, and RB, which can change later:
1241                     data [i][j] = "-" ;
1242                 }
1243                 for (int j = 0 ; j < 13 ; j++)
1244                 {
1245                     // matrix stats, which do not change:
1246                     // 4:id, 5:Group, 6:Name, 7:nrows, 8:ncols, 9:nentries,
1247                     // 10:isreal, 11:isBinary, 12:isND, 13:posdef, 14: psym,
1248                     // 15:nsym, 16:kind
1249                     if (j >= 6 && j <= 9)
1250                     {
1251                         int k = (Integer) newstats [i][j] ;
1252                         if (k < 0)
1253                         {
1254                             data [i][j+4] = " ?" ;
1255                         }
1256                         else if (k == 0)
1257                         {
1258                             data [i][j+4] = " no" ;
1259                         }
1260                         else
1261                         {
1262                             data [i][j+4] = " yes" ;
1263                         }
1264                     }
1265                     else
1266                     {
1267                         data [i][j+4] = newstats [i][j] ;
1268                     }
1269                 }
1270             }
1271             fireTableDataChanged ( ) ;
1272         }
1273     }
1274 
1275     //--------------------------------------------------------------------------
1276     // get a value from the matrix table
1277     //--------------------------------------------------------------------------
1278 
get_table_value(int id, int j)1279     private Object get_table_value (int id, int j)
1280     {
1281         // id is in the range 1 to Stats.length.  The model index is id-1.
1282         // Convert this to the row index of the view and then get the data.
1283         // j is in the range 0 to 16, and is the same in the view and the
1284         // model, since column rearranging is never done.
1285 
1286         int i = matrix_Table.convertRowIndexToView (id-1) ;
1287         return (matrix_Table.getValueAt (i, j)) ;
1288     }
1289 
1290     //--------------------------------------------------------------------------
1291     // set a value in the matrix table
1292     //--------------------------------------------------------------------------
1293 
set_table_value(Object value, int id, int j)1294     private void set_table_value (Object value, int id, int j)
1295     {
1296         // just like get_table_value, setting the data instead of getting it
1297 
1298         int i = matrix_Table.convertRowIndexToView (id-1) ;
1299         matrix_Table.setValueAt (value, i, j) ;
1300     }
1301 
1302     //--------------------------------------------------------------------------
1303     // get ids of highlighted matrices
1304     //--------------------------------------------------------------------------
1305 
get_highlighted_ids( )1306     private int [ ] get_highlighted_ids ( )
1307     {
1308         // return a list of highlighted matrix id's
1309 
1310         // get the highlighted row indices in the current view
1311         int [ ] highlighted = matrix_Table.getSelectedRows ( ) ;
1312         // convert the row view indices to matrix id's
1313         for (int k = 0 ; k < highlighted.length ; k++)
1314         {
1315             int i = highlighted [k] ;
1316             int id = 1 + matrix_Table.convertRowIndexToModel (i) ;
1317             highlighted [k] = id ;
1318         }
1319         return (highlighted) ;
1320     }
1321 
1322     //--------------------------------------------------------------------------
1323     // get ids of matrices selected for download
1324     //--------------------------------------------------------------------------
1325 
get_download_ids( )1326     private int [ ] get_download_ids ( )
1327     {
1328         // get the list of ids to download, in view order
1329         nselected = 0 ;
1330         for (int i = 0 ; i < Stats.length ; i++)
1331         {
1332             if ((Boolean) matrix_Table.getValueAt (i, 0))
1333             {
1334                 nselected++ ;
1335             }
1336         }
1337         int [ ] downloads = new int [nselected] ;
1338         int k = 0 ;
1339         for (int i = 0 ; i < Stats.length ; i++)
1340         {
1341             if ((Boolean) matrix_Table.getValueAt (i, 0))
1342             {
1343                 int id = 1 + matrix_Table.convertRowIndexToModel (i) ;
1344                 downloads [k++] = id ;
1345             }
1346         }
1347         return (downloads) ;
1348     }
1349 
1350     //--------------------------------------------------------------------------
1351     // set "Matrices selected:" label and download tool tip
1352     //--------------------------------------------------------------------------
1353 
set_selected_label(boolean enabled)1354     private void set_selected_label (boolean enabled)
1355     {
1356         if (gui_ready)
1357         {
1358             nselected_Label.setText
1359                 ("   Matrices selected: " + nselected + "   ") ;
1360             download_Button.setEnabled (enabled) ;
1361             if (enabled)
1362             {
1363                 if (nselected == 0)
1364                 {
1365                     download_Button.setToolTipText
1366                         ("No matrices have been selected for download") ;
1367                 }
1368                 else if (nselected == 1)
1369                 {
1370                     download_Button.setToolTipText
1371                         ("Click to download the single selected matrix") ;
1372                 }
1373                 else
1374                 {
1375                     download_Button.setToolTipText
1376                         ("Click to download the " + nselected +
1377                         " selected matrices") ;
1378                 }
1379             }
1380             else
1381             {
1382                 download_Button.setToolTipText ("Download in progress.") ;
1383             }
1384         }
1385     }
1386 
1387     //--------------------------------------------------------------------------
1388     // show matrix icon
1389     //--------------------------------------------------------------------------
1390 
show_highlighted_icon( )1391     private void show_highlighted_icon ( )
1392     {
1393         // show icon of last entry in the highlighted list
1394         int [ ] highlighted = get_highlighted_ids ( ) ;
1395         int n = highlighted.length ;
1396         if (n > 0)
1397         {
1398             int id = highlighted [n-1] ;
1399             String Group = (String) Stats [id-1][1] ;
1400             String Name  = (String) Stats [id-1][2] ;
1401             update_icon (Group + "/" + Name) ;
1402         }
1403     }
1404 
1405     //--------------------------------------------------------------------------
1406     // matrix table popup listener
1407     //--------------------------------------------------------------------------
1408 
1409     private class matrix_Table_PopupListener extends MouseAdapter
1410     {
1411         JPopupMenu pop ;
1412 
matrix_Table_PopupListener(JPopupMenu popupMenu)1413         matrix_Table_PopupListener (JPopupMenu popupMenu)
1414         {
1415             pop = popupMenu ;
1416         }
1417 
mousePressed(MouseEvent e)1418         public void mousePressed (MouseEvent e)
1419         {
1420             maybeShowPopup (e) ;
1421         }
1422 
mouseReleased(MouseEvent e)1423         public void mouseReleased (MouseEvent e)
1424         {
1425             maybeShowPopup (e) ;
1426         }
1427 
maybeShowPopup(MouseEvent e)1428         private void maybeShowPopup (MouseEvent e)
1429         {
1430             if (e.isPopupTrigger ( ))
1431             {
1432                 pop.show (e.getComponent ( ), e.getX ( ), e.getY ( )) ;
1433             }
1434         }
1435     }
1436 
1437     //--------------------------------------------------------------------------
1438     // matrix table row listener
1439     //--------------------------------------------------------------------------
1440 
1441     private class matrix_Table_RowListener implements ListSelectionListener
1442     {
valueChanged(ListSelectionEvent event)1443         public void valueChanged (ListSelectionEvent event)
1444         {
1445             if (event.getValueIsAdjusting ( ))
1446             {
1447                 return ;
1448             }
1449             show_highlighted_icon ( ) ;
1450         }
1451     }
1452 
1453     //--------------------------------------------------------------------------
1454     // FindKinds:  determine the set of all Problem kinds
1455     //--------------------------------------------------------------------------
1456 
FindKinds( )1457     private String [ ] FindKinds ( )
1458     {
1459         Set<String> KindSet = new TreeSet<String> ( ) ;
1460         KindSet.add (all_kinds) ;
1461         for (int id = 1 ; id <= Stats.length ; id++)
1462         {
1463             KindSet.add (SimplifyKind ((String) Stats [id-1][12])) ;
1464         }
1465         return ((String [ ]) KindSet.toArray (new String [0])) ;
1466     }
1467 
1468     //--------------------------------------------------------------------------
1469     // FindGroups:  determine the set of all groups
1470     //--------------------------------------------------------------------------
1471 
FindGroups( )1472     private String [ ] FindGroups ( )
1473     {
1474         Set<String> GroupSet = new TreeSet<String> ( ) ;
1475         GroupSet.add (all_groups) ;
1476         for (int id = 1 ; id <= Stats.length ; id++)
1477         {
1478             GroupSet.add ((String) Stats [id-1][1]) ;
1479         }
1480         return ((String [ ]) GroupSet.toArray (new String [0])) ;
1481     }
1482 
1483     //--------------------------------------------------------------------------
1484     // SimplifyKind: remove extranneous terms from a string
1485     //--------------------------------------------------------------------------
1486 
SimplifyKind(String kind)1487     private String SimplifyKind (String kind)
1488     {
1489         // remove terms from a matrix-kind string
1490         String result = null ;
1491         String [ ] token = kind.split (" ") ;
1492         for (int i = 0 ; i < token.length ; i++)
1493         {
1494             if (! (token [i].equals ("subsequent")
1495                 || token [i].equals ("sequence")
1496                 || token [i].equals ("problem")
1497                 || token [i].equals ("duplicate")))
1498             {
1499                 if (result == null)
1500                 {
1501                     result = token [i] ;
1502                 }
1503                 else
1504                 {
1505                     result = result + " " + token [i] ;
1506                 }
1507             }
1508         }
1509         return (result) ;
1510     }
1511 
1512     //--------------------------------------------------------------------------
1513     // CheckDir:  return a directory, creating it if it doesn't exist
1514     //--------------------------------------------------------------------------
1515 
CheckDir(String directory_name)1516     private File CheckDir (String directory_name)
1517     {
1518         File dir = new File (fix_name (directory_name)) ;
1519         if (!dir.isDirectory ( ))
1520         {
1521             dir.mkdirs ( ) ;
1522         }
1523         return (dir) ;
1524     }
1525 
1526     //--------------------------------------------------------------------------
1527     // CheckExistence: determine which files exist in the local file system
1528     //--------------------------------------------------------------------------
1529 
CheckExistence( )1530     private void CheckExistence ( )
1531     {
1532         // check the existence all matrices in all 3 formats
1533         fire_updates (false) ;
1534         for (int id = 1 ; id <= Stats.length ; id++)
1535         {
1536             CheckExistence (id) ;
1537         }
1538         fire_updates (true) ;
1539     }
1540 
CheckExistence(int id)1541     private boolean [ ] CheckExistence (int id)
1542     {
1543         // check the existence of a single file (in all 3 formats)
1544         boolean [ ] exists = new boolean [4] ;
1545         boolean [ ] etable = new boolean [3] ;
1546 
1547         String Group = (String) Stats [id-1][1] ;
1548         String Name  = (String) Stats [id-1][2] ;
1549 
1550         for (int j = 0 ; j < 3 ; j++)
1551         {
1552             etable [j] = (((String) get_table_value (id, j+1)).charAt (0) == 'x') ;
1553         }
1554 
1555         for (int j = 0 ; j < 4 ; j++)
1556         {
1557             exists [j] = false ;
1558         }
1559 
1560         // check for mat/HB/west0067.mat
1561         File G = new File (mat, Group) ;
1562         if (G.isDirectory ( ) && (new File (G, Name + ".mat")).exists ( ))
1563         {
1564             exists [0] = true ;
1565         }
1566 
1567         // check for MM/HB/west0067.tar.gz
1568         G = new File (MM, Group) ;
1569         if (G.isDirectory ( ) && (new File (G, Name + ".tar.gz")).exists ( ))
1570         {
1571             exists [1] = true ;
1572         }
1573 
1574         // check for MM/HB/west0067.tar.gz
1575         G = new File (RB, Group) ;
1576         if (G.isDirectory ( ) && (new File (G, Name + ".tar.gz")).exists ( ))
1577         {
1578             exists [2] = true ;
1579         }
1580 
1581         // check for files/HB/west0067.png
1582         G = new File (iconDir, Group) ;
1583         if (G.isDirectory ( ) && (new File (G, Name + ".png")).exists ( ))
1584         {
1585             exists [3] = true ;
1586         }
1587 
1588         // update the matrix table (mat, MM, and RB columns)
1589         for (int j = 0 ; j < 3 ; j++)
1590         {
1591             if (etable [j] != exists [j])
1592             {
1593                 // only update the table if the existence status has changed
1594                 set_table_value (exists [j] ? "x" : "-", id, j+1) ;
1595             }
1596         }
1597         return (exists) ;
1598     }
1599 
1600     //-------------------------------------------------------------------------
1601     // get long from JTextField
1602     //-------------------------------------------------------------------------
1603 
getLong(JTextField tfield, long Default)1604     private long getLong (JTextField tfield, long Default)
1605     {
1606         String s = tfield.getText ( ) ;
1607         long result = Default ;
1608         if (s.length ( ) > 0)
1609         {
1610             try
1611             {
1612                 result = Long.parseLong (s) ;
1613             }
1614             catch (Exception e)
1615             {
1616             }
1617         }
1618         return (result) ;
1619     }
1620 
1621     //-------------------------------------------------------------------------
1622     // get double from JTextField
1623     //-------------------------------------------------------------------------
1624 
getDouble(JTextField tfield, double Default)1625     private double getDouble (JTextField tfield, double Default)
1626     {
1627         String s = tfield.getText ( ) ;
1628         double result = Default ;
1629         if (s.length ( ) > 0)
1630         {
1631             try
1632             {
1633                 result = Double.parseDouble (s) ;
1634             }
1635             catch (Exception e)
1636             {
1637             }
1638         }
1639         return (result) ;
1640     }
1641 
1642     //-------------------------------------------------------------------------
1643     // change to a wait cursor
1644     //-------------------------------------------------------------------------
1645 
please_wait( )1646     private void please_wait ( )
1647     {
1648         this.setCursor (Cursor.getPredefinedCursor (Cursor.WAIT_CURSOR)) ;
1649     }
1650 
1651     //-------------------------------------------------------------------------
1652     // change to a normal cursor
1653     //-------------------------------------------------------------------------
1654 
the_long_wait_is_over( )1655     private void the_long_wait_is_over ( )
1656     {
1657         this.setCursor (Cursor.getDefaultCursor ( )) ;
1658     }
1659 
1660     //-------------------------------------------------------------------------
1661     // make or clear a selection
1662     //-------------------------------------------------------------------------
1663 
make_selection(boolean action)1664     private void make_selection (boolean action)
1665     {
1666         // set selections according to controls
1667         please_wait ( ) ;
1668         fire_updates (false) ;
1669 
1670         long minrow = getLong (minrow_Field, 0) ;
1671         long maxrow = getLong (maxrow_Field, INF) ;
1672 
1673         long mincol = getLong (mincol_Field, 0) ;
1674         long maxcol = getLong (maxcol_Field, INF) ;
1675 
1676         long minnentries = getLong (minnentries_Field, 0) ;
1677         long maxnentries = getLong (maxnentries_Field, INF) ;
1678 
1679         double minpsym = getDouble (minpsym_Field, 0) ;
1680         double maxpsym = getDouble (maxpsym_Field, 1.0) ;
1681 
1682         double minnsym = getDouble (minnsym_Field, 0) ;
1683         double maxnsym = getDouble (maxnsym_Field, 1.0) ;
1684 
1685         boolean shape_square = shape_square_Button.isSelected ( ) ;
1686         boolean shape_rect   = shape_rect_Button.isSelected ( ) ;
1687         boolean shape_either = shape_either_Button.isSelected ( ) ;
1688 
1689         boolean posdef_yes    = posdef_yes_Button.isSelected ( ) ;
1690         boolean posdef_no     = posdef_no_Button.isSelected ( ) ;
1691         boolean posdef_either = posdef_either_Button.isSelected ( ) ;
1692 
1693         boolean nd_yes    = nd_yes_Button.isSelected ( ) ;
1694         boolean nd_no     = nd_no_Button.isSelected ( ) ;
1695         boolean nd_either = nd_either_Button.isSelected ( ) ;
1696 
1697         boolean real_yes    = real_yes_Button.isSelected ( ) ;
1698         boolean real_no     = real_no_Button.isSelected ( ) ;
1699         boolean real_either = real_either_Button.isSelected ( ) ;
1700 
1701         // create HashSet for the selected groups
1702         Set<String> Gset = null ;
1703         Object [ ] Gsel = Group_List.getSelectedValuesList ( ).toArray ( ) ;
1704         int ngroups = Gsel.length ;
1705         if (ngroups > 0)
1706         {
1707             for (int i = 0 ; i < ngroups ; i++)
1708             {
1709                 if (((String) Gsel [i]).equals (all_groups)) ngroups = 0 ;
1710             }
1711             Gset = new HashSet<String> ( ) ;
1712             for (int i = 0 ; i < ngroups ; i++)
1713             {
1714                 Gset.add ((String) Gsel [i]) ;
1715                 if (debug) System.out.println ("Group: " + (String) Gsel [i]) ;
1716             }
1717         }
1718 
1719         // create HashSet for the selected kinds
1720         Set<String> Kset = null ;
1721         Object [ ] Ksel = Kind_List.getSelectedValuesList ( ).toArray ( ) ;
1722         int nkinds = Ksel.length ;
1723         if (nkinds > 0)
1724         {
1725             for (int i = 0 ; i < nkinds ; i++)
1726             {
1727                 if (((String) Ksel [i]).equals (all_kinds)) nkinds = 0 ;
1728             }
1729             Kset = new HashSet<String> ( ) ;
1730             for (int i = 0 ; i < nkinds ; i++)
1731             {
1732                 Kset.add ((String) Ksel [i]) ;
1733                 if (debug) System.out.println ("Kind: " + ((String) Ksel [i])) ;
1734             }
1735         }
1736 
1737         for (int id = 1 ; id <= Stats.length ; id++)
1738         {
1739 
1740             // look at the matrix properties to see if it fits the selection
1741             long nrows = (Long) Stats [id-1][3] ;
1742             long ncols = (Long) Stats [id-1][4] ;
1743             long nentries = (Long) Stats [id-1][5] ;
1744 
1745             int isReal   = (Integer) Stats [id-1][6] ;
1746             int isBinary = (Integer) Stats [id-1][7] ;
1747             int isND     = (Integer) Stats [id-1][8] ;
1748             int posdef   = (Integer) Stats [id-1][9] ;
1749 
1750             double psym = (Double) Stats [id-1][10] ;
1751             double nsym = (Double) Stats [id-1][11] ;
1752 
1753             boolean choose_group = true ;
1754             if (ngroups > 0)
1755             {
1756                 String group = (String) Stats [id-1][1] ;
1757                 choose_group = Gset.contains (group) ;
1758             }
1759 
1760             boolean choose_kind = true ;
1761             if (nkinds > 0)
1762             {
1763                 String kind = SimplifyKind ((String) Stats [id-1][12]) ;
1764                 choose_kind = Kset.contains (kind) ;
1765             }
1766 
1767             if ((minrow <= nrows && nrows <= maxrow) &&
1768                 (mincol <= ncols && ncols <= maxcol) &&
1769                 (minnentries <= nentries && nentries <= maxnentries) &&
1770                 (minpsym <= psym && psym <= maxpsym) &&
1771                 (minnsym <= nsym && nsym <= maxnsym) &&
1772                 (posdef_either ||
1773                     (posdef_yes && posdef == 1) ||
1774                     (posdef_no && posdef == 0)) &&
1775                 (nd_either ||
1776                     (nd_yes && isND == 1) ||
1777                     (nd_no && isND == 0)) &&
1778                 (real_either ||
1779                     (real_yes && isReal == 1) ||
1780                     (real_no && isReal == 0)) &&
1781                 (shape_either ||
1782                     (shape_square && nrows == ncols) ||
1783                     (shape_rect && nrows != ncols)) &&
1784                 choose_group && choose_kind)
1785             {
1786                 // change the selection box for this matrix id
1787                 set_table_value (action, id, 0) ;
1788             }
1789         }
1790         fire_updates (true) ;
1791         progress1_Bar.setValue (0) ;
1792         progress2_Bar.setValue (0) ;
1793         the_long_wait_is_over ( ) ;
1794     }
1795 
1796     //-------------------------------------------------------------------------
1797     // reset button
1798     //-------------------------------------------------------------------------
1799 
reset_Button_action(ActionEvent e)1800     private void reset_Button_action (ActionEvent e)
1801     {
1802         // reset the selection criteria to the defaults
1803         minrow_Field.setText ("") ;
1804         maxrow_Field.setText ("") ;
1805 
1806         mincol_Field.setText ("") ;
1807         maxcol_Field.setText ("") ;
1808 
1809         minnentries_Field.setText ("") ;
1810         maxnentries_Field.setText ("") ;
1811 
1812         minpsym_Field.setText ("0.0") ;
1813         maxpsym_Field.setText ("1.0") ;
1814 
1815         minnsym_Field.setText ("0.0") ;
1816         maxnsym_Field.setText ("1.0") ;
1817 
1818         shape_either_Button.setSelected (true) ;
1819         posdef_either_Button.setSelected (true) ;
1820         nd_either_Button.setSelected (true) ;
1821         real_either_Button.setSelected (true) ;
1822 
1823         Group_List.clearSelection ( ) ;
1824         Kind_List.clearSelection ( ) ;
1825 
1826         progress1_Bar.setValue (0) ;
1827         progress2_Bar.setValue (0) ;
1828     }
1829 
1830     //-------------------------------------------------------------------------
1831     // clear button
1832     //-------------------------------------------------------------------------
1833 
clear_Button_action(ActionEvent e)1834     private void clear_Button_action (ActionEvent e)
1835     {
1836         // set selections according to controls
1837         please_wait ( ) ;
1838         fire_updates (false) ;
1839 
1840         for (int id = 1 ; id <= Stats.length ; id++)
1841         {
1842             // clear the selection box for this matrix id
1843             set_table_value (false, id, 0) ;
1844         }
1845         fire_updates (true) ;
1846         progress1_Bar.setValue (0) ;
1847         progress2_Bar.setValue (0) ;
1848         the_long_wait_is_over ( ) ;
1849     }
1850 
1851     //-------------------------------------------------------------------------
1852     // select popup menu item
1853     //-------------------------------------------------------------------------
1854 
popup_action(ActionEvent e, boolean action)1855     private void popup_action (ActionEvent e, boolean action)
1856     {
1857         // select or deselect the highlight matrices
1858         please_wait ( ) ;
1859         int [ ] highlighted = get_highlighted_ids ( ) ;
1860         int n = highlighted.length ;
1861         for (int k = 0 ; k < n ; k++)
1862         {
1863             set_table_value (action, highlighted [k], 0) ;
1864         }
1865         the_long_wait_is_over ( ) ;
1866     }
1867 
1868     //-------------------------------------------------------------------------
1869     // export popup menu item
1870     //-------------------------------------------------------------------------
1871 
export_list_action(ActionEvent e, boolean csv)1872     private void export_list_action (ActionEvent e, boolean csv)
1873     {
1874         // export the list in the order of the current view
1875         if (chooser.showSaveDialog (ssgui.this) == JFileChooser.APPROVE_OPTION)
1876         {
1877             please_wait ( ) ;
1878             print_out = null ;
1879             try
1880             {
1881                 print_out = new PrintWriter (chooser.getSelectedFile ( )) ;
1882                 int [ ] ids = get_download_ids ( ) ;
1883                 int n = ids.length ;
1884 
1885                 // print the header
1886                 if (csv)
1887                 {
1888                     print_out.println ("mat, MM, RB, id, Group, Name, rows, " +
1889                         "cols, entries, real, binary, 2D/3D, posdef, psym, " +
1890                         "nsym, kind") ;
1891                 }
1892                 else
1893                 {
1894                     print_out.println ("%% Matrices selected from ssgui:") ;
1895                     print_out.println ("% Example usage:") ;
1896                     print_out.println ("% for k = 1:length(ids)") ;
1897                     print_out.println ("%    Problem = ssget (ids (k))") ;
1898                     print_out.println ("% end") ;
1899                     print_out.println ("ids = [")  ;
1900                 }
1901 
1902                 for (int k = 0 ; k < n ; k++)
1903                 {
1904                     // get the matrix id and stats
1905                     int id = ids [k] ;
1906                     boolean [ ] exists = CheckExistence (id) ;
1907                     String Group       = (String)  Stats [id-1][1] ;
1908                     String Name        = (String)  Stats [id-1][2] ;
1909                     long nrows         = (Long)    Stats [id-1][3] ;
1910                     long ncols         = (Long)    Stats [id-1][4] ;
1911                     long nentries      = (Long)    Stats [id-1][5] ;
1912                     int isReal         = (Integer) Stats [id-1][6] ;
1913                     int isBinary       = (Integer) Stats [id-1][7] ;
1914                     int isND           = (Integer) Stats [id-1][8] ;
1915                     int posdef         = (Integer) Stats [id-1][9] ;
1916                     double psym        = (Double)  Stats [id-1][10] ;
1917                     double nsym        = (Double)  Stats [id-1][11] ;
1918                     String kind        = (String)  Stats [id-1][12] ;
1919 
1920                     if (csv)
1921                     {
1922                         // print the matrix stats in a single CSV line of text
1923                         print_out.println (
1924                             exists [0] + ", " + exists [1] + ", " +
1925                             exists [2] + ", " + id + ", " + Group + ", " +
1926                             Name + ", " + nrows + ", " + ncols + ", " +
1927                             nentries + ", " + isReal + ", " + isBinary + ", " +
1928                             isND + ", " + posdef + ", " + psym + ", " +
1929                             nsym + ", " + kind) ;
1930                     }
1931                     else
1932                     {
1933                         // print the matrix id, with a comment for the name
1934                         print_out.println (id + " % " + Group + "/" + Name) ;
1935                     }
1936                 }
1937                 if (!csv)
1938                 {
1939                     print_out.println ("] ;")  ;
1940                 }
1941             }
1942             catch (Exception err)
1943             {
1944                 // display warning dialog
1945                 JOptionPane.showMessageDialog (this, "Export failed.",
1946                     "Warning", JOptionPane.WARNING_MESSAGE) ;
1947             }
1948             finally
1949             {
1950                 close_printer_stream (print_out) ;
1951             }
1952             the_long_wait_is_over ( ) ;
1953         }
1954     }
1955 
1956     //-------------------------------------------------------------------------
1957     // help button
1958     //-------------------------------------------------------------------------
1959 
help_Button_action(ActionEvent e)1960     private void help_Button_action (ActionEvent e)
1961     {
1962         // create the Help window
1963         please_wait ( ) ;
1964         JFrame help_Frame = new JFrame ("Help: SuiteSparse Matrix Collection") ;
1965 
1966         // open the HTML help file and put it in an editor pane
1967         JEditorPane editorPane = new JEditorPane ( ) ;
1968         editorPane.setEditable (false) ;
1969         URL helpURL = ssgui.class.getResource ("sshelp.html") ;
1970         if (helpURL != null)
1971         {
1972             try
1973             {
1974                 editorPane.setPage (helpURL) ;
1975             }
1976             catch (IOException error)
1977             {
1978                 // display warning dialog
1979                 JOptionPane.showMessageDialog (this,
1980                     "Sorry, Help document sshelp.html not found.",
1981                     "Warning", JOptionPane.WARNING_MESSAGE) ;
1982             }
1983         }
1984 
1985         // Put the editor pane in a scroll pane.
1986         JScrollPane editorScrollPane = new JScrollPane (editorPane) ;
1987 
1988         // Add the scroll pane to the Help window
1989         help_Frame.getContentPane ( ).add (editorScrollPane) ;
1990         help_Frame.setSize (800,600) ;
1991         help_Frame.setVisible (true) ;
1992 
1993         the_long_wait_is_over ( ) ;
1994     }
1995 
1996     //-------------------------------------------------------------------------
1997     // get the icon filename
1998     //-------------------------------------------------------------------------
1999 
icon_file(String fullname)2000     private String icon_file (String fullname)
2001     {
2002         return ("files/" + fullname + ".png") ;
2003     }
2004 
2005     //-------------------------------------------------------------------------
2006     // update the icon
2007     //-------------------------------------------------------------------------
2008 
update_icon(String fullname)2009     private void update_icon (String fullname)
2010     {
2011         // fullname is of the form Group/Name (HB/west0479, for example)
2012         icon_Label.setText (fullname) ;
2013         ImageIcon icon = new ImageIcon (fix_name (icon_file (fullname))) ;
2014         if (icon.getIconWidth ( ) < 0)
2015         {
2016             // icon image failed to load; get the image from the web
2017             icon = new ImageIcon (get_url (sssite +"/"+ icon_file (fullname))) ;
2018         }
2019         icon_Label.setIcon (icon) ;
2020     }
2021 
2022     //--------------------------------------------------------------------------
2023     // cancel button
2024     //--------------------------------------------------------------------------
2025 
cancel_Button_action(ActionEvent e)2026     private void cancel_Button_action (ActionEvent e)
2027     {
2028         if (downloading && !cancel)
2029         {
2030             cancel = true ;
2031             cancel_Button.setEnabled (false) ;
2032             cancel_Button.setToolTipText ("canceling...") ;
2033         }
2034     }
2035 
2036     //-------------------------------------------------------------------------
2037     // get all icons
2038     //-------------------------------------------------------------------------
2039 
get_all_icons( )2040     private void get_all_icons ( )
2041     {
2042         // get all icons
2043         start_download_thread (0) ;
2044     }
2045 
2046     //-------------------------------------------------------------------------
2047     // download button
2048     //-------------------------------------------------------------------------
2049 
download_Button_action(ActionEvent e)2050     private void download_Button_action (ActionEvent e)
2051     {
2052         // get the selected matrices
2053         start_download_thread (2) ;
2054     }
2055 
2056     //-------------------------------------------------------------------------
2057     // start the downloader thread
2058     //-------------------------------------------------------------------------
2059 
start_download_thread(int what)2060     private void start_download_thread (int what)
2061     {
2062         if (!downloading)
2063         {
2064             // only allow one active download at a time
2065             downloading = true ;
2066             cancel = false ;
2067 
2068             if (gui_ready)
2069             {
2070                 cancel_Button.setEnabled (true) ;
2071                 cancel_Button.setToolTipText
2072                     ("Click to cancel the current download.") ;
2073             }
2074 
2075             if (what == 0)
2076             {
2077                 // get all the icons
2078                 get_icons = true ;
2079                 download_ids = null ;
2080             }
2081             else
2082             {
2083                 // download one or more matrices
2084                 get_icons = false ;
2085                 download_ids = get_download_ids ( ) ;
2086             }
2087             set_selected_label (false) ;
2088             // start the downloader thread
2089             ssdownload tt = new ssdownload ( ) ;
2090         }
2091     }
2092 
2093     //--------------------------------------------------------------------------
2094     // downloader thread
2095     //--------------------------------------------------------------------------
2096 
2097     private class ssdownload implements Runnable
2098     {
2099 
2100         // constructor starts the downloader thread
ssdownload( )2101         public ssdownload ( )
2102         {
2103             Thread thread = new Thread (this) ;
2104             thread.start ( ) ;
2105         }
2106 
2107         // thread.start calls the run method
run( )2108         public void run ( )
2109         {
2110 
2111             if (get_icons)
2112             {
2113                 // get all missing icons
2114                 progress1_Bar.setValue (1) ;
2115                 progress1_Bar.setMaximum (Stats.length) ;
2116                 icon_Label.setBorder (BorderFactory.createTitledBorder
2117                     ("checking for new matrix icons")) ;
2118                 for (int id = 1 ; !cancel && id <= Stats.length ; id++)
2119                 {
2120                     boolean [ ] exists = CheckExistence (id) ;
2121                     if (!exists [3])
2122                     {
2123                         icon_Label.setBorder (BorderFactory.createTitledBorder
2124                             ("downloading new matrix icons")) ;
2125                         String Group = (String) Stats [id-1][1] ;
2126                         String Name  = (String) Stats [id-1][2] ;
2127                         String fullname = Group + "/" + Name ;
2128                         CheckDir ("files/" + Group) ;
2129                         download_file (icon_file (fullname)) ;
2130                         update_icon (fullname) ;
2131                     }
2132                     progress1_Bar.setValue (id+2) ;
2133                 }
2134                 progress1_Bar.setValue (Stats.length) ;
2135                 icon_Label.setBorder (BorderFactory.createTitledBorder
2136                     ("matrix icon")) ;
2137             }
2138 
2139             if (download_ids != null && download_ids.length > 0)
2140             {
2141                 // download all selected matrices in the requested formats
2142 
2143                 // determine which formats to download
2144                 int barmax = download_ids.length + 2 ;
2145 
2146                 boolean format_mat = format_mat_Button.isSelected ( ) ;
2147                 boolean format_mm  = format_mm_Button.isSelected ( ) ;
2148                 boolean format_rb  = format_rb_Button.isSelected ( ) ;
2149 
2150                 // start the overall progress bar
2151                 progress1_Bar.setValue (1) ;
2152                 progress1_Bar.setMaximum (barmax) ;
2153 
2154                 // download all the files
2155                 for (int k = 0 ; !cancel && k < download_ids.length ; k++)
2156                 {
2157                     int id = download_ids [k] ;
2158 
2159                     // get matrxx
2160                     String Group = (String) Stats [id-1][1] ;
2161                     String Name  = (String) Stats [id-1][2] ;
2162                     String fullname = Group + "/" + Name ;
2163 
2164                     // recheck to see if the matrix exists in the 4 formats
2165                     boolean [ ] exists = CheckExistence (id) ;
2166 
2167                     if (!exists [3])
2168                     {
2169                         // always download the matrix icon if it doesn't exist
2170                         CheckDir ("files/" + Group) ;
2171                         download_file (icon_file (fullname)) ;
2172                         update_icon (fullname) ;
2173                     }
2174 
2175                     if (!exists [0] && format_mat)
2176                     {
2177                         // download the matrix in MATLAB format
2178                         update_icon (fullname) ;
2179                         CheckDir ("mat/" + Group) ;
2180                         download_file ("mat/" + fullname + ".mat") ;
2181                     }
2182 
2183                     if (!exists [1] && format_mm)
2184                     {
2185                         // download the matrix in Matrix Market format
2186                         update_icon (fullname) ;
2187                         CheckDir ("MM/" + Group) ;
2188                         download_file ("MM/" + fullname + ".tar.gz") ;
2189                     }
2190 
2191                     if (!exists [2] && format_rb)
2192                     {
2193                         // download the matrix in Rutherford/Boeing format
2194                         update_icon (fullname) ;
2195                         CheckDir ("RB/" + Group) ;
2196                         download_file ("RB/" + fullname + ".tar.gz") ;
2197                     }
2198 
2199                     progress1_Bar.setValue (k+2) ;
2200                 }
2201 
2202                 // update the mat/MM/RB check boxes
2203                 for (int k = 0 ; k < download_ids.length ; k++)
2204                 {
2205                     int id = download_ids [k] ;
2206                     CheckExistence (id) ;
2207                 }
2208 
2209                 // finish the overall progress bar
2210                 progress1_Bar.setValue (barmax) ;
2211             }
2212 
2213             cancel_Button.setEnabled (false) ;
2214             cancel_Button.setToolTipText ("No downloads in progress.") ;
2215 
2216             set_selected_label (true) ;
2217             cancel = false ;
2218             downloading = false ;
2219         }
2220     }
2221 
2222     //--------------------------------------------------------------------------
2223     // get a URL
2224     //--------------------------------------------------------------------------
2225 
get_url(String urlstring)2226     private URL get_url (String urlstring)
2227     {
2228         try
2229         {
2230             return (new URL (urlstring)) ;
2231         }
2232         catch (MalformedURLException e)
2233         {
2234             // display warning dialog
2235             JOptionPane.showMessageDialog (this, "Invalid URL: "
2236                 + urlstring, "Warning", JOptionPane.WARNING_MESSAGE) ;
2237             return (null) ;
2238         }
2239     }
2240 
2241     //--------------------------------------------------------------------------
2242     // download a file
2243     //--------------------------------------------------------------------------
2244 
download_file(String filename)2245     private void download_file (String filename)
2246     {
2247         boolean ok = true ;
2248         if (cancel) return ;
2249         String urlstring = sssite + "/" + filename ;
2250         if (debug) System.out.println ("downloading: " + urlstring) ;
2251 
2252         // create the URL
2253         URL url = get_url (urlstring) ;
2254         if (url == null) return ;
2255 
2256         // download the file
2257         url_in = null ;
2258         ftemp_out = null ;
2259         ftemp_name = filename + "_IN_PROGREss" ;
2260         int barmax = 1 ;
2261 
2262         try
2263         {
2264             // Follow redirects manually
2265             int max_redirects = 5;
2266             HttpURLConnection conn = (HttpURLConnection) url.openConnection();
2267 
2268             for(int redirect_count = 0; redirect_count < max_redirects; redirect_count++)
2269             {
2270                 int status = conn.getResponseCode();
2271                 if (status >= 300 && status <= 308)
2272                 {
2273                     // Redirecting
2274                     String loc = conn.getHeaderField("Location");
2275                     url = new URL(loc);
2276                     conn = (HttpURLConnection) url.openConnection();
2277                 }
2278                 else
2279                 {
2280                     break;
2281                 }
2282             }
2283 
2284             // determine the file size (fails for files > 2GB)
2285             int len = conn.getContentLength();
2286 
2287             // start the progress bar
2288             if (gui_ready)
2289             {
2290                 if (len < 0)
2291                 {
2292                     progress2_Bar.setIndeterminate (true) ;
2293                     progress_size_Label.setText ("") ;
2294                 }
2295                 else
2296                 {
2297                     progress2_Bar.setValue (0) ;
2298                     // display the filesize to the right of the progress bar
2299                     if (len < M)
2300                     {
2301                         barmax = 1 + len / K ;
2302                         progress_size_Label.setText (((len+K/2) / K) + " KB") ;
2303                     }
2304                     else
2305                     {
2306                         barmax = 1 + len / M ;
2307                         progress_size_Label.setText (((len+M/2) / M) + " MB") ;
2308                     }
2309                 }
2310                 progress2_Bar.setMaximum (barmax) ;
2311             }
2312 
2313             // open the source and destination files
2314             //url_in = new BufferedInputStream (url.openStream ( )) ;
2315             url_in = new BufferedInputStream (conn.getInputStream()) ;
2316             ftemp_out = new BufferedOutputStream (new FileOutputStream
2317                 (fix_name (ftemp_name)), buffersize) ;
2318 
2319             // transfer the data
2320             byte buffer [ ] = new byte [buffersize] ;
2321             long bytes_read = 0 ;
2322             int count = 0 ;
2323             while (!cancel && (count = url_in.read (buffer, 0, buffersize)) >= 0)
2324             {
2325                 if (ftemp_out != null) ftemp_out.write (buffer, 0, count) ;
2326                 bytes_read += count ;
2327                 if (gui_ready && len > 0)
2328                 {
2329                     if (len < M)
2330                     {
2331                         progress2_Bar.setValue ((int) (bytes_read / K)) ;
2332                     }
2333                     else
2334                     {
2335                         progress2_Bar.setValue ((int) (bytes_read / M)) ;
2336                     }
2337                 }
2338             }
2339         }
2340         catch (Exception e)
2341         {
2342             if (debug)
2343             {
2344                 System.out.println("Download failed: " + urlstring);
2345             }
2346             ok = false ;
2347         }
2348 
2349         if (gui_ready)
2350         {
2351             progress2_Bar.setIndeterminate (false) ;
2352             progress2_Bar.setValue (barmax) ;
2353             progress_size_Label.setText ("") ;
2354         }
2355 
2356         // wrap-up
2357         if (ok && !cancel)
2358         {
2359             // success:  rename the temp file to the permanent filename
2360             cleanup (false) ;
2361             File fsrc = new File (fix_name (ftemp_name)) ;
2362             File fdst = new File (fix_name (filename)) ;
2363             fsrc.renameTo (fdst) ;
2364         }
2365         else
2366         {
2367             // cancelled, or something failed:  delete the files if they exist
2368             cleanup (true) ;
2369         }
2370     }
2371 
2372     //--------------------------------------------------------------------------
2373     // download the latest matrix stats
2374     //--------------------------------------------------------------------------
2375 
download_matrix_stats( )2376     private Object [ ][ ] download_matrix_stats ( )
2377     {
2378         download_file (ssindex) ;       // download files/ss_index.mat
2379         download_file (ssstats) ;       // download files/ssstats.csv
2380         return (load_ssstats ( )) ;     // load the ssstats.csv file
2381     }
2382 
2383     //--------------------------------------------------------------------------
2384     // prepend the ss rchive directory and replace '/' with the file separator
2385     //--------------------------------------------------------------------------
2386 
fix_name(String s)2387     private static String fix_name (String s)
2388     {
2389         // file separator is '/' on Unix/Solaris/Linux/Mac, and '\' on Windows
2390         String r = ssarchive ;
2391         if (s != null)
2392         {
2393             r = r + s ;
2394         }
2395         return (r.replace ('/', File.separatorChar)) ;
2396     }
2397 
2398     //--------------------------------------------------------------------------
2399     // close an output stream
2400     //--------------------------------------------------------------------------
2401 
close_output(OutputStream out)2402     private static void close_output (OutputStream out)
2403     {
2404         try
2405         {
2406             if (out != null) out.close ( ) ;
2407         }
2408         catch (IOException e)
2409         {
2410         }
2411     }
2412 
2413     //--------------------------------------------------------------------------
2414     // close an input stream
2415     //--------------------------------------------------------------------------
2416 
close_reader(Reader in)2417     private static void close_reader (Reader in)
2418     {
2419         try
2420         {
2421             if (in != null) in.close ( ) ;
2422         }
2423         catch (IOException e)
2424         {
2425         }
2426     }
2427 
2428     //--------------------------------------------------------------------------
2429     // close a printer stream
2430     //--------------------------------------------------------------------------
2431 
close_printer_stream(PrintWriter out)2432     private static void close_printer_stream (PrintWriter out)
2433     {
2434         if (out != null) out.close ( ) ;
2435     }
2436 
2437     //--------------------------------------------------------------------------
2438     // delete a file
2439     //--------------------------------------------------------------------------
2440 
delete_file(String filename)2441     private static void delete_file (String filename)
2442     {
2443         if (filename != null)
2444         {
2445             File ff = new File (fix_name (filename)) ;
2446             if (ff.exists ( )) ff.delete ( ) ;
2447         }
2448     }
2449 
2450     //--------------------------------------------------------------------------
2451     // cleanup
2452     //--------------------------------------------------------------------------
2453 
cleanup(boolean delete)2454     private static void cleanup (boolean delete)
2455     {
2456         // close input streams, if any
2457         try
2458         {
2459             if (url_in != null) url_in.close ( ) ;
2460         }
2461         catch (IOException e)
2462         {
2463         }
2464         url_in = null ;
2465 
2466         // close temporary file
2467         close_output (ftemp_out) ;
2468         ftemp_out = null ;
2469 
2470         if (delete)
2471         {
2472             // delete temporary file
2473             delete_file (ftemp_name) ;
2474             ftemp_name = null ;
2475         }
2476 
2477         // close the printer stream, if any
2478         close_printer_stream (print_out) ;
2479 
2480         // close the reader stream, if any
2481         close_reader (in_reader) ;
2482     }
2483 
2484     //--------------------------------------------------------------------------
2485     // main method
2486     //--------------------------------------------------------------------------
2487 
main(String args [ ])2488     public static void main (String args [ ])
2489     {
2490         // register a shutdown hook
2491         Runtime.getRuntime ( ).addShutdownHook
2492         (
2493             new Thread ( )
2494             {
2495                 public void run ( )
2496                 {
2497                     // delete any temporary files when the ssgui shuts down,
2498                     // and close any files
2499                     cleanup (true) ;
2500                 }
2501             }
2502         ) ;
2503 
2504         // start the GUI in its own thread
2505         EventQueue.invokeLater
2506         (
2507             new Runnable ( )
2508             {
2509                 public void run ( )
2510                 {
2511                     new ssgui ( ).setVisible (true) ;
2512                 }
2513             }
2514         ) ;
2515     }
2516 }
2517