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