JAL-3633 Apply (proxy) button enabled when needed
[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 java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Component;
26 import java.awt.Dimension;
27 import java.awt.Font;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.ActionListener;
30 import java.awt.event.MouseEvent;
31 import java.io.File;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import javax.help.HelpSetException;
36 import javax.swing.JColorChooser;
37 import javax.swing.JFileChooser;
38 import javax.swing.JInternalFrame;
39 import javax.swing.JPanel;
40 import javax.swing.ListSelectionModel;
41 import javax.swing.RowFilter;
42 import javax.swing.RowSorter;
43 import javax.swing.SortOrder;
44 import javax.swing.event.DocumentEvent;
45 import javax.swing.event.DocumentListener;
46 import javax.swing.event.ListSelectionEvent;
47 import javax.swing.event.ListSelectionListener;
48 import javax.swing.table.TableCellRenderer;
49 import javax.swing.table.TableColumn;
50 import javax.swing.table.TableModel;
51 import javax.swing.table.TableRowSorter;
52
53 import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
54 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
55 import jalview.bin.Cache;
56 import jalview.gui.Help.HelpId;
57 import jalview.gui.StructureViewer.ViewerType;
58 import jalview.io.BackupFiles;
59 import jalview.io.BackupFilesPresetEntry;
60 import jalview.io.FileFormatI;
61 import jalview.io.JalviewFileChooser;
62 import jalview.io.JalviewFileView;
63 import jalview.jbgui.GPreferences;
64 import jalview.jbgui.GSequenceLink;
65 import jalview.schemes.ColourSchemeI;
66 import jalview.schemes.ColourSchemes;
67 import jalview.schemes.ResidueColourScheme;
68 import jalview.urls.UrlLinkTableModel;
69 import jalview.urls.api.UrlProviderFactoryI;
70 import jalview.urls.api.UrlProviderI;
71 import jalview.urls.desktop.DesktopUrlProviderFactory;
72 import jalview.util.MessageManager;
73 import jalview.util.Platform;
74 import jalview.util.UrlConstants;
75 import jalview.ws.sifts.SiftsSettings;
76
77 /**
78  * DOCUMENT ME!
79  * 
80  * @author $author$
81  * @version $Revision$
82  */
83 /*
84  * for merge with Jalview-JS
85  public class Preferences extends GPreferences implements ApplicationSingletonI
86  */
87 public class Preferences extends GPreferences
88 {
89   public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
90
91   public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA";
92
93   public static final String DEFAULT_COLOUR = "DEFAULT_COLOUR";
94
95   public static final String DEFAULT_COLOUR_PROT = "DEFAULT_COLOUR_PROT";
96
97   public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC";
98
99   public static final String ADD_TEMPFACT_ANN = "ADD_TEMPFACT_ANN";
100
101   public static final String ADD_SS_ANN = "ADD_SS_ANN";
102
103   public static final String USE_RNAVIEW = "USE_RNAVIEW";
104
105   public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB";
106
107   public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY";
108
109   public static final String CHIMERA_PATH = "CHIMERA_PATH";
110
111   public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS";
112
113   public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
114
115   public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY";
116
117   public static final String SHOW_OV_HIDDEN_AT_START = "SHOW_OV_HIDDEN_AT_START";
118
119   public static final String USE_LEGACY_GAP = "USE_LEGACY_GAP";
120
121   public static final String GAP_COLOUR = "GAP_COLOUR";
122
123   public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR";
124
125   private static final int MIN_FONT_SIZE = 1;
126
127   private static final int MAX_FONT_SIZE = 30;
128
129   private String previousProxyType;
130
131   private static Preferences INSTANCE = null; // add "final"
132
133   /**
134    * Holds name and link separated with | character. Sequence ID must be
135    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
136    */
137   public static UrlProviderI sequenceUrlLinks;
138
139   public static UrlLinkTableModel dataModel;
140
141   /**
142    * Holds name and link separated with | character. Sequence IDS and Sequences
143    * must be $SEQUENCEIDS$ or $SEQUENCEIDS=/.possible | chars ./=$ and
144    * $SEQUENCES$ or $SEQUENCES=/.possible | chars ./=$ and separation character
145    * for first and second token specified after a pipe character at end |,|.
146    * (TODO: proper escape for using | to separate ids or sequences
147    */
148
149   public static List<String> groupURLLinks;
150   static
151   {
152     // get links selected to be in the menu (SEQUENCE_LINKS)
153     // and links entered by the user but not selected (STORED_LINKS)
154     String inMenuString = Cache.getDefault("SEQUENCE_LINKS", "");
155     String notInMenuString = Cache.getDefault("STORED_LINKS", "");
156     String defaultUrl = Cache.getDefault("DEFAULT_URL",
157             UrlConstants.DEFAULT_LABEL);
158
159     // if both links lists are empty, add the DEFAULT_URL link
160     // otherwise we assume the default link is in one of the lists
161     if (inMenuString.isEmpty() && notInMenuString.isEmpty())
162     {
163       inMenuString = UrlConstants.DEFAULT_STRING;
164     }
165     UrlProviderFactoryI factory = new DesktopUrlProviderFactory(defaultUrl,
166             inMenuString, notInMenuString);
167     sequenceUrlLinks = factory.createUrlProvider();
168     dataModel = new UrlLinkTableModel(sequenceUrlLinks);
169
170     /**
171      * TODO: reformulate groupURL encoding so two or more can be stored in the
172      * .properties file as '|' separated strings
173      */
174
175     groupURLLinks = new ArrayList<>();
176   }
177
178   JInternalFrame frame;
179
180   private WsPreferences wsPrefs;
181
182   private OptionsParam promptEachTimeOpt = new OptionsParam(
183           MessageManager.getString("label.prompt_each_time"),
184           "Prompt each time");
185
186   private OptionsParam lineArtOpt = new OptionsParam(
187           MessageManager.getString("label.lineart"), "Lineart");
188
189   private OptionsParam textOpt = new OptionsParam(
190           MessageManager.getString("action.text"), "Text");
191
192   // get singleton Preferences instance
193   public static Preferences getInstance()
194   {
195     if (INSTANCE == null || INSTANCE.frame == null
196             || INSTANCE.frame.isClosed())
197     {
198       INSTANCE = new Preferences();
199     }
200     return INSTANCE;
201
202     /*
203      * Replace code with the following for Jalvew-JS
204     Preferences INSTANCE = ApplicationSingletonProvider.getInstance(Preferences.class);
205     if (INSTANCE == null || INSTANCE.frame == null
206             || INSTANCE.frame.isClosed())
207     {
208       ApplicationSingletonProvider.remove(Preferences.class);
209       INSTANCE = ApplicationSingletonProvider.getInstance(Preferences.class);
210     }
211     return INSTANCE;
212     */
213   }
214
215   public static void openPreferences()
216   {
217     openPreferences(0, null);
218   }
219
220   public static void openPreferences(int selectTab, String message)
221   {
222     Preferences p = getInstance();
223     p.selectTab(selectTab);
224     p.setMessage(message);
225     p.frame.show();
226     p.frame.moveToFront();
227     p.frame.grabFocus();
228   }
229
230   /**
231    * Creates a new Preferences object.
232    */
233   private Preferences()
234   {
235     super();
236     frame = new JInternalFrame();
237     frame.setContentPane(this);
238     wsPrefs = new WsPreferences();
239     wsTab.add(wsPrefs, BorderLayout.CENTER);
240     int width = 500, height = 450;
241     new jalview.util.Platform();
242     if (Platform.isAMac())
243     {
244       width = 570;
245       height = 480;
246     }
247
248     Desktop.addInternalFrame(frame,
249             MessageManager.getString("label.preferences"), width, height);
250     frame.setMinimumSize(new Dimension(width, height));
251
252     /*
253      * Set Visual tab defaults
254      */
255     seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true));
256     rightAlign.setSelected(Cache.getDefault("RIGHT_ALIGN_IDS", false));
257     fullScreen.setSelected(Cache.getDefault("SHOW_FULLSCREEN", false));
258     annotations.setSelected(Cache.getDefault("SHOW_ANNOTATIONS", true));
259
260     conservation.setSelected(Cache.getDefault("SHOW_CONSERVATION", true));
261     quality.setSelected(Cache.getDefault("SHOW_QUALITY", true));
262     identity.setSelected(Cache.getDefault("SHOW_IDENTITY", true));
263     openoverv.setSelected(Cache.getDefault("SHOW_OVERVIEW", false));
264     showUnconserved
265             .setSelected(Cache.getDefault("SHOW_UNCONSERVED", false));
266     showOccupancy.setSelected(Cache.getDefault(SHOW_OCCUPANCY, false));
267     showGroupConsensus
268             .setSelected(Cache.getDefault("SHOW_GROUP_CONSENSUS", false));
269     showGroupConservation.setSelected(
270             Cache.getDefault("SHOW_GROUP_CONSERVATION", false));
271     showConsensHistogram.setSelected(
272             Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true));
273     showConsensLogo
274             .setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO", false));
275     showNpTooltip
276             .setSelected(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true));
277     showDbRefTooltip
278             .setSelected(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true));
279
280     String[] fonts = java.awt.GraphicsEnvironment
281             .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
282     for (int i = 0; i < fonts.length; i++)
283     {
284       fontNameCB.addItem(fonts[i]);
285     }
286
287     for (int i = MIN_FONT_SIZE; i <= MAX_FONT_SIZE; i++)
288     {
289       fontSizeCB.addItem(i + "");
290     }
291
292     fontStyleCB.addItem("plain");
293     fontStyleCB.addItem("bold");
294     fontStyleCB.addItem("italic");
295
296     fontNameCB.setSelectedItem(Cache.getDefault("FONT_NAME", "SansSerif"));
297     fontSizeCB.setSelectedItem(Cache.getDefault("FONT_SIZE", "10"));
298     fontStyleCB.setSelectedItem(
299             Cache.getDefault("FONT_STYLE", Font.PLAIN + ""));
300
301     smoothFont.setSelected(Cache.getDefault("ANTI_ALIAS", true));
302     scaleProteinToCdna
303             .setSelected(Cache.getDefault(SCALE_PROTEIN_TO_CDNA, false));
304
305     idItalics.setSelected(Cache.getDefault("ID_ITALICS", true));
306
307     wrap.setSelected(Cache.getDefault("WRAP_ALIGNMENT", false));
308
309     gapSymbolCB.addItem("-");
310     gapSymbolCB.addItem(".");
311
312     gapSymbolCB.setSelectedItem(Cache.getDefault("GAP_SYMBOL", "-"));
313
314     sortby.addItem("No sort");
315     sortby.addItem("Id");
316     sortby.addItem("Pairwise Identity");
317     sortby.setSelectedItem(Cache.getDefault("SORT_ALIGNMENT", "No sort"));
318
319     sortAnnBy.addItem(SequenceAnnotationOrder.NONE.toString());
320     sortAnnBy
321             .addItem(SequenceAnnotationOrder.SEQUENCE_AND_LABEL.toString());
322     sortAnnBy
323             .addItem(SequenceAnnotationOrder.LABEL_AND_SEQUENCE.toString());
324     SequenceAnnotationOrder savedSort = SequenceAnnotationOrder
325             .valueOf(Cache.getDefault(SORT_ANNOTATIONS,
326                     SequenceAnnotationOrder.NONE.name()));
327     sortAnnBy.setSelectedItem(savedSort.toString());
328
329     sortAutocalc.addItem("Autocalculated first");
330     sortAutocalc.addItem("Autocalculated last");
331     final boolean showAbove = Cache.getDefault(SHOW_AUTOCALC_ABOVE, true);
332     sortAutocalc.setSelectedItem(showAbove ? sortAutocalc.getItemAt(0)
333             : sortAutocalc.getItemAt(1));
334     startupCheckbox
335             .setSelected(Cache.getDefault("SHOW_STARTUP_FILE", true));
336     startupFileTextfield.setText(Cache.getDefault("STARTUP_FILE",
337             Cache.getDefault("www.jalview.org", "http://www.jalview.org")
338                     + "/examples/exampleFile_2_3.jar"));
339
340     /*
341      * Set Colours tab defaults
342      */
343     protColour.addItem(ResidueColourScheme.NONE);
344     nucColour.addItem(ResidueColourScheme.NONE);
345     for (ColourSchemeI cs : ColourSchemes.getInstance().getColourSchemes())
346     {
347       String name = cs.getSchemeName();
348       protColour.addItem(name);
349       nucColour.addItem(name);
350     }
351     String oldProp = Cache.getDefault(DEFAULT_COLOUR,
352             ResidueColourScheme.NONE);
353     String newProp = Cache.getDefault(DEFAULT_COLOUR_PROT, null);
354     protColour.setSelectedItem(newProp != null ? newProp : oldProp);
355     newProp = Cache.getDefault(DEFAULT_COLOUR_NUC, null);
356     nucColour.setSelectedItem(newProp != null ? newProp : oldProp);
357     minColour.setBackground(
358             Cache.getDefaultColour("ANNOTATIONCOLOUR_MIN", Color.orange));
359     maxColour.setBackground(
360             Cache.getDefaultColour("ANNOTATIONCOLOUR_MAX", Color.red));
361
362     /*
363      * Set overview panel defaults
364      */
365     gapColour.setBackground(Cache.getDefaultColour(GAP_COLOUR,
366             jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP));
367     hiddenColour.setBackground(Cache.getDefaultColour(HIDDEN_COLOUR,
368             jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN));
369     useLegacyGap.setSelected(Cache.getDefault(USE_LEGACY_GAP, false));
370     gapLabel.setEnabled(!useLegacyGap.isSelected());
371     gapColour.setEnabled(!useLegacyGap.isSelected());
372     showHiddenAtStart
373             .setSelected(Cache.getDefault(SHOW_OV_HIDDEN_AT_START, false));
374
375     /*
376      * Set Structure tab defaults.
377      */
378     final boolean structSelected = Cache.getDefault(STRUCT_FROM_PDB, false);
379     structFromPdb.setSelected(structSelected);
380     useRnaView.setSelected(Cache.getDefault(USE_RNAVIEW, false));
381     useRnaView.setEnabled(structSelected);
382     addSecondaryStructure.setSelected(Cache.getDefault(ADD_SS_ANN, false));
383     addSecondaryStructure.setEnabled(structSelected);
384     addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, false));
385     addTempFactor.setEnabled(structSelected);
386     structViewer.setSelectedItem(
387             Cache.getDefault(STRUCTURE_DISPLAY, ViewerType.JMOL.name()));
388     chimeraPath.setText(Cache.getDefault(CHIMERA_PATH, ""));
389     chimeraPath.addActionListener(new ActionListener()
390     {
391       @Override
392       public void actionPerformed(ActionEvent e)
393       {
394         validateChimeraPath();
395       }
396     });
397
398     if (Cache.getDefault("MAP_WITH_SIFTS", false))
399     {
400       siftsMapping.setSelected(true);
401     }
402     else
403     {
404       nwMapping.setSelected(true);
405     }
406
407     SiftsSettings
408             .setMapWithSifts(Cache.getDefault("MAP_WITH_SIFTS", false));
409
410     /*
411      * Set Connections tab defaults
412      */
413
414     // set up sorting
415     linkUrlTable.setModel(dataModel);
416     final TableRowSorter<TableModel> sorter = new TableRowSorter<>(
417             linkUrlTable.getModel());
418     linkUrlTable.setRowSorter(sorter);
419     List<RowSorter.SortKey> sortKeys = new ArrayList<>();
420
421     UrlLinkTableModel m = (UrlLinkTableModel) linkUrlTable.getModel();
422     sortKeys.add(new RowSorter.SortKey(m.getPrimaryColumn(),
423             SortOrder.DESCENDING));
424     sortKeys.add(new RowSorter.SortKey(m.getSelectedColumn(),
425             SortOrder.DESCENDING));
426     sortKeys.add(
427             new RowSorter.SortKey(m.getNameColumn(), SortOrder.ASCENDING));
428
429     sorter.setSortKeys(sortKeys);
430     sorter.sort();
431
432     // set up filtering
433     ActionListener onReset;
434     onReset = new ActionListener()
435     {
436       @Override
437       public void actionPerformed(ActionEvent e)
438       {
439         filterTB.setText("");
440         sorter.setRowFilter(RowFilter.regexFilter(""));
441       }
442
443     };
444     doReset.addActionListener(onReset);
445
446     // filter to display only custom urls
447     final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
448     {
449       @Override
450       public boolean include(
451               Entry<? extends TableModel, ? extends Object> entry)
452       {
453         return ((UrlLinkTableModel) entry.getModel()).isUserEntry(entry);
454       }
455     };
456
457     final TableRowSorter<TableModel> customSorter = new TableRowSorter<>(
458             linkUrlTable.getModel());
459     customSorter.setRowFilter(customUrlFilter);
460
461     ActionListener onCustomOnly;
462     onCustomOnly = new ActionListener()
463     {
464       @Override
465       public void actionPerformed(ActionEvent e)
466       {
467         filterTB.setText("");
468         sorter.setRowFilter(customUrlFilter);
469       }
470     };
471     userOnly.addActionListener(onCustomOnly);
472
473     filterTB.getDocument().addDocumentListener(new DocumentListener()
474     {
475       String caseInsensitiveFlag = "(?i)";
476
477       @Override
478       public void changedUpdate(DocumentEvent e)
479       {
480         sorter.setRowFilter(RowFilter
481                 .regexFilter(caseInsensitiveFlag + filterTB.getText()));
482       }
483
484       @Override
485       public void removeUpdate(DocumentEvent e)
486       {
487         sorter.setRowFilter(RowFilter
488                 .regexFilter(caseInsensitiveFlag + filterTB.getText()));
489       }
490
491       @Override
492       public void insertUpdate(DocumentEvent e)
493       {
494         sorter.setRowFilter(RowFilter
495                 .regexFilter(caseInsensitiveFlag + filterTB.getText()));
496       }
497     });
498
499     // set up list selection functionality
500     linkUrlTable.getSelectionModel()
501             .addListSelectionListener(new UrlListSelectionHandler());
502
503     // set up radio buttons
504     int onClickCol = ((UrlLinkTableModel) linkUrlTable.getModel())
505             .getPrimaryColumn();
506     String onClickName = linkUrlTable.getColumnName(onClickCol);
507     linkUrlTable.getColumn(onClickName)
508             .setCellRenderer(new RadioButtonRenderer());
509     linkUrlTable.getColumn(onClickName)
510             .setCellEditor(new RadioButtonEditor());
511
512     // get boolean columns and resize those to min possible
513     for (int column = 0; column < linkUrlTable.getColumnCount(); column++)
514     {
515       if (linkUrlTable.getModel().getColumnClass(column)
516               .equals(Boolean.class))
517       {
518         TableColumn tableColumn = linkUrlTable.getColumnModel()
519                 .getColumn(column);
520         int preferredWidth = tableColumn.getMinWidth();
521
522         TableCellRenderer cellRenderer = linkUrlTable.getCellRenderer(0,
523                 column);
524         Component c = linkUrlTable.prepareRenderer(cellRenderer, 0, column);
525         int cwidth = c.getPreferredSize().width
526                 + linkUrlTable.getIntercellSpacing().width;
527         preferredWidth = Math.max(preferredWidth, cwidth);
528
529         tableColumn.setPreferredWidth(preferredWidth);
530       }
531     }
532
533     String proxyTypeString = Cache.getDefault("USE_PROXY", "false");
534     previousProxyType = proxyTypeString;
535     switch (proxyTypeString)
536     {
537     case Cache.PROXYTYPE_NONE:
538       proxyType.setSelected(noProxy.getModel(), true);
539       break;
540     case Cache.PROXYTYPE_SYSTEM:
541       proxyType.setSelected(systemProxy.getModel(), true);
542       break;
543     case Cache.PROXYTYPE_CUSTOM:
544       proxyType.setSelected(customProxy.getModel(), true);
545       break;
546     default:
547       Cache.log.warn(
548               "Incorrect PROXY_TYPE - should be 'none' (clear proxy properties), 'false' (system settings), 'true' (custom settings): "
549                       + proxyTypeString);
550     }
551     proxyServerHttpTB.setText(Cache.getDefault("PROXY_SERVER", ""));
552     proxyPortHttpTB.setText(Cache.getDefault("PROXY_PORT", ""));
553     proxyServerHttpsTB.setText(Cache.getDefault("PROXY_SERVER_HTTPS", ""));
554     proxyPortHttpsTB.setText(Cache.getDefault("PROXY_PORT_HTTPS", ""));
555     proxyAuth.setSelected(Cache.getDefault("PROXY_AUTH", false));
556     proxyAuthUsernameTB
557             .setText(Cache.getDefault("PROXY_AUTH_USERNAME", ""));
558     // we are not storing or retrieving proxy password from .jalview_properties
559     proxyAuthPasswordPB.setText(Cache.proxyAuthPassword == null ? ""
560             : new String(Cache.proxyAuthPassword));
561     setCustomProxyEnabled();
562     applyProxyButtonEnabled(false);
563
564     defaultBrowser.setText(Cache.getDefault("DEFAULT_BROWSER", ""));
565
566     usagestats.setSelected(Cache.getDefault("USAGESTATS", false));
567     // note antisense here: default is true
568     questionnaire
569             .setSelected(Cache.getProperty("NOQUESTIONNAIRES") == null);
570     versioncheck.setSelected(Cache.getDefault("VERSION_CHECK", true));
571
572     /*
573      * Set Output tab defaults
574      */
575     epsRendering.addItem(promptEachTimeOpt);
576     epsRendering.addItem(lineArtOpt);
577     epsRendering.addItem(textOpt);
578     String defaultEPS = Cache.getDefault("EPS_RENDERING",
579             "Prompt each time");
580     if (defaultEPS.equalsIgnoreCase("Text"))
581     {
582       epsRendering.setSelectedItem(textOpt);
583     }
584     else if (defaultEPS.equalsIgnoreCase("Lineart"))
585     {
586       epsRendering.setSelectedItem(lineArtOpt);
587     }
588     else
589     {
590       epsRendering.setSelectedItem(promptEachTimeOpt);
591     }
592     autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false));
593     userIdWidth.setEnabled(!autoIdWidth.isSelected());
594     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
595     Integer wi = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH");
596     userIdWidth.setText(wi == null ? "" : wi.toString());
597     // TODO: refactor to use common enum via FormatAdapter and allow extension
598     // for new flat file formats
599     blcjv.setSelected(Cache.getDefault("BLC_JVSUFFIX", true));
600     clustaljv.setSelected(Cache.getDefault("CLUSTAL_JVSUFFIX", true));
601     fastajv.setSelected(Cache.getDefault("FASTA_JVSUFFIX", true));
602     msfjv.setSelected(Cache.getDefault("MSF_JVSUFFIX", true));
603     pfamjv.setSelected(Cache.getDefault("PFAM_JVSUFFIX", true));
604     pileupjv.setSelected(Cache.getDefault("PILEUP_JVSUFFIX", true));
605     pirjv.setSelected(Cache.getDefault("PIR_JVSUFFIX", true));
606     modellerOutput.setSelected(Cache.getDefault("PIR_MODELLER", false));
607     embbedBioJSON
608             .setSelected(Cache.getDefault("EXPORT_EMBBED_BIOJSON", true));
609
610     /*
611      * Set Editing tab defaults
612      */
613     autoCalculateConsCheck
614             .setSelected(Cache.getDefault("AUTO_CALC_CONSENSUS", true));
615     padGaps.setSelected(Cache.getDefault("PAD_GAPS", false));
616     sortByTree.setSelected(Cache.getDefault("SORT_BY_TREE", false));
617
618     annotations_actionPerformed(null); // update the display of the annotation
619                                        // settings
620
621     /*
622      * Set Backups tab defaults
623      */
624     loadLastSavedBackupsOptions();
625   }
626
627   /**
628    * Save user selections on the Preferences tabs to the Cache and write out to
629    * file.
630    * 
631    * @param e
632    */
633   @Override
634   public void ok_actionPerformed(ActionEvent e)
635   {
636     if (!validateSettings())
637     {
638       return;
639     }
640
641     /* 
642      * Set proxy settings first (to be before web services refresh)
643      */
644     saveProxySettings();
645
646     /*
647      * Save Visual settings
648      */
649     Cache.applicationProperties.setProperty("SHOW_JVSUFFIX",
650             Boolean.toString(seqLimit.isSelected()));
651     Cache.applicationProperties.setProperty("RIGHT_ALIGN_IDS",
652             Boolean.toString(rightAlign.isSelected()));
653     Cache.applicationProperties.setProperty("SHOW_FULLSCREEN",
654             Boolean.toString(fullScreen.isSelected()));
655     Cache.applicationProperties.setProperty("SHOW_OVERVIEW",
656             Boolean.toString(openoverv.isSelected()));
657     Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
658             Boolean.toString(annotations.isSelected()));
659     Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
660             Boolean.toString(conservation.isSelected()));
661     Cache.applicationProperties.setProperty("SHOW_QUALITY",
662             Boolean.toString(quality.isSelected()));
663     Cache.applicationProperties.setProperty("SHOW_IDENTITY",
664             Boolean.toString(identity.isSelected()));
665
666     Cache.applicationProperties.setProperty("GAP_SYMBOL",
667             gapSymbolCB.getSelectedItem().toString());
668
669     Cache.applicationProperties.setProperty("FONT_NAME",
670             fontNameCB.getSelectedItem().toString());
671     Cache.applicationProperties.setProperty("FONT_STYLE",
672             fontStyleCB.getSelectedItem().toString());
673     Cache.applicationProperties.setProperty("FONT_SIZE",
674             fontSizeCB.getSelectedItem().toString());
675
676     Cache.applicationProperties.setProperty("ID_ITALICS",
677             Boolean.toString(idItalics.isSelected()));
678     Cache.applicationProperties.setProperty("SHOW_UNCONSERVED",
679             Boolean.toString(showUnconserved.isSelected()));
680     Cache.applicationProperties.setProperty(SHOW_OCCUPANCY,
681             Boolean.toString(showOccupancy.isSelected()));
682     Cache.applicationProperties.setProperty("SHOW_GROUP_CONSENSUS",
683             Boolean.toString(showGroupConsensus.isSelected()));
684     Cache.applicationProperties.setProperty("SHOW_GROUP_CONSERVATION",
685             Boolean.toString(showGroupConservation.isSelected()));
686     Cache.applicationProperties.setProperty("SHOW_CONSENSUS_HISTOGRAM",
687             Boolean.toString(showConsensHistogram.isSelected()));
688     Cache.applicationProperties.setProperty("SHOW_CONSENSUS_LOGO",
689             Boolean.toString(showConsensLogo.isSelected()));
690     Cache.applicationProperties.setProperty("ANTI_ALIAS",
691             Boolean.toString(smoothFont.isSelected()));
692     Cache.applicationProperties.setProperty(SCALE_PROTEIN_TO_CDNA,
693             Boolean.toString(scaleProteinToCdna.isSelected()));
694     Cache.applicationProperties.setProperty("SHOW_NPFEATS_TOOLTIP",
695             Boolean.toString(showNpTooltip.isSelected()));
696     Cache.applicationProperties.setProperty("SHOW_DBREFS_TOOLTIP",
697             Boolean.toString(showDbRefTooltip.isSelected()));
698
699     Cache.applicationProperties.setProperty("WRAP_ALIGNMENT",
700             Boolean.toString(wrap.isSelected()));
701
702     Cache.applicationProperties.setProperty("STARTUP_FILE",
703             startupFileTextfield.getText());
704     Cache.applicationProperties.setProperty("SHOW_STARTUP_FILE",
705             Boolean.toString(startupCheckbox.isSelected()));
706
707     Cache.applicationProperties.setProperty("SORT_ALIGNMENT",
708             sortby.getSelectedItem().toString());
709
710     // convert description of sort order to enum name for save
711     SequenceAnnotationOrder annSortOrder = SequenceAnnotationOrder
712             .forDescription(sortAnnBy.getSelectedItem().toString());
713     if (annSortOrder != null)
714     {
715       Cache.applicationProperties.setProperty(SORT_ANNOTATIONS,
716               annSortOrder.name());
717     }
718
719     final boolean showAutocalcFirst = sortAutocalc.getSelectedIndex() == 0;
720     Cache.applicationProperties.setProperty(SHOW_AUTOCALC_ABOVE,
721             Boolean.valueOf(showAutocalcFirst).toString());
722
723     /*
724      * Save Colours settings
725      */
726     Cache.applicationProperties.setProperty(DEFAULT_COLOUR_PROT,
727             protColour.getSelectedItem().toString());
728     Cache.applicationProperties.setProperty(DEFAULT_COLOUR_NUC,
729             nucColour.getSelectedItem().toString());
730     Cache.setColourProperty("ANNOTATIONCOLOUR_MIN",
731             minColour.getBackground());
732     Cache.setColourProperty("ANNOTATIONCOLOUR_MAX",
733             maxColour.getBackground());
734
735     /*
736      * Save Overview settings
737      */
738     Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground());
739     Cache.setColourProperty(HIDDEN_COLOUR, hiddenColour.getBackground());
740     Cache.applicationProperties.setProperty(USE_LEGACY_GAP,
741             Boolean.toString(useLegacyGap.isSelected()));
742     Cache.applicationProperties.setProperty(SHOW_OV_HIDDEN_AT_START,
743             Boolean.toString(showHiddenAtStart.isSelected()));
744
745     /*
746      * Save Structure settings
747      */
748     Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN,
749             Boolean.toString(addTempFactor.isSelected()));
750     Cache.applicationProperties.setProperty(ADD_SS_ANN,
751             Boolean.toString(addSecondaryStructure.isSelected()));
752     Cache.applicationProperties.setProperty(USE_RNAVIEW,
753             Boolean.toString(useRnaView.isSelected()));
754     Cache.applicationProperties.setProperty(STRUCT_FROM_PDB,
755             Boolean.toString(structFromPdb.isSelected()));
756     Cache.applicationProperties.setProperty(STRUCTURE_DISPLAY,
757             structViewer.getSelectedItem().toString());
758     Cache.setOrRemove(CHIMERA_PATH, chimeraPath.getText());
759     Cache.applicationProperties.setProperty("MAP_WITH_SIFTS",
760             Boolean.toString(siftsMapping.isSelected()));
761     SiftsSettings.setMapWithSifts(siftsMapping.isSelected());
762
763     /*
764      * Save Output settings
765      */
766     Cache.applicationProperties.setProperty("EPS_RENDERING",
767             ((OptionsParam) epsRendering.getSelectedItem()).getCode());
768
769     /*
770      * Save Connections settings
771      */
772     // Proxy settings set first (to catch web services)
773
774     Cache.setOrRemove("DEFAULT_BROWSER", defaultBrowser.getText());
775
776     jalview.util.BrowserLauncher.resetBrowser();
777
778     // save user-defined and selected links
779     String menuLinks = sequenceUrlLinks.writeUrlsAsString(true);
780     if (menuLinks.isEmpty())
781     {
782       Cache.applicationProperties.remove("SEQUENCE_LINKS");
783     }
784     else
785     {
786       Cache.applicationProperties.setProperty("SEQUENCE_LINKS",
787               menuLinks.toString());
788     }
789
790     String nonMenuLinks = sequenceUrlLinks.writeUrlsAsString(false);
791     if (nonMenuLinks.isEmpty())
792     {
793       Cache.applicationProperties.remove("STORED_LINKS");
794     }
795     else
796     {
797       Cache.applicationProperties.setProperty("STORED_LINKS",
798               nonMenuLinks.toString());
799     }
800
801     Cache.applicationProperties.setProperty("DEFAULT_URL",
802             sequenceUrlLinks.getPrimaryUrlId());
803
804     Cache.setProperty("VERSION_CHECK",
805             Boolean.toString(versioncheck.isSelected()));
806     if (Cache.getProperty("USAGESTATS") != null || usagestats.isSelected())
807     {
808       // default is false - we only set this if the user has actively agreed
809       Cache.setProperty("USAGESTATS",
810               Boolean.toString(usagestats.isSelected()));
811     }
812     if (!questionnaire.isSelected())
813     {
814       Cache.setProperty("NOQUESTIONNAIRES", "true");
815     }
816     else
817     {
818       // special - made easy to edit a property file to disable questionnaires
819       // by just adding the given line
820       Cache.removeProperty("NOQUESTIONNAIRES");
821     }
822
823     /*
824      * Save Output settings
825      */
826     Cache.applicationProperties.setProperty("BLC_JVSUFFIX",
827             Boolean.toString(blcjv.isSelected()));
828     Cache.applicationProperties.setProperty("CLUSTAL_JVSUFFIX",
829             Boolean.toString(clustaljv.isSelected()));
830     Cache.applicationProperties.setProperty("FASTA_JVSUFFIX",
831             Boolean.toString(fastajv.isSelected()));
832     Cache.applicationProperties.setProperty("MSF_JVSUFFIX",
833             Boolean.toString(msfjv.isSelected()));
834     Cache.applicationProperties.setProperty("PFAM_JVSUFFIX",
835             Boolean.toString(pfamjv.isSelected()));
836     Cache.applicationProperties.setProperty("PILEUP_JVSUFFIX",
837             Boolean.toString(pileupjv.isSelected()));
838     Cache.applicationProperties.setProperty("PIR_JVSUFFIX",
839             Boolean.toString(pirjv.isSelected()));
840     Cache.applicationProperties.setProperty("PIR_MODELLER",
841             Boolean.toString(modellerOutput.isSelected()));
842     Cache.applicationProperties.setProperty("EXPORT_EMBBED_BIOJSON",
843             Boolean.toString(embbedBioJSON.isSelected()));
844     jalview.io.PIRFile.useModellerOutput = modellerOutput.isSelected();
845
846     Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH",
847             Boolean.toString(autoIdWidth.isSelected()));
848     userIdWidth_actionPerformed();
849     Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH",
850             userIdWidth.getText());
851
852     /*
853      * Save Editing settings
854      */
855     Cache.applicationProperties.setProperty("AUTO_CALC_CONSENSUS",
856             Boolean.toString(autoCalculateConsCheck.isSelected()));
857     Cache.applicationProperties.setProperty("SORT_BY_TREE",
858             Boolean.toString(sortByTree.isSelected()));
859     Cache.applicationProperties.setProperty("PAD_GAPS",
860             Boolean.toString(padGaps.isSelected()));
861
862     wsPrefs.updateAndRefreshWsMenuConfig(false);
863
864     /*
865      * Save Backups settings
866      */
867     Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
868             Boolean.toString(enableBackupFiles.isSelected()));
869     int preset = getComboIntStringKey(backupfilesPresetsCombo);
870     Cache.applicationProperties.setProperty(BackupFiles.NS + "_PRESET",
871             Integer.toString(preset));
872
873     if (preset == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
874     {
875       BackupFilesPresetEntry customBFPE = getBackupfilesCurrentEntry();
876       BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
877               BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM, customBFPE);
878       Cache.applicationProperties.setProperty(
879               BackupFilesPresetEntry.CUSTOMCONFIG, customBFPE.toString());
880     }
881
882     BackupFilesPresetEntry savedBFPE = BackupFilesPresetEntry.backupfilesPresetEntriesValues
883             .get(preset);
884     Cache.applicationProperties.setProperty(
885             BackupFilesPresetEntry.SAVEDCONFIG, savedBFPE.toString());
886
887     Cache.saveProperties();
888     Desktop.instance.doConfigureStructurePrefs();
889     try
890     {
891       frame.setClosed(true);
892     } catch (Exception ex)
893     {
894     }
895   }
896
897   public void saveProxySettings()
898   {
899     String newProxyType = customProxy.isSelected() ? Cache.PROXYTYPE_CUSTOM
900             : noProxy.isSelected() ? Cache.PROXYTYPE_NONE
901                     : Cache.PROXYTYPE_SYSTEM;
902     Cache.applicationProperties.setProperty("USE_PROXY", newProxyType);
903     Cache.setOrRemove("PROXY_SERVER", proxyServerHttpTB.getText());
904     Cache.setOrRemove("PROXY_PORT", proxyPortHttpTB.getText());
905     Cache.setOrRemove("PROXY_SERVER_HTTPS", proxyServerHttpsTB.getText());
906     Cache.setOrRemove("PROXY_PORT_HTTPS", proxyPortHttpsTB.getText());
907     Cache.setOrRemove("PROXY_AUTH",
908             Boolean.toString(proxyAuth.isSelected()));
909     Cache.setOrRemove("PROXY_AUTH_USERNAME", proxyAuthUsernameTB.getText());
910     Cache.proxyAuthPassword = proxyAuthPasswordPB.getPassword();
911     Cache.setProxyPropertiesFromPreferences(previousProxyType);
912     if (newProxyType.equals(Cache.PROXYTYPE_CUSTOM)
913             || !newProxyType.equals(previousProxyType))
914     {
915       // force a re-lookup of ws if proxytype is custom or has changed
916       wsPrefs.update++;
917     }
918     previousProxyType = newProxyType;
919   }
920
921   /**
922    * Do any necessary validation before saving settings. Return focus to the
923    * first tab which fails validation.
924    * 
925    * @return
926    */
927   private boolean validateSettings()
928   {
929     if (!validateStructure())
930     {
931       structureTab.requestFocusInWindow();
932       return false;
933     }
934     return true;
935   }
936
937   @Override
938   protected boolean validateStructure()
939   {
940     return validateChimeraPath();
941
942   }
943
944   /**
945    * DOCUMENT ME!
946    */
947   @Override
948   public void startupFileTextfield_mouseClicked()
949   {
950     String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
951     JalviewFileChooser chooser = JalviewFileChooser
952             .forRead(Cache.getProperty("LAST_DIRECTORY"), fileFormat);
953     chooser.setFileView(new JalviewFileView());
954     chooser.setDialogTitle(
955             MessageManager.getString("label.select_startup_file"));
956
957     int value = chooser.showOpenDialog(this);
958
959     if (value == JalviewFileChooser.APPROVE_OPTION)
960     {
961       FileFormatI format = chooser.getSelectedFormat();
962       if (format != null)
963       {
964         Cache.applicationProperties.setProperty("DEFAULT_FILE_FORMAT",
965                 format.getName());
966       }
967       startupFileTextfield
968               .setText(chooser.getSelectedFile().getAbsolutePath());
969     }
970   }
971
972   /**
973    * DOCUMENT ME!
974    * 
975    * @param e
976    *          DOCUMENT ME!
977    */
978   @Override
979   public void cancel_actionPerformed(ActionEvent e)
980   {
981     try
982     {
983       wsPrefs.updateWsMenuConfig(true);
984       wsPrefs.refreshWs_actionPerformed(e);
985       frame.setClosed(true);
986     } catch (Exception ex)
987     {
988     }
989   }
990
991   /**
992    * DOCUMENT ME!
993    * 
994    * @param e
995    *          DOCUMENT ME!
996    */
997   @Override
998   public void annotations_actionPerformed(ActionEvent e)
999   {
1000     conservation.setEnabled(annotations.isSelected());
1001     quality.setEnabled(annotations.isSelected());
1002     identity.setEnabled(annotations.isSelected());
1003     showOccupancy.setEnabled(annotations.isSelected());
1004     showGroupConsensus.setEnabled(annotations.isSelected());
1005     showGroupConservation.setEnabled(annotations.isSelected());
1006     showConsensHistogram.setEnabled(annotations.isSelected()
1007             && (identity.isSelected() || showGroupConsensus.isSelected()));
1008     showConsensLogo.setEnabled(annotations.isSelected()
1009             && (identity.isSelected() || showGroupConsensus.isSelected()));
1010   }
1011
1012   @Override
1013   public void newLink_actionPerformed(ActionEvent e)
1014   {
1015     GSequenceLink link = new GSequenceLink();
1016     boolean valid = false;
1017     while (!valid)
1018     {
1019       if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link,
1020               MessageManager.getString("label.new_sequence_url_link"),
1021               JvOptionPane.OK_CANCEL_OPTION, -1,
1022               null) == JvOptionPane.OK_OPTION)
1023       {
1024         if (link.checkValid())
1025         {
1026           if (((UrlLinkTableModel) linkUrlTable.getModel())
1027                   .isUniqueName(link.getName()))
1028           {
1029             ((UrlLinkTableModel) linkUrlTable.getModel())
1030                     .insertRow(link.getName(), link.getURL());
1031             valid = true;
1032           }
1033           else
1034           {
1035             link.notifyDuplicate();
1036             continue;
1037           }
1038         }
1039       }
1040       else
1041       {
1042         break;
1043       }
1044     }
1045   }
1046
1047   @Override
1048   public void editLink_actionPerformed(ActionEvent e)
1049   {
1050     GSequenceLink link = new GSequenceLink();
1051
1052     int index = linkUrlTable.getSelectedRow();
1053     if (index == -1)
1054     {
1055       // button no longer enabled if row is not selected
1056       Cache.log.debug("Edit with no row selected in linkUrlTable");
1057       return;
1058     }
1059
1060     int nameCol = ((UrlLinkTableModel) linkUrlTable.getModel())
1061             .getNameColumn();
1062     int urlCol = ((UrlLinkTableModel) linkUrlTable.getModel())
1063             .getUrlColumn();
1064     String oldName = linkUrlTable.getValueAt(index, nameCol).toString();
1065     link.setName(oldName);
1066     link.setURL(linkUrlTable.getValueAt(index, urlCol).toString());
1067
1068     boolean valid = false;
1069     while (!valid)
1070     {
1071       if (JvOptionPane.showInternalConfirmDialog(Desktop.desktop, link,
1072               MessageManager.getString("label.edit_sequence_url_link"),
1073               JvOptionPane.OK_CANCEL_OPTION, -1,
1074               null) == JvOptionPane.OK_OPTION)
1075       {
1076         if (link.checkValid())
1077         {
1078           if ((oldName.equals(link.getName()))
1079                   || (((UrlLinkTableModel) linkUrlTable.getModel())
1080                           .isUniqueName(link.getName())))
1081           {
1082             linkUrlTable.setValueAt(link.getName(), index, nameCol);
1083             linkUrlTable.setValueAt(link.getURL(), index, urlCol);
1084             valid = true;
1085           }
1086           else
1087           {
1088             link.notifyDuplicate();
1089             continue;
1090           }
1091         }
1092       }
1093       else
1094       {
1095         break;
1096       }
1097     }
1098   }
1099
1100   @Override
1101   public void deleteLink_actionPerformed(ActionEvent e)
1102   {
1103     int index = linkUrlTable.getSelectedRow();
1104     int modelIndex = -1;
1105     if (index == -1)
1106     {
1107       // button no longer enabled if row is not selected
1108       Cache.log.debug("Delete with no row selected in linkUrlTable");
1109       return;
1110     }
1111     else
1112     {
1113       modelIndex = linkUrlTable.convertRowIndexToModel(index);
1114     }
1115
1116     // make sure we use the model index to delete, and not the table index
1117     ((UrlLinkTableModel) linkUrlTable.getModel()).removeRow(modelIndex);
1118   }
1119
1120   @Override
1121   public void defaultBrowser_mouseClicked(MouseEvent e)
1122   {
1123     JFileChooser chooser = new JFileChooser(".");
1124     chooser.setDialogTitle(
1125             MessageManager.getString("label.select_default_browser"));
1126
1127     int value = chooser.showOpenDialog(this);
1128
1129     if (value == JFileChooser.APPROVE_OPTION)
1130     {
1131       defaultBrowser.setText(chooser.getSelectedFile().getAbsolutePath());
1132     }
1133
1134   }
1135
1136   /*
1137    * (non-Javadoc)
1138    * 
1139    * @see
1140    * jalview.jbgui.GPreferences#showunconserved_actionPerformed(java.awt.event
1141    * .ActionEvent)
1142    */
1143   @Override
1144   protected void showunconserved_actionPerformed(ActionEvent e)
1145   {
1146     // TODO Auto-generated method stub
1147     super.showunconserved_actionPerformed(e);
1148   }
1149
1150   public static List<String> getGroupURLLinks()
1151   {
1152     return groupURLLinks;
1153   }
1154
1155   @Override
1156   public void minColour_actionPerformed(JPanel panel)
1157   {
1158     Color col = JColorChooser.showDialog(this,
1159             MessageManager.getString("label.select_colour_minimum_value"),
1160             minColour.getBackground());
1161     if (col != null)
1162     {
1163       panel.setBackground(col);
1164     }
1165     panel.repaint();
1166   }
1167
1168   @Override
1169   public void maxColour_actionPerformed(JPanel panel)
1170   {
1171     Color col = JColorChooser.showDialog(this,
1172             MessageManager.getString("label.select_colour_maximum_value"),
1173             maxColour.getBackground());
1174     if (col != null)
1175     {
1176       panel.setBackground(col);
1177     }
1178     panel.repaint();
1179   }
1180
1181   @Override
1182   public void gapColour_actionPerformed(JPanel gap)
1183   {
1184     if (!useLegacyGap.isSelected())
1185     {
1186       Color col = JColorChooser.showDialog(this,
1187               MessageManager.getString("label.select_gap_colour"),
1188               gapColour.getBackground());
1189       if (col != null)
1190       {
1191         gap.setBackground(col);
1192       }
1193       gap.repaint();
1194     }
1195   }
1196
1197   @Override
1198   public void hiddenColour_actionPerformed(JPanel hidden)
1199   {
1200     Color col = JColorChooser.showDialog(this,
1201             MessageManager.getString("label.select_hidden_colour"),
1202             hiddenColour.getBackground());
1203     if (col != null)
1204     {
1205       hidden.setBackground(col);
1206     }
1207     hidden.repaint();
1208   }
1209
1210   @Override
1211   protected void useLegacyGaps_actionPerformed(ActionEvent e)
1212   {
1213     boolean enabled = useLegacyGap.isSelected();
1214     if (enabled)
1215     {
1216       gapColour.setBackground(
1217               jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_LEGACY_GAP);
1218     }
1219     else
1220     {
1221       gapColour.setBackground(
1222               jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP);
1223     }
1224     gapColour.setEnabled(!enabled);
1225     gapLabel.setEnabled(!enabled);
1226   }
1227
1228   @Override
1229   protected void resetOvDefaults_actionPerformed(ActionEvent e)
1230   {
1231     useLegacyGap.setSelected(false);
1232     useLegacyGaps_actionPerformed(null);
1233     showHiddenAtStart.setSelected(false);
1234     hiddenColour.setBackground(
1235             jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_HIDDEN);
1236   }
1237
1238   @Override
1239   protected void userIdWidth_actionPerformed()
1240   {
1241     try
1242     {
1243       String val = userIdWidth.getText().trim();
1244       if (val.length() > 0)
1245       {
1246         Integer iw = Integer.parseInt(val);
1247         if (iw.intValue() < 12)
1248         {
1249           throw new NumberFormatException();
1250         }
1251         userIdWidth.setText(iw.toString());
1252       }
1253     } catch (NumberFormatException x)
1254     {
1255       JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1256               MessageManager
1257                       .getString("warn.user_defined_width_requirements"),
1258               MessageManager.getString("label.invalid_id_column_width"),
1259               JvOptionPane.WARNING_MESSAGE);
1260       userIdWidth.setText("");
1261     }
1262   }
1263
1264   @Override
1265   protected void autoIdWidth_actionPerformed()
1266   {
1267     userIdWidth.setEnabled(!autoIdWidth.isSelected());
1268     userIdWidthlabel.setEnabled(!autoIdWidth.isSelected());
1269   }
1270
1271   /**
1272    * Returns true if chimera path is to a valid executable, else show an error
1273    * dialog.
1274    */
1275   private boolean validateChimeraPath()
1276   {
1277     if (chimeraPath.getText().trim().length() > 0)
1278     {
1279       File f = new File(chimeraPath.getText());
1280       if (!f.canExecute())
1281       {
1282         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
1283                 MessageManager.getString("label.invalid_chimera_path"),
1284                 MessageManager.getString("label.invalid_name"),
1285                 JvOptionPane.ERROR_MESSAGE);
1286         return false;
1287       }
1288     }
1289     return true;
1290   }
1291
1292   /**
1293    * If Chimera is selected, check it can be found on default or user-specified
1294    * path, if not show a warning/help dialog.
1295    */
1296   @Override
1297   protected void structureViewer_actionPerformed(String selectedItem)
1298   {
1299     if (!selectedItem.equals(ViewerType.CHIMERA.name()))
1300     {
1301       return;
1302     }
1303     boolean found = false;
1304
1305     /*
1306      * Try user-specified and standard paths for Chimera executable.
1307      */
1308     List<String> paths = StructureManager.getChimeraPaths();
1309     paths.add(0, chimeraPath.getText());
1310     for (String path : paths)
1311     {
1312       if (new File(path.trim()).canExecute())
1313       {
1314         found = true;
1315         break;
1316       }
1317     }
1318     if (!found)
1319     {
1320       String[] options = { "OK", "Help" };
1321       int showHelp = JvOptionPane.showInternalOptionDialog(Desktop.desktop,
1322               JvSwingUtils.wrapTooltip(true,
1323                       MessageManager.getString("label.chimera_missing")),
1324               "", JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE,
1325               null, options, options[0]);
1326       if (showHelp == JvOptionPane.NO_OPTION)
1327       {
1328         try
1329         {
1330           Help.showHelpWindow(HelpId.StructureViewer);
1331         } catch (HelpSetException e)
1332         {
1333           e.printStackTrace();
1334         }
1335       }
1336     }
1337   }
1338
1339   public class OptionsParam
1340   {
1341     private String name;
1342
1343     private String code;
1344
1345     public OptionsParam(String name, String code)
1346     {
1347       this.name = name;
1348       this.code = code;
1349     }
1350
1351     public String getName()
1352     {
1353       return name;
1354     }
1355
1356     public void setName(String name)
1357     {
1358       this.name = name;
1359     }
1360
1361     public String getCode()
1362     {
1363       return code;
1364     }
1365
1366     public void setCode(String code)
1367     {
1368       this.code = code;
1369     }
1370
1371     @Override
1372     public String toString()
1373     {
1374       return name;
1375     }
1376
1377     @Override
1378     public boolean equals(Object that)
1379     {
1380       if (!(that instanceof OptionsParam))
1381       {
1382         return false;
1383       }
1384       return this.code.equalsIgnoreCase(((OptionsParam) that).code);
1385     }
1386
1387     @Override
1388     public int hashCode()
1389     {
1390       return name.hashCode() + code.hashCode();
1391     }
1392   }
1393
1394   private class UrlListSelectionHandler implements ListSelectionListener
1395   {
1396
1397     @Override
1398     public void valueChanged(ListSelectionEvent e)
1399     {
1400       ListSelectionModel lsm = (ListSelectionModel) e.getSource();
1401
1402       int index = lsm.getMinSelectionIndex();
1403       if (index == -1)
1404       {
1405         // no selection, so disable delete/edit buttons
1406         editLink.setEnabled(false);
1407         deleteLink.setEnabled(false);
1408         return;
1409       }
1410       int modelIndex = linkUrlTable.convertRowIndexToModel(index);
1411
1412       // enable/disable edit and delete link buttons
1413       if (((UrlLinkTableModel) linkUrlTable.getModel())
1414               .isRowDeletable(modelIndex))
1415       {
1416         deleteLink.setEnabled(true);
1417       }
1418       else
1419       {
1420         deleteLink.setEnabled(false);
1421       }
1422
1423       if (((UrlLinkTableModel) linkUrlTable.getModel())
1424               .isRowEditable(modelIndex))
1425       {
1426         editLink.setEnabled(true);
1427       }
1428       else
1429       {
1430         editLink.setEnabled(false);
1431       }
1432     }
1433   }
1434
1435 }