Merge branch 'develop' into features/JAL-2360colourSchemeApplicability
[jalview.git] / src / jalview / gui / Preferences.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import static jalview.util.UrlConstants.DB_ACCESSION;
24 import static jalview.util.UrlConstants.EMBLEBI_STRING;
25 import static jalview.util.UrlConstants.SEQUENCE_ID;
26 import static jalview.util.UrlConstants.SRS_STRING;
27
28 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
29 import jalview.bin.Cache;
30 import jalview.gui.Help.HelpId;
31 import jalview.gui.StructureViewer.ViewerType;
32 import jalview.io.FileFormatI;
33 import jalview.io.JalviewFileChooser;
34 import jalview.io.JalviewFileView;
35 import jalview.jbgui.GPreferences;
36 import jalview.jbgui.GSequenceLink;
37 import jalview.schemes.ColourSchemeI;
38 import jalview.schemes.ColourSchemes;
39 import jalview.schemes.ResidueColourScheme;
40 import jalview.util.MessageManager;
41 import jalview.util.Platform;
42 import jalview.ws.sifts.SiftsSettings;
43
44 import java.awt.BorderLayout;
45 import java.awt.Color;
46 import java.awt.Dimension;
47 import java.awt.Font;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.MouseEvent;
51 import java.io.File;
52 import java.util.ArrayList;
53 import java.util.List;
54 import java.util.StringTokenizer;
55 import java.util.Vector;
56
57 import javax.help.HelpSetException;
58 import javax.swing.JColorChooser;
59 import javax.swing.JFileChooser;
60 import javax.swing.JInternalFrame;
61 import javax.swing.JPanel;
62
63 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
64
65 /**
66  * DOCUMENT ME!
67  * 
68  * @author $author$
69  * @version $Revision$
70  */
71 public class Preferences extends GPreferences
72 {
73   public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
74
75   public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA";
76
77   public static final String DEFAULT_COLOUR = "DEFAULT_COLOUR";
78
79   public static final String DEFAULT_COLOUR_PROT = "DEFAULT_COLOUR_PROT";
80
81   public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC";
82
83   public static final String ADD_TEMPFACT_ANN = "ADD_TEMPFACT_ANN";
84
85   public static final String ADD_SS_ANN = "ADD_SS_ANN";
86
87   public static final String USE_RNAVIEW = "USE_RNAVIEW";
88
89   public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB";
90
91   public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY";
92
93   public static final String CHIMERA_PATH = "CHIMERA_PATH";
94
95   public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS";
96
97   public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
98
99   private static final int MIN_FONT_SIZE = 1;
100
101   private static final int MAX_FONT_SIZE = 30;
102
103   /**
104    * Holds name and link separated with | character. Sequence ID must be
105    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
106    */
107   public static Vector<String> sequenceURLLinks;
108
109   /**
110    * Holds name and link separated with | character. Sequence IDS and Sequences
111    * must be $SEQUENCEIDS$ or $SEQUENCEIDS=/.possible | chars ./=$ and
112    * $SEQUENCES$ or $SEQUENCES=/.possible | chars ./=$ and separation character
113    * for first and second token specified after a pipe character at end |,|.
114    * (TODO: proper escape for using | to separate ids or sequences
115    */
116
117   public static List<String> groupURLLinks;
118   static
119   {
120     String string = Cache.getDefault("SEQUENCE_LINKS", EMBLEBI_STRING);
121     sequenceURLLinks = new Vector<String>();
122
123     try
124     {
125       StringTokenizer st = new StringTokenizer(string, "|");
126       while (st.hasMoreElements())
127       {
128         String name = st.nextToken();
129         String url = st.nextToken();
130         // check for '|' within a regex
131         int rxstart = url.indexOf("$" + DB_ACCESSION + "$");
132         if (rxstart == -1)
133         {
134           rxstart = url.indexOf("$" + SEQUENCE_ID + "$");
135         }
136         while (rxstart == -1 && url.indexOf("/=$") == -1)
137         {
138           url = url + "|" + st.nextToken();
139         }
140         sequenceURLLinks.addElement(name + "|" + url);
141       }
142     } catch (Exception ex)
143     {
144       System.out.println(ex + "\nError parsing sequence links");
145     }
146     {
147       // upgrade old SRS link
148       int srsPos = sequenceURLLinks.indexOf(SRS_STRING);
149       if (srsPos > -1)
150       {
151         sequenceURLLinks.setElementAt(EMBLEBI_STRING, srsPos);
152       }
153     }
154
155     /**
156      * TODO: reformulate groupURL encoding so two or more can be stored in the
157      * .properties file as '|' separated strings
158      */
159
160     groupURLLinks = new ArrayList<String>();
161   }
162
163   Vector<String> nameLinks, urlLinks;
164
165   JInternalFrame frame;
166
167   DasSourceBrowser dasSource;
168
169   private WsPreferences wsPrefs;
170
171   private OptionsParam promptEachTimeOpt = new OptionsParam(
172           MessageManager.getString("label.prompt_each_time"),
173           "Prompt each time");
174
175   private OptionsParam lineArtOpt = new OptionsParam(
176           MessageManager.getString("label.lineart"), "Lineart");
177
178   private OptionsParam textOpt = new OptionsParam(
179           MessageManager.getString("action.text"), "Text");
180
181   /**
182    * Creates a new Preferences object.
183    */
184   public Preferences()
185   {
186     super();
187     frame = new JInternalFrame();
188     frame.setContentPane(this);
189     dasSource = new DasSourceBrowser();
190     dasTab.add(dasSource, BorderLayout.CENTER);
191     wsPrefs = new WsPreferences();
192     wsTab.add(wsPrefs, BorderLayout.CENTER);
193     int width = 500, height = 450;
194     new jalview.util.Platform();
195     if (Platform.isAMac())
196     {
197       width = 570;
198       height = 480;
199     }
200
201     Desktop.addInternalFrame(frame,
202             MessageManager.getString("label.preferences"), width, height);
203     frame.setMinimumSize(new Dimension(width, height));
204
205     /*
206      * Set Visual tab defaults
207      */
208     seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true));
209     rightAlign.setSelected(Cache.getDefault("RIGHT_ALIGN_IDS", false));
210     fullScreen.setSelected(Cache.getDefault("SHOW_FULLSCREEN", false));
211     annotations.setSelected(Cache.getDefault("SHOW_ANNOTATIONS", true));
212
213     conservation.setSelected(Cache.getDefault("SHOW_CONSERVATION", true));
214     quality.setSelected(Cache.getDefault("SHOW_QUALITY", true));
215     identity.setSelected(Cache.getDefault("SHOW_IDENTITY", true));
216     openoverv.setSelected(Cache.getDefault("SHOW_OVERVIEW", false));
217     showUnconserved
218             .setSelected(Cache.getDefault("SHOW_UNCONSERVED", false));
219     showGroupConsensus.setSelected(Cache.getDefault("SHOW_GROUP_CONSENSUS",
220             false));
221     showGroupConservation.setSelected(Cache.getDefault(
222             "SHOW_GROUP_CONSERVATION", false));
223     showConsensHistogram.setSelected(Cache.getDefault(
224             "SHOW_CONSENSUS_HISTOGRAM", true));
225     showConsensLogo.setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO",
226             false));
227     showNpTooltip.setSelected(Cache
228             .getDefault("SHOW_NPFEATS_TOOLTIP", true));
229     showDbRefTooltip.setSelected(Cache.getDefault("SHOW_DBREFS_TOOLTIP",
230             true));
231
232     String[] fonts = java.awt.GraphicsEnvironment
233             .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
234     for (int i = 0; i < fonts.length; i++)
235     {
236       fontNameCB.addItem(fonts[i]);
237     }
238
239     for (int i = MIN_FONT_SIZE; i <= MAX_FONT_SIZE; i++)
240     {
241       fontSizeCB.addItem(i + "");
242     }
243
244     fontStyleCB.addItem("plain");
245     fontStyleCB.addItem("bold");
246     fontStyleCB.addItem("italic");
247
248     fontNameCB.setSelectedItem(Cache.getDefault("FONT_NAME", "SansSerif"));
249     fontSizeCB.setSelectedItem(Cache.getDefault("FONT_SIZE", "10"));
250     fontStyleCB.setSelectedItem(Cache.getDefault("FONT_STYLE", Font.PLAIN
251             + ""));
252
253     smoothFont.setSelected(Cache.getDefault("ANTI_ALIAS", false));
254     scaleProteinToCdna.setSelected(Cache.getDefault(SCALE_PROTEIN_TO_CDNA,
255             false));
256
257     idItalics.setSelected(Cache.getDefault("ID_ITALICS", true));
258
259     wrap.setSelected(Cache.getDefault("WRAP_ALIGNMENT", false));
260
261     gapSymbolCB.addItem("-");
262     gapSymbolCB.addItem(".");
263
264     gapSymbolCB.setSelectedItem(Cache.getDefault("GAP_SYMBOL", "-"));
265
266     sortby.addItem("No sort");
267     sortby.addItem("Id");
268     sortby.addItem("Pairwise Identity");
269     sortby.setSelectedItem(Cache.getDefault("SORT_ALIGNMENT", "No sort"));
270
271     sortAnnBy.addItem(SequenceAnnotationOrder.NONE.toString());
272     sortAnnBy
273             .addItem(SequenceAnnotationOrder.SEQUENCE_AND_LABEL.toString());
274     sortAnnBy
275             .addItem(SequenceAnnotationOrder.LABEL_AND_SEQUENCE.toString());
276     SequenceAnnotationOrder savedSort = SequenceAnnotationOrder
277             .valueOf(Cache.getDefault(SORT_ANNOTATIONS,
278                     SequenceAnnotationOrder.NONE.name()));
279     sortAnnBy.setSelectedItem(savedSort.toString());
280
281     sortAutocalc.addItem("Autocalculated first");
282     sortAutocalc.addItem("Autocalculated last");
283     final boolean showAbove = Cache.getDefault(SHOW_AUTOCALC_ABOVE, true);
284     sortAutocalc.setSelectedItem(showAbove ? sortAutocalc.getItemAt(0)
285             : sortAutocalc.getItemAt(1));
286     startupCheckbox
287             .setSelected(Cache.getDefault("SHOW_STARTUP_FILE", true));
288     startupFileTextfield.setText(Cache.getDefault("STARTUP_FILE",
289             Cache.getDefault("www.jalview.org", "http://www.jalview.org")
290                     + "/examples/exampleFile_2_3.jar"));
291
292     /*
293      * Set Colours tab defaults
294      */
295     protColour.addItem(ResidueColourScheme.NONE);
296     nucColour.addItem(ResidueColourScheme.NONE);
297     for (ColourSchemeI cs : ColourSchemes.getInstance().getColourSchemes())
298     {
299       String name = cs.getSchemeName();
300       protColour.addItem(name);
301       nucColour.addItem(name);
302     }
303     String oldProp = Cache.getDefault(DEFAULT_COLOUR,
304             ResidueColourScheme.NONE);
305     String newProp = Cache.getDefault(DEFAULT_COLOUR_PROT, null);
306     protColour.setSelectedItem(newProp != null ? newProp : oldProp);
307     newProp = Cache.getDefault(DEFAULT_COLOUR_NUC, null);
308     nucColour.setSelectedItem(newProp != null ? newProp : oldProp);
309     minColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN",
310             Color.orange));
311     maxColour.setBackground(Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX",
312             Color.red));
313
314     /*
315      * Set Structure tab defaults.
316      */
317     final boolean structSelected = Cache.getDefault(STRUCT_FROM_PDB, false);
318     structFromPdb.setSelected(structSelected);
319     useRnaView.setSelected(Cache.getDefault(USE_RNAVIEW, false));
320     useRnaView.setEnabled(structSelected);
321     addSecondaryStructure.setSelected(Cache.getDefault(ADD_SS_ANN, false));
322     addSecondaryStructure.setEnabled(structSelected);
323     addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, false));
324     addTempFactor.setEnabled(structSelected);
325     structViewer.setSelectedItem(Cache.getDefault(STRUCTURE_DISPLAY,
326             ViewerType.JMOL.name()));
327     chimeraPath.setText(Cache.getDefault(CHIMERA_PATH, ""));
328     chimeraPath.addActionListener(new ActionListener()
329     {
330       @Override
331       public void actionPerformed(ActionEvent e)
332       {
333         validateChimeraPath();
334       }
335     });
336
337     if (Cache.getDefault("MAP_WITH_SIFTS", false))
338     {
339       siftsMapping.setSelected(true);
340     }
341     else
342     {
343       nwMapping.setSelected(true);
344     }
345
346     SiftsSettings
347             .setMapWithSifts(Cache.getDefault("MAP_WITH_SIFTS", false));
348
349     /*
350      * Set Connections tab defaults
351      */
352     nameLinks = new Vector<String>();
353     urlLinks = new Vector<String>();
354     for (int i = 0; i < sequenceURLLinks.size(); i++)
355     {
356       String link = sequenceURLLinks.elementAt(i).toString();
357       nameLinks.addElement(link.substring(0, link.indexOf("|")));
358       urlLinks.addElement(link.substring(link.indexOf("|") + 1));
359     }
360
361     updateLinkData();
362
363     useProxy.setSelected(Cache.getDefault("USE_PROXY", false));
364     proxyServerTB.setEnabled(useProxy.isSelected());
365     proxyPortTB.setEnabled(useProxy.isSelected());
366     proxyServerTB.setText(Cache.getDefault("PROXY_SERVER", ""));
367     proxyPortTB.setText(Cache.getDefault("PROXY_PORT", ""));
368
369     defaultBrowser.setText(Cache.getDefault("DEFAULT_BROWSER", ""));
370
371     usagestats.setSelected(Cache.getDefault("USAGESTATS", false));
372     // note antisense here: default is true
373     questionnaire
374             .setSelected(Cache.getProperty("NOQUESTIONNAIRES") == null);
375     versioncheck.setSelected(Cache.getDefault("VERSION_CHECK", true));
376
377     /*
378      * Set Output tab defaults
379      */
380     epsRendering.addItem(promptEachTimeOpt);
381     epsRendering.addItem(lineArtOpt);
382     epsRendering.addItem(textOpt);
383     String defaultEPS = Cache.getDefault("EPS_RENDERING",
384             "Prompt each time");
385     if (defaultEPS.equalsIgnoreCase("Text"))
386     {
387       epsRendering.setSelectedItem(textOpt);
388     }
389     else if (defaultEPS.equalsIgnoreCase("Lineart"))
390     {
391       epsRendering.setSelectedItem(lineArtOpt);
392     }
393     else
394     {
395       epsRendering.setSelectedItem(promptEachTimeOpt);
396     }
397     autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false));
398     userIdWidth.setEnabled(!autoIdWidth.isSelected());
399     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
400     Integer wi = Cache.getIntegerProperty("FIGURE_USERIDWIDTH");
401     userIdWidth.setText(wi == null ? "" : wi.toString());
402     blcjv.setSelected(Cache.getDefault("BLC_JVSUFFIX", true));
403     clustaljv.setSelected(Cache.getDefault("CLUSTAL_JVSUFFIX", true));
404     fastajv.setSelected(Cache.getDefault("FASTA_JVSUFFIX", true));
405     msfjv.setSelected(Cache.getDefault("MSF_JVSUFFIX", true));
406     pfamjv.setSelected(Cache.getDefault("PFAM_JVSUFFIX", true));
407     pileupjv.setSelected(Cache.getDefault("PILEUP_JVSUFFIX", true));
408     pirjv.setSelected(Cache.getDefault("PIR_JVSUFFIX", true));
409     modellerOutput.setSelected(Cache.getDefault("PIR_MODELLER", false));
410     embbedBioJSON.setSelected(Cache.getDefault("EXPORT_EMBBED_BIOJSON",
411             true));
412
413     /*
414      * Set Editing tab defaults
415      */
416     autoCalculateConsCheck.setSelected(Cache.getDefault(
417             "AUTO_CALC_CONSENSUS", true));
418     padGaps.setSelected(Cache.getDefault("PAD_GAPS", false));
419     sortByTree.setSelected(Cache.getDefault("SORT_BY_TREE", false));
420
421     annotations_actionPerformed(null); // update the display of the annotation
422                                        // settings
423   }
424
425   /**
426    * Save user selections on the Preferences tabs to the Cache and write out to
427    * file.
428    * 
429    * @param e
430    */
431   @Override
432   public void ok_actionPerformed(ActionEvent e)
433   {
434     if (!validateSettings())
435     {
436       return;
437     }
438
439     /*
440      * Save Visual settings
441      */
442     Cache.applicationProperties.setProperty("SHOW_JVSUFFIX",
443             Boolean.toString(seqLimit.isSelected()));
444     Cache.applicationProperties.setProperty("RIGHT_ALIGN_IDS",
445             Boolean.toString(rightAlign.isSelected()));
446     Cache.applicationProperties.setProperty("SHOW_FULLSCREEN",
447             Boolean.toString(fullScreen.isSelected()));
448     Cache.applicationProperties.setProperty("SHOW_OVERVIEW",
449             Boolean.toString(openoverv.isSelected()));
450     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
451             Boolean.toString(annotations.isSelected()));
452     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
453             Boolean.toString(conservation.isSelected()));
454     Cache.applicationProperties.setProperty("SHOW_QUALITY",
455             Boolean.toString(quality.isSelected()));
456     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
457             Boolean.toString(identity.isSelected()));
458
459     Cache.applicationProperties.setProperty("GAP_SYMBOL", gapSymbolCB
460             .getSelectedItem().toString());
461
462     Cache.applicationProperties.setProperty("FONT_NAME", fontNameCB
463             .getSelectedItem().toString());
464     Cache.applicationProperties.setProperty("FONT_STYLE", fontStyleCB
465             .getSelectedItem().toString());
466     Cache.applicationProperties.setProperty("FONT_SIZE", fontSizeCB
467             .getSelectedItem().toString());
468
469     Cache.applicationProperties.setProperty("ID_ITALICS",
470             Boolean.toString(idItalics.isSelected()));
471     Cache.applicationProperties.setProperty("SHOW_UNCONSERVED",
472             Boolean.toString(showUnconserved.isSelected()));
473     Cache.applicationProperties.setProperty("SHOW_GROUP_CONSENSUS",
474             Boolean.toString(showGroupConsensus.isSelected()));
475     Cache.applicationProperties.setProperty("SHOW_GROUP_CONSERVATION",
476             Boolean.toString(showGroupConservation.isSelected()));
477     Cache.applicationProperties.setProperty("SHOW_CONSENSUS_HISTOGRAM",
478             Boolean.toString(showConsensHistogram.isSelected()));
479     Cache.applicationProperties.setProperty("SHOW_CONSENSUS_LOGO",
480             Boolean.toString(showConsensLogo.isSelected()));
481     Cache.applicationProperties.setProperty("ANTI_ALIAS",
482             Boolean.toString(smoothFont.isSelected()));
483     Cache.applicationProperties.setProperty(SCALE_PROTEIN_TO_CDNA,
484             Boolean.toString(scaleProteinToCdna.isSelected()));
485     Cache.applicationProperties.setProperty("SHOW_NPFEATS_TOOLTIP",
486             Boolean.toString(showNpTooltip.isSelected()));
487     Cache.applicationProperties.setProperty("SHOW_DBREFS_TOOLTIP",
488             Boolean.toString(showDbRefTooltip.isSelected()));
489
490     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT",
491             Boolean.toString(wrap.isSelected()));
492
493     Cache.applicationProperties.setProperty("STARTUP_FILE",
494             startupFileTextfield.getText());
495     Cache.applicationProperties.setProperty("SHOW_STARTUP_FILE",
496             Boolean.toString(startupCheckbox.isSelected()));
497
498     Cache.applicationProperties.setProperty("SORT_ALIGNMENT", sortby
499             .getSelectedItem().toString());
500
501     // convert description of sort order to enum name for save
502     SequenceAnnotationOrder annSortOrder = SequenceAnnotationOrder
503             .forDescription(sortAnnBy.getSelectedItem().toString());
504     if (annSortOrder != null)
505     {
506       Cache.applicationProperties.setProperty(SORT_ANNOTATIONS,
507               annSortOrder.name());
508     }
509
510     final boolean showAutocalcFirst = sortAutocalc.getSelectedIndex() == 0;
511     Cache.applicationProperties.setProperty(SHOW_AUTOCALC_ABOVE, Boolean
512             .valueOf(showAutocalcFirst).toString());
513
514     /*
515      * Save Colours settings
516      */
517     Cache.applicationProperties.setProperty(DEFAULT_COLOUR_PROT, protColour
518             .getSelectedItem().toString());
519     Cache.applicationProperties.setProperty(DEFAULT_COLOUR_NUC, nucColour
520             .getSelectedItem().toString());
521     Cache.setColourProperty("ANNOTATIONCOLOUR_MIN",
522             minColour.getBackground());
523     Cache.setColourProperty("ANNOTATIONCOLOUR_MAX",
524             maxColour.getBackground());
525
526     /*
527      * Save Structure settings
528      */
529     Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN,
530             Boolean.toString(addTempFactor.isSelected()));
531     Cache.applicationProperties.setProperty(ADD_SS_ANN,
532             Boolean.toString(addSecondaryStructure.isSelected()));
533     Cache.applicationProperties.setProperty(USE_RNAVIEW,
534             Boolean.toString(useRnaView.isSelected()));
535     Cache.applicationProperties.setProperty(STRUCT_FROM_PDB,
536             Boolean.toString(structFromPdb.isSelected()));
537     Cache.applicationProperties.setProperty(STRUCTURE_DISPLAY, structViewer
538             .getSelectedItem().toString());
539     Cache.setOrRemove(CHIMERA_PATH, chimeraPath.getText());
540     Cache.applicationProperties.setProperty("MAP_WITH_SIFTS",
541             Boolean.toString(siftsMapping.isSelected()));
542     SiftsSettings.setMapWithSifts(siftsMapping.isSelected());
543
544     /*
545      * Save Output settings
546      */
547     Cache.applicationProperties.setProperty("EPS_RENDERING",
548             ((OptionsParam) epsRendering.getSelectedItem()).getCode());
549
550     /*
551      * Save Connections settings
552      */
553     Cache.setOrRemove("DEFAULT_BROWSER", defaultBrowser.getText());
554
555     jalview.util.BrowserLauncher.resetBrowser();
556
557     if (nameLinks.size() > 0)
558     {
559       StringBuffer links = new StringBuffer();
560       sequenceURLLinks = new Vector<String>();
561       for (int i = 0; i < nameLinks.size(); i++)
562       {
563         sequenceURLLinks.addElement(nameLinks.elementAt(i) + "|"
564                 + urlLinks.elementAt(i));
565         links.append(sequenceURLLinks.elementAt(i).toString());
566         links.append("|");
567       }
568       // remove last "|"
569       links.setLength(links.length() - 1);
570       Cache.applicationProperties.setProperty("SEQUENCE_LINKS",
571               links.toString());
572     }
573     else
574     {
575       Cache.applicationProperties.remove("SEQUENCE_LINKS");
576       sequenceURLLinks.clear();
577     }
578
579     Cache.applicationProperties.setProperty("USE_PROXY",
580             Boolean.toString(useProxy.isSelected()));
581
582     Cache.setOrRemove("PROXY_SERVER", proxyServerTB.getText());
583
584     Cache.setOrRemove("PROXY_PORT", proxyPortTB.getText());
585
586     if (useProxy.isSelected())
587     {
588       System.setProperty("http.proxyHost", proxyServerTB.getText());
589       System.setProperty("http.proxyPort", proxyPortTB.getText());
590     }
591     else
592     {
593       System.setProperty("http.proxyHost", "");
594       System.setProperty("http.proxyPort", "");
595     }
596     Cache.setProperty("VERSION_CHECK",
597             Boolean.toString(versioncheck.isSelected()));
598     if (Cache.getProperty("USAGESTATS") != null || usagestats.isSelected())
599     {
600       // default is false - we only set this if the user has actively agreed
601       Cache.setProperty("USAGESTATS",
602               Boolean.toString(usagestats.isSelected()));
603     }
604     if (!questionnaire.isSelected())
605     {
606       Cache.setProperty("NOQUESTIONNAIRES", "true");
607     }
608     else
609     {
610       // special - made easy to edit a property file to disable questionnaires
611       // by just adding the given line
612       Cache.removeProperty("NOQUESTIONNAIRES");
613     }
614
615     /*
616      * Save Output settings
617      */
618     Cache.applicationProperties.setProperty("BLC_JVSUFFIX",
619             Boolean.toString(blcjv.isSelected()));
620     Cache.applicationProperties.setProperty("CLUSTAL_JVSUFFIX",
621             Boolean.toString(clustaljv.isSelected()));
622     Cache.applicationProperties.setProperty("FASTA_JVSUFFIX",
623             Boolean.toString(fastajv.isSelected()));
624     Cache.applicationProperties.setProperty("MSF_JVSUFFIX",
625             Boolean.toString(msfjv.isSelected()));
626     Cache.applicationProperties.setProperty("PFAM_JVSUFFIX",
627             Boolean.toString(pfamjv.isSelected()));
628     Cache.applicationProperties.setProperty("PILEUP_JVSUFFIX",
629             Boolean.toString(pileupjv.isSelected()));
630     Cache.applicationProperties.setProperty("PIR_JVSUFFIX",
631             Boolean.toString(pirjv.isSelected()));
632     Cache.applicationProperties.setProperty("PIR_MODELLER",
633             Boolean.toString(modellerOutput.isSelected()));
634     Cache.applicationProperties.setProperty("EXPORT_EMBBED_BIOJSON",
635             Boolean.toString(embbedBioJSON.isSelected()));
636     jalview.io.PIRFile.useModellerOutput = modellerOutput.isSelected();
637
638     Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH",
639             Boolean.toString(autoIdWidth.isSelected()));
640     userIdWidth_actionPerformed();
641     Cache.applicationProperties.setProperty("FIGURE_USERIDWIDTH",
642             userIdWidth.getText());
643
644     /*
645      * Save Editing settings
646      */
647     Cache.applicationProperties.setProperty("AUTO_CALC_CONSENSUS",
648             Boolean.toString(autoCalculateConsCheck.isSelected()));
649     Cache.applicationProperties.setProperty("SORT_BY_TREE",
650             Boolean.toString(sortByTree.isSelected()));
651     Cache.applicationProperties.setProperty("PAD_GAPS",
652             Boolean.toString(padGaps.isSelected()));
653
654     dasSource.saveProperties(Cache.applicationProperties);
655     wsPrefs.updateAndRefreshWsMenuConfig(false);
656     Cache.saveProperties();
657     Desktop.instance.doConfigureStructurePrefs();
658     try
659     {
660       frame.setClosed(true);
661     } catch (Exception ex)
662     {
663     }
664   }
665
666   /**
667    * Do any necessary validation before saving settings. Return focus to the
668    * first tab which fails validation.
669    * 
670    * @return
671    */
672   private boolean validateSettings()
673   {
674     if (!validateStructure())
675     {
676       structureTab.requestFocusInWindow();
677       return false;
678     }
679     return true;
680   }
681
682   @Override
683   protected boolean validateStructure()
684   {
685     return validateChimeraPath();
686
687   }
688
689   /**
690    * DOCUMENT ME!
691    */
692   @Override
693   public void startupFileTextfield_mouseClicked()
694   {
695     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
696     JalviewFileChooser chooser = JalviewFileChooser.forRead(
697             Cache.getProperty("LAST_DIRECTORY"), fileFormat);
698     chooser.setFileView(new JalviewFileView());
699     chooser.setDialogTitle(MessageManager
700             .getString("label.select_startup_file"));
701
702     int value = chooser.showOpenDialog(this);
703
704     if (value == JalviewFileChooser.APPROVE_OPTION)
705     {
706       FileFormatI format = chooser.getSelectedFormat();
707       if (format != null)
708       {
709         Cache.applicationProperties.setProperty("DEFAULT_FILE_FORMAT",
710                 format.getName());
711       }
712       startupFileTextfield.setText(chooser.getSelectedFile()
713               .getAbsolutePath());
714     }
715   }
716
717   /**
718    * DOCUMENT ME!
719    * 
720    * @param e
721    *          DOCUMENT ME!
722    */
723   @Override
724   public void cancel_actionPerformed(ActionEvent e)
725   {
726     try
727     {
728       wsPrefs.updateWsMenuConfig(true);
729       wsPrefs.refreshWs_actionPerformed(e);
730       frame.setClosed(true);
731     } catch (Exception ex)
732     {
733     }
734   }
735
736   /**
737    * DOCUMENT ME!
738    * 
739    * @param e
740    *          DOCUMENT ME!
741    */
742   @Override
743   public void annotations_actionPerformed(ActionEvent e)
744   {
745     conservation.setEnabled(annotations.isSelected());
746     quality.setEnabled(annotations.isSelected());
747     identity.setEnabled(annotations.isSelected());
748     showGroupConsensus.setEnabled(annotations.isSelected());
749     showGroupConservation.setEnabled(annotations.isSelected());
750     showConsensHistogram.setEnabled(annotations.isSelected()
751             && (identity.isSelected() || showGroupConsensus.isSelected()));
752     showConsensLogo.setEnabled(annotations.isSelected()
753             && (identity.isSelected() || showGroupConsensus.isSelected()));
754   }
755
756   @Override
757   public void newLink_actionPerformed(ActionEvent e)
758   {
759
760     GSequenceLink link = new GSequenceLink();
761     boolean valid = false;
762     while (!valid)
763     {
764       if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link,
765               MessageManager.getString("label.new_sequence_url_link"),
766               JvOptionPane.OK_CANCEL_OPTION, -1, null) == JvOptionPane.OK_OPTION)
767       {
768         if (link.checkValid())
769         {
770           nameLinks.addElement(link.getName());
771           urlLinks.addElement(link.getURL());
772           updateLinkData();
773           valid = true;
774         }
775       }
776       else
777       {
778         break;
779       }
780     }
781   }
782
783   @Override
784   public void editLink_actionPerformed(ActionEvent e)
785   {
786     GSequenceLink link = new GSequenceLink();
787
788     int index = linkNameList.getSelectedIndex();
789     if (index == -1)
790     {
791       JvOptionPane.showInternalMessageDialog(Desktop.desktop,
792               MessageManager.getString("label.no_link_selected"),
793               MessageManager.getString("label.no_link_selected"),
794               JvOptionPane.WARNING_MESSAGE);
795       return;
796     }
797
798     link.setName(nameLinks.elementAt(index).toString());
799     link.setURL(urlLinks.elementAt(index).toString());
800
801     boolean valid = false;
802     while (!valid)
803     {
804
805       if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link,
806               MessageManager.getString("label.new_sequence_url_link"),
807               JvOptionPane.OK_CANCEL_OPTION, -1, null) == JvOptionPane.OK_OPTION)
808       {
809         if (link.checkValid())
810         {
811           nameLinks.setElementAt(link.getName(), index);
812           urlLinks.setElementAt(link.getURL(), index);
813           updateLinkData();
814           valid = true;
815         }
816       }
817
818       else
819       {
820         break;
821       }
822     }
823   }
824
825   @Override
826   public void deleteLink_actionPerformed(ActionEvent e)
827   {
828     int index = linkNameList.getSelectedIndex();
829     if (index == -1)
830     {
831       JvOptionPane.showInternalMessageDialog(Desktop.desktop,
832               MessageManager.getString("label.no_link_selected"),
833               MessageManager.getString("label.no_link_selected"),
834               JvOptionPane.WARNING_MESSAGE);
835       return;
836     }
837     nameLinks.removeElementAt(index);
838     urlLinks.removeElementAt(index);
839     updateLinkData();
840   }
841
842   void updateLinkData()
843   {
844     linkNameList.setListData(nameLinks);
845     linkURLList.setListData(urlLinks);
846   }
847
848   @Override
849   public void defaultBrowser_mouseClicked(MouseEvent e)
850   {
851     JFileChooser chooser = new JFileChooser(".");
852     chooser.setDialogTitle(MessageManager
853             .getString("label.select_default_browser"));
854
855     int value = chooser.showOpenDialog(this);
856
857     if (value == JFileChooser.APPROVE_OPTION)
858     {
859       defaultBrowser.setText(chooser.getSelectedFile().getAbsolutePath());
860     }
861
862   }
863
864   /*
865    * (non-Javadoc)
866    * 
867    * @see
868    * jalview.jbgui.GPreferences#showunconserved_actionPerformed(java.awt.event
869    * .ActionEvent)
870    */
871   @Override
872   protected void showunconserved_actionPerformed(ActionEvent e)
873   {
874     // TODO Auto-generated method stub
875     super.showunconserved_actionPerformed(e);
876   }
877
878   public static List<String> getGroupURLLinks()
879   {
880     return groupURLLinks;
881   }
882
883   @Override
884   public void minColour_actionPerformed(JPanel panel)
885   {
886     Color col = JColorChooser.showDialog(this,
887             MessageManager.getString("label.select_colour_minimum_value"),
888             minColour.getBackground());
889     if (col != null)
890     {
891       panel.setBackground(col);
892     }
893     panel.repaint();
894   }
895
896   @Override
897   public void maxColour_actionPerformed(JPanel panel)
898   {
899     Color col = JColorChooser.showDialog(this,
900             MessageManager.getString("label.select_colour_maximum_value"),
901             maxColour.getBackground());
902     if (col != null)
903     {
904       panel.setBackground(col);
905     }
906     panel.repaint();
907   }
908
909   @Override
910   protected void userIdWidth_actionPerformed()
911   {
912     try
913     {
914       String val = userIdWidth.getText().trim();
915       if (val.length() > 0)
916       {
917         Integer iw = Integer.parseInt(val);
918         if (iw.intValue() < 12)
919         {
920           throw new NumberFormatException();
921         }
922         userIdWidth.setText(iw.toString());
923       }
924     } catch (NumberFormatException x)
925     {
926       JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
927               .getString("warn.user_defined_width_requirements"),
928               MessageManager.getString("label.invalid_id_column_width"),
929               JvOptionPane.WARNING_MESSAGE);
930       userIdWidth.setText("");
931     }
932   }
933
934   @Override
935   protected void autoIdWidth_actionPerformed()
936   {
937     userIdWidth.setEnabled(!autoIdWidth.isSelected());
938     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
939   }
940
941   /**
942    * Returns true if chimera path is to a valid executable, else show an error
943    * dialog.
944    */
945   private boolean validateChimeraPath()
946   {
947     if (chimeraPath.getText().trim().length() > 0)
948     {
949       File f = new File(chimeraPath.getText());
950       if (!f.canExecute())
951       {
952         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
953                 MessageManager.getString("label.invalid_chimera_path"),
954                 MessageManager.getString("label.invalid_name"),
955                 JvOptionPane.ERROR_MESSAGE);
956         return false;
957       }
958     }
959     return true;
960   }
961
962   /**
963    * If Chimera is selected, check it can be found on default or user-specified
964    * path, if not show a warning/help dialog.
965    */
966   @Override
967   protected void structureViewer_actionPerformed(String selectedItem)
968   {
969     if (!selectedItem.equals(ViewerType.CHIMERA.name()))
970     {
971       return;
972     }
973     boolean found = false;
974
975     /*
976      * Try user-specified and standard paths for Chimera executable.
977      */
978     List<String> paths = StructureManager.getChimeraPaths();
979     paths.add(0, chimeraPath.getText());
980     for (String path : paths)
981     {
982       if (new File(path.trim()).canExecute())
983       {
984         found = true;
985         break;
986       }
987     }
988     if (!found)
989     {
990       String[] options = { "OK", "Help" };
991       int showHelp = JvOptionPane.showInternalOptionDialog(
992               Desktop.desktop,
993               JvSwingUtils.wrapTooltip(true,
994                       MessageManager.getString("label.chimera_missing")),
995               "", JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
996               null, options, options[0]);
997       if (showHelp == JvOptionPane.NO_OPTION)
998       {
999         try
1000         {
1001           Help.showHelpWindow(HelpId.StructureViewer);
1002         } catch (HelpSetException e)
1003         {
1004           e.printStackTrace();
1005         }
1006       }
1007     }
1008   }
1009
1010   public class OptionsParam
1011   {
1012     private String name;
1013
1014     private String code;
1015
1016     public OptionsParam(String name, String code)
1017     {
1018       this.name = name;
1019       this.code = code;
1020     }
1021
1022     public String getName()
1023     {
1024       return name;
1025     }
1026
1027     public void setName(String name)
1028     {
1029       this.name = name;
1030     }
1031
1032     public String getCode()
1033     {
1034       return code;
1035     }
1036
1037     public void setCode(String code)
1038     {
1039       this.code = code;
1040     }
1041
1042     @Override
1043     public String toString()
1044     {
1045       return name;
1046     }
1047
1048     @Override
1049     public boolean equals(Object that)
1050     {
1051       if (!(that instanceof OptionsParam))
1052       {
1053         return false;
1054       }
1055       return this.code.equalsIgnoreCase(((OptionsParam) that).code);
1056     }
1057
1058     @Override
1059     public int hashCode()
1060     {
1061       return name.hashCode() + code.hashCode();
1062     }
1063   }
1064 }