JAL-3551 concatenate colour by sequence commands for all except PyMOL
[jalview.git] / src / jalview / jbgui / GPreferences.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.jbgui;
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.FlowLayout;
28 import java.awt.Font;
29 import java.awt.GridBagConstraints;
30 import java.awt.GridBagLayout;
31 import java.awt.GridLayout;
32 import java.awt.Insets;
33 import java.awt.Rectangle;
34 import java.awt.event.ActionEvent;
35 import java.awt.event.ActionListener;
36 import java.awt.event.FocusEvent;
37 import java.awt.event.KeyEvent;
38 import java.awt.event.KeyListener;
39 import java.awt.event.MouseAdapter;
40 import java.awt.event.MouseEvent;
41 import java.util.Arrays;
42 import java.util.List;
43
44 import javax.swing.AbstractCellEditor;
45 import javax.swing.BorderFactory;
46 import javax.swing.ButtonGroup;
47 import javax.swing.DefaultListCellRenderer;
48 import javax.swing.JButton;
49 import javax.swing.JCheckBox;
50 import javax.swing.JComboBox;
51 import javax.swing.JFileChooser;
52 import javax.swing.JLabel;
53 import javax.swing.JPanel;
54 import javax.swing.JRadioButton;
55 import javax.swing.JScrollPane;
56 import javax.swing.JSpinner;
57 import javax.swing.JTabbedPane;
58 import javax.swing.JTable;
59 import javax.swing.JTextArea;
60 import javax.swing.JTextField;
61 import javax.swing.ListSelectionModel;
62 import javax.swing.SpinnerModel;
63 import javax.swing.SpinnerNumberModel;
64 import javax.swing.SwingConstants;
65 import javax.swing.border.Border;
66 import javax.swing.border.EmptyBorder;
67 import javax.swing.border.EtchedBorder;
68 import javax.swing.border.TitledBorder;
69 import javax.swing.event.ChangeEvent;
70 import javax.swing.event.ChangeListener;
71 import javax.swing.table.TableCellEditor;
72 import javax.swing.table.TableCellRenderer;
73
74 import jalview.bin.Cache;
75 import jalview.fts.core.FTSDataColumnPreferences;
76 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
77 import jalview.fts.service.pdb.PDBFTSRestClient;
78 import jalview.gui.Desktop;
79 import jalview.gui.JalviewBooleanRadioButtons;
80 import jalview.gui.JvOptionPane;
81 import jalview.gui.JvSwingUtils;
82 import jalview.gui.StructureViewer.ViewerType;
83 import jalview.io.BackupFilenameParts;
84 import jalview.io.BackupFiles;
85 import jalview.io.BackupFilesPresetEntry;
86 import jalview.io.IntKeyStringValueEntry;
87 import jalview.util.MessageManager;
88
89 /**
90  * Base class for the Preferences panel.
91  * 
92  * @author $author$
93  * @version $Revision$
94  */
95 public class GPreferences extends JPanel
96 {
97   private static final Font LABEL_FONT = JvSwingUtils.getLabelFont();
98
99   private static final Font LABEL_FONT_ITALIC = JvSwingUtils
100           .getLabelFont(false, true);
101
102   private static final Font LABEL_FONT_BOLD = JvSwingUtils
103           .getLabelFont(true, false);
104
105   /*
106    * Visual tab components
107    */
108   protected JCheckBox fullScreen = new JCheckBox();
109
110   protected JCheckBox openoverv = new JCheckBox();
111
112   protected JCheckBox seqLimit = new JCheckBox();
113
114   protected JCheckBox rightAlign = new JCheckBox();
115
116   protected JComboBox<String> fontSizeCB = new JComboBox<>();
117
118   protected JComboBox<String> fontStyleCB = new JComboBox<>();
119
120   protected JComboBox<String> fontNameCB = new JComboBox<>();
121
122   protected JCheckBox showOccupancy = new JCheckBox();
123
124   protected JCheckBox showUnconserved = new JCheckBox();
125
126   protected JCheckBox idItalics = new JCheckBox();
127
128   protected JCheckBox smoothFont = new JCheckBox();
129
130   protected JCheckBox scaleProteinToCdna = new JCheckBox();
131
132   protected JComboBox<String> gapSymbolCB = new JComboBox<>();
133
134   protected JCheckBox wrap = new JCheckBox();
135
136   protected JComboBox<String> sortby = new JComboBox<>();
137
138   protected JComboBox<String> sortAnnBy = new JComboBox<>();
139
140   protected JComboBox<String> sortAutocalc = new JComboBox<>();
141
142   protected JCheckBox startupCheckbox = new JCheckBox();
143
144   protected JTextField startupFileTextfield = new JTextField();
145
146   // below are in the 'second column'
147   protected JCheckBox annotations = new JCheckBox();
148
149   protected JCheckBox quality = new JCheckBox();
150
151   protected JCheckBox conservation = new JCheckBox();
152
153   protected JCheckBox identity = new JCheckBox();
154
155   protected JCheckBox showGroupConsensus = new JCheckBox();
156
157   protected JCheckBox showGroupConservation = new JCheckBox();
158
159   protected JCheckBox showConsensHistogram = new JCheckBox();
160
161   protected JCheckBox showConsensLogo = new JCheckBox();
162
163   protected JCheckBox showDbRefTooltip = new JCheckBox();
164
165   protected JCheckBox showNpTooltip = new JCheckBox();
166
167   /*
168    * Structure tab and components
169    */
170   protected JPanel structureTab;
171
172   protected JCheckBox structFromPdb = new JCheckBox();
173
174   protected JCheckBox useRnaView = new JCheckBox();
175
176   protected JCheckBox addSecondaryStructure = new JCheckBox();
177
178   protected JCheckBox addTempFactor = new JCheckBox();
179
180   protected JComboBox<String> structViewer = new JComboBox<>();
181
182   protected JLabel structureViewerPathLabel;
183
184   protected JTextField structureViewerPath = new JTextField();
185
186   protected ButtonGroup mappingMethod = new ButtonGroup();
187
188   protected JRadioButton siftsMapping = new JRadioButton();
189
190   protected JRadioButton nwMapping = new JRadioButton();
191
192   /*
193    * Colours tab components
194    */
195   protected JPanel minColour = new JPanel();
196
197   protected JPanel maxColour = new JPanel();
198
199   protected JComboBox<String> protColour = new JComboBox<>();
200
201   protected JComboBox<String> nucColour = new JComboBox<>();
202
203   /*
204    * Overview tab components
205    */
206   protected JPanel gapColour = new JPanel();
207
208   protected JPanel hiddenColour = new JPanel();
209
210   protected JCheckBox useLegacyGap;
211
212   protected JCheckBox showHiddenAtStart;
213
214   protected JLabel gapLabel;
215
216   /*
217    * Connections tab components
218    */
219   protected JTable linkUrlTable = new JTable();
220
221   protected JButton editLink = new JButton();
222
223   protected JButton deleteLink = new JButton();
224
225   protected JTextField filterTB = new JTextField();
226
227   protected JButton doReset = new JButton();
228
229   protected JButton userOnly = new JButton();
230
231   protected JLabel portLabel = new JLabel();
232
233   protected JLabel serverLabel = new JLabel();
234
235   protected JTextField proxyServerTB = new JTextField();
236
237   protected JTextField proxyPortTB = new JTextField();
238
239   protected JTextField defaultBrowser = new JTextField();
240
241   protected JCheckBox useProxy = new JCheckBox();
242
243   protected JCheckBox usagestats = new JCheckBox();
244
245   protected JCheckBox questionnaire = new JCheckBox();
246
247   protected JCheckBox versioncheck = new JCheckBox();
248
249   /*
250    * Output tab components
251    */
252   protected JComboBox<Object> epsRendering = new JComboBox<>();
253
254   protected JLabel userIdWidthlabel = new JLabel();
255
256   protected JCheckBox autoIdWidth = new JCheckBox();
257
258   protected JTextField userIdWidth = new JTextField();
259
260   protected JCheckBox blcjv = new JCheckBox();
261
262   protected JCheckBox pileupjv = new JCheckBox();
263
264   protected JCheckBox clustaljv = new JCheckBox();
265
266   protected JCheckBox msfjv = new JCheckBox();
267
268   protected JCheckBox fastajv = new JCheckBox();
269
270   protected JCheckBox pfamjv = new JCheckBox();
271
272   protected JCheckBox pirjv = new JCheckBox();
273
274   protected JCheckBox modellerOutput = new JCheckBox();
275
276   protected JCheckBox embbedBioJSON = new JCheckBox();
277
278   /*
279    * Editing tab components
280    */
281   protected JCheckBox autoCalculateConsCheck = new JCheckBox();
282
283   protected JCheckBox padGaps = new JCheckBox();
284
285   protected JCheckBox sortByTree = new JCheckBox();
286
287   /*
288    * Web Services tab
289    */
290   protected JPanel wsTab = new JPanel();
291
292   /*
293    * Backups tab components
294    * a lot of these are member variables instead of local variables only so that they
295    * can be enabled/disabled easily in one go
296    */
297
298   protected JCheckBox enableBackupFiles = new JCheckBox();
299
300   protected JPanel presetsPanel = new JPanel();
301
302   protected JLabel presetsComboLabel = new JLabel();
303
304   protected JCheckBox customiseCheckbox = new JCheckBox();
305
306   protected JButton revertButton = new JButton();
307
308   protected JComboBox<Object> backupfilesPresetsCombo = new JComboBox<>();
309
310   private int backupfilesPresetsComboLastSelected = 0;
311
312   protected JPanel suffixPanel = new JPanel();
313
314   protected JPanel keepfilesPanel = new JPanel();
315
316   protected JPanel exampleFilesPanel = new JPanel();
317
318   protected JTextField suffixTemplate = new JTextField(null, 8);
319
320   protected JLabel suffixTemplateLabel = new JLabel();
321
322   protected JLabel suffixDigitsLabel = new JLabel();
323
324   protected JSpinner suffixDigitsSpinner = new JSpinner();
325
326   protected JalviewBooleanRadioButtons suffixReverse = new JalviewBooleanRadioButtons();
327
328   protected JalviewBooleanRadioButtons backupfilesKeepAll = new JalviewBooleanRadioButtons();
329
330   public JSpinner backupfilesRollMaxSpinner = new JSpinner();
331
332   protected JLabel oldBackupFilesLabel = new JLabel();
333
334   protected JalviewBooleanRadioButtons backupfilesConfirmDelete = new JalviewBooleanRadioButtons();
335
336   protected JTextArea backupfilesExampleLabel = new JTextArea();
337
338   /**
339    * Creates a new GPreferences object.
340    */
341   public GPreferences()
342   {
343     try
344     {
345       jbInit();
346     } catch (Exception ex)
347     {
348       ex.printStackTrace();
349     }
350   }
351
352   /**
353    * Construct the panel and its tabbed sub-panels.
354    * 
355    * @throws Exception
356    */
357   private void jbInit() throws Exception
358   {
359     final JTabbedPane tabbedPane = new JTabbedPane();
360     this.setLayout(new BorderLayout());
361     JPanel okCancelPanel = initOkCancelPanel();
362     this.add(tabbedPane, BorderLayout.CENTER);
363     this.add(okCancelPanel, BorderLayout.SOUTH);
364
365     tabbedPane.add(initVisualTab(),
366             MessageManager.getString("label.visual"));
367
368     tabbedPane.add(initColoursTab(),
369             MessageManager.getString("label.colours"));
370
371     tabbedPane.add(initOverviewTab(),
372             MessageManager.getString("label.overview"));
373
374     tabbedPane.add(initStructureTab(),
375             MessageManager.getString("label.structure"));
376
377     tabbedPane.add(initConnectionsTab(),
378             MessageManager.getString("label.connections"));
379
380     tabbedPane.add(initBackupsTab(),
381             MessageManager.getString("label.backups"));
382
383     tabbedPane.add(initLinksTab(),
384             MessageManager.getString("label.urllinks"));
385
386     tabbedPane.add(initOutputTab(),
387             MessageManager.getString("label.output"));
388
389     tabbedPane.add(initEditingTab(),
390             MessageManager.getString("label.editing"));
391
392     /*
393      * See WsPreferences for the real work of configuring this tab.
394      */
395     wsTab.setLayout(new BorderLayout());
396     tabbedPane.add(wsTab, MessageManager.getString("label.web_services"));
397
398     /*
399      * Handler to validate a tab before leaving it - currently only for
400      * Structure.
401      */
402     tabbedPane.addChangeListener(new ChangeListener()
403     {
404       private Component lastTab;
405
406       @Override
407       public void stateChanged(ChangeEvent e)
408       {
409         if (lastTab == structureTab
410                 && tabbedPane.getSelectedComponent() != structureTab)
411         {
412           if (!validateStructure())
413           {
414             tabbedPane.setSelectedComponent(structureTab);
415             return;
416           }
417         }
418         lastTab = tabbedPane.getSelectedComponent();
419       }
420
421     });
422   }
423
424   /**
425    * Initialises the Editing tabbed panel.
426    * 
427    * @return
428    */
429   private JPanel initEditingTab()
430   {
431     JPanel editingTab = new JPanel();
432     editingTab.setLayout(null);
433     autoCalculateConsCheck.setFont(LABEL_FONT);
434     autoCalculateConsCheck.setText(
435             MessageManager.getString("label.autocalculate_consensus"));
436     autoCalculateConsCheck.setBounds(new Rectangle(21, 52, 209, 23));
437     padGaps.setFont(LABEL_FONT);
438     padGaps.setText(
439             MessageManager.getString("label.pad_gaps_when_editing"));
440     padGaps.setBounds(new Rectangle(22, 94, 168, 23));
441     sortByTree.setFont(LABEL_FONT);
442     sortByTree
443             .setText(MessageManager.getString("label.sort_with_new_tree"));
444     sortByTree.setToolTipText(MessageManager.getString(
445             "label.any_trees_calculated_or_loaded_alignment_automatically_sort"));
446     sortByTree.setBounds(new Rectangle(22, 136, 168, 23));
447     editingTab.add(autoCalculateConsCheck);
448     editingTab.add(padGaps);
449     editingTab.add(sortByTree);
450     return editingTab;
451   }
452
453   /**
454    * Initialises the Output tabbed panel.
455    * 
456    * @return
457    */
458   private JPanel initOutputTab()
459   {
460     JPanel outputTab = new JPanel();
461     outputTab.setLayout(null);
462     JLabel epsLabel = new JLabel();
463     epsLabel.setFont(LABEL_FONT);
464     epsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
465     epsLabel.setText(MessageManager.getString("label.eps_rendering_style"));
466     epsLabel.setBounds(new Rectangle(9, 31, 140, 24));
467     epsRendering.setFont(LABEL_FONT);
468     epsRendering.setBounds(new Rectangle(154, 34, 187, 21));
469     JLabel jLabel1 = new JLabel();
470     jLabel1.setFont(LABEL_FONT);
471     jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
472     jLabel1.setText(MessageManager.getString("label.append_start_end"));
473     jLabel1.setFont(LABEL_FONT);
474     fastajv.setFont(LABEL_FONT);
475     fastajv.setHorizontalAlignment(SwingConstants.LEFT);
476     clustaljv.setText(MessageManager.getString("label.clustal") + "     ");
477     blcjv.setText(MessageManager.getString("label.blc") + "     ");
478     fastajv.setText(MessageManager.getString("label.fasta") + "     ");
479     msfjv.setText(MessageManager.getString("label.msf") + "     ");
480     pfamjv.setText(MessageManager.getString("label.pfam") + "     ");
481     pileupjv.setText(MessageManager.getString("label.pileup") + "     ");
482     msfjv.setFont(LABEL_FONT);
483     msfjv.setHorizontalAlignment(SwingConstants.LEFT);
484     pirjv.setText(MessageManager.getString("label.pir") + "     ");
485     JPanel jPanel11 = new JPanel();
486     jPanel11.setFont(LABEL_FONT);
487     TitledBorder titledBorder2 = new TitledBorder(
488             MessageManager.getString("label.file_output"));
489     jPanel11.setBorder(titledBorder2);
490     jPanel11.setBounds(new Rectangle(30, 72, 196, 182));
491     GridLayout gridLayout3 = new GridLayout();
492     jPanel11.setLayout(gridLayout3);
493     gridLayout3.setRows(8);
494     blcjv.setFont(LABEL_FONT);
495     blcjv.setHorizontalAlignment(SwingConstants.LEFT);
496     clustaljv.setFont(LABEL_FONT);
497     clustaljv.setHorizontalAlignment(SwingConstants.LEFT);
498     pfamjv.setFont(LABEL_FONT);
499     pfamjv.setHorizontalAlignment(SwingConstants.LEFT);
500     pileupjv.setFont(LABEL_FONT);
501     pileupjv.setHorizontalAlignment(SwingConstants.LEFT);
502     pirjv.setFont(LABEL_FONT);
503     pirjv.setHorizontalAlignment(SwingConstants.LEFT);
504     autoIdWidth.setFont(LABEL_FONT);
505     autoIdWidth.setText(
506             MessageManager.getString("label.automatically_set_id_width"));
507     autoIdWidth.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager
508             .getString("label.adjusts_width_generated_eps_png")));
509     autoIdWidth.setBounds(new Rectangle(228, 96, 188, 23));
510     autoIdWidth.addActionListener(new ActionListener()
511     {
512
513       @Override
514       public void actionPerformed(ActionEvent e)
515       {
516         autoIdWidth_actionPerformed();
517       }
518     });
519     userIdWidthlabel.setFont(LABEL_FONT);
520     userIdWidthlabel.setText(
521             MessageManager.getString("label.figure_id_column_width"));
522     userIdWidth.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager
523             .getString("label.manually_specify_width_left_column")));
524     userIdWidthlabel.setToolTipText(
525             JvSwingUtils.wrapTooltip(true, MessageManager.getString(
526                     "label.manually_specify_width_left_column")));
527     userIdWidthlabel.setBounds(new Rectangle(236, 120, 168, 23));
528     userIdWidth.setFont(JvSwingUtils.getTextAreaFont());
529     userIdWidth.setText("");
530     userIdWidth.setBounds(new Rectangle(232, 144, 84, 23));
531     userIdWidth.addActionListener(new ActionListener()
532     {
533
534       @Override
535       public void actionPerformed(ActionEvent e)
536       {
537         userIdWidth_actionPerformed();
538       }
539     });
540     modellerOutput.setFont(LABEL_FONT);
541     modellerOutput
542             .setText(MessageManager.getString("label.use_modeller_output"));
543     modellerOutput.setBounds(new Rectangle(228, 226, 168, 23));
544     embbedBioJSON.setFont(LABEL_FONT);
545     embbedBioJSON.setText(MessageManager.getString("label.embbed_biojson"));
546     embbedBioJSON.setBounds(new Rectangle(228, 200, 250, 23));
547
548     jPanel11.add(jLabel1);
549     jPanel11.add(blcjv);
550     jPanel11.add(clustaljv);
551     jPanel11.add(fastajv);
552     jPanel11.add(msfjv);
553     jPanel11.add(pfamjv);
554     jPanel11.add(pileupjv);
555     jPanel11.add(pirjv);
556     outputTab.add(autoIdWidth);
557     outputTab.add(userIdWidth);
558     outputTab.add(userIdWidthlabel);
559     outputTab.add(modellerOutput);
560     outputTab.add(embbedBioJSON);
561     outputTab.add(epsLabel);
562     outputTab.add(epsRendering);
563     outputTab.add(jPanel11);
564     return outputTab;
565   }
566
567   /**
568    * Initialises the Connections tabbed panel.
569    * 
570    * @return
571    */
572   private JPanel initConnectionsTab()
573   {
574     JPanel connectTab = new JPanel();
575     connectTab.setLayout(new GridBagLayout());
576
577     // Label for browser text box
578     JLabel browserLabel = new JLabel();
579     browserLabel.setFont(LABEL_FONT);
580     browserLabel.setHorizontalAlignment(SwingConstants.TRAILING);
581     browserLabel.setText(
582             MessageManager.getString("label.default_browser_unix"));
583     defaultBrowser.setFont(LABEL_FONT);
584     defaultBrowser.setText("");
585     final String tooltip = JvSwingUtils.wrapTooltip(true,
586             MessageManager.getString("label.double_click_to_browse"));
587     defaultBrowser.setToolTipText(tooltip);
588     defaultBrowser.addMouseListener(new MouseAdapter()
589     {
590       @Override
591       public void mouseClicked(MouseEvent e)
592       {
593         if (e.getClickCount() > 1)
594         {
595           defaultBrowser_mouseClicked(e);
596         }
597       }
598     });
599
600     JPanel proxyPanel = initConnTabProxyPanel();
601     initConnTabCheckboxes();
602
603     // Add default Browser text box
604     connectTab.add(browserLabel,
605             new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
606                     GridBagConstraints.WEST, GridBagConstraints.NONE,
607                     new Insets(10, 0, 5, 5), 5, 1));
608     defaultBrowser.setFont(LABEL_FONT);
609     defaultBrowser.setText("");
610
611     connectTab.add(defaultBrowser, new GridBagConstraints(1, 0, 1, 1, 1.0,
612             0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
613             new Insets(10, 0, 5, 10), 30, 1));
614
615     // Add proxy server panel
616     connectTab.add(proxyPanel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0,
617             GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
618             new Insets(10, 0, 5, 12), 4, 10));
619
620     // Add usage stats, version check and questionnaire checkboxes
621     connectTab.add(usagestats,
622             new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0,
623                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
624                     new Insets(0, 2, 5, 5), 70, 1));
625     connectTab.add(questionnaire,
626             new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0,
627                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
628                     new Insets(0, 2, 5, 10), 70, 1));
629     connectTab.add(versioncheck,
630             new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0,
631                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
632                     new Insets(0, 2, 5, 5), 70, 1));
633
634     versioncheck.setVisible(false);
635
636     // Add padding so the panel doesn't look ridiculous
637     JPanel spacePanel = new JPanel();
638     connectTab.add(spacePanel,
639             new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0,
640                     GridBagConstraints.WEST, GridBagConstraints.BOTH,
641                     new Insets(0, 0, 0, 5), 70, 1));
642
643     return connectTab;
644   }
645
646   /**
647    * Initialises the Links tabbed panel.
648    * 
649    * @return
650    */
651   private JPanel initLinksTab()
652   {
653     JPanel linkTab = new JPanel();
654     linkTab.setLayout(new GridBagLayout());
655
656     // Set up table for Url links
657     linkUrlTable.getTableHeader().setReorderingAllowed(false);
658     linkUrlTable.setFillsViewportHeight(true);
659     linkUrlTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
660     linkUrlTable.setAutoCreateRowSorter(true);
661     linkUrlTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
662
663     // adjust row height so radio buttons actually fit
664     // don't do this in the renderer, it causes the awt thread to activate
665     // constantly
666     JRadioButton temp = new JRadioButton();
667     linkUrlTable.setRowHeight(temp.getMinimumSize().height);
668
669     // Table in scrollpane so that the table is given a scrollbar
670     JScrollPane linkScrollPane = new JScrollPane(linkUrlTable);
671     linkScrollPane.setBorder(null);
672
673     // Panel for links functionality
674     JPanel linkPanel = new JPanel(new GridBagLayout());
675     linkPanel.setBorder(new TitledBorder(
676             MessageManager.getString("label.url_linkfrom_sequence_id")));
677
678     // Put the Url links panel together
679
680     // Buttons go at top right, resizing only resizes the blank space vertically
681     JPanel buttonPanel = initLinkTabUrlButtons();
682     GridBagConstraints linkConstraints1 = new GridBagConstraints();
683     linkConstraints1.insets = new Insets(0, 0, 5, 0);
684     linkConstraints1.gridx = 0;
685     linkConstraints1.gridy = 0;
686     linkConstraints1.weightx = 1.0;
687     linkConstraints1.fill = GridBagConstraints.HORIZONTAL;
688     linkTab.add(buttonPanel, linkConstraints1);
689
690     // Links table goes at top left, resizing resizes the table
691     GridBagConstraints linkConstraints2 = new GridBagConstraints();
692     linkConstraints2.insets = new Insets(0, 0, 5, 5);
693     linkConstraints2.gridx = 0;
694     linkConstraints2.gridy = 1;
695     linkConstraints2.weightx = 1.0;
696     linkConstraints2.weighty = 1.0;
697     linkConstraints2.fill = GridBagConstraints.BOTH;
698     linkTab.add(linkScrollPane, linkConstraints2);
699
700     // Filter box and buttons goes at bottom left, resizing resizes the text box
701     JPanel filterPanel = initLinkTabFilterPanel();
702     GridBagConstraints linkConstraints3 = new GridBagConstraints();
703     linkConstraints3.insets = new Insets(0, 0, 0, 5);
704     linkConstraints3.gridx = 0;
705     linkConstraints3.gridy = 2;
706     linkConstraints3.weightx = 1.0;
707     linkConstraints3.fill = GridBagConstraints.HORIZONTAL;
708     linkTab.add(filterPanel, linkConstraints3);
709
710     return linkTab;
711   }
712
713   private JPanel initLinkTabFilterPanel()
714   {
715     // Filter textbox and reset button
716     JLabel filterLabel = new JLabel(
717             MessageManager.getString("label.filter"));
718     filterLabel.setFont(LABEL_FONT);
719     filterLabel.setHorizontalAlignment(SwingConstants.RIGHT);
720     filterLabel.setHorizontalTextPosition(SwingConstants.LEADING);
721
722     filterTB.setFont(LABEL_FONT);
723     filterTB.setText("");
724
725     doReset.setText(MessageManager.getString("action.showall"));
726     userOnly.setText(MessageManager.getString("action.customfilter"));
727
728     // Panel for filter functionality
729     JPanel filterPanel = new JPanel(new GridBagLayout());
730     filterPanel.setBorder(new TitledBorder("Filter"));
731     GridBagConstraints gbc = new GridBagConstraints();
732     gbc.gridx = 0;
733     gbc.gridy = 0;
734     gbc.fill = GridBagConstraints.NONE;
735     gbc.anchor = GridBagConstraints.WEST;
736
737     filterPanel.add(filterLabel, gbc);
738
739     GridBagConstraints gbc1 = new GridBagConstraints();
740     gbc1.gridx = 1;
741     gbc1.gridwidth = 2;
742     gbc1.fill = GridBagConstraints.HORIZONTAL;
743     gbc1.anchor = GridBagConstraints.WEST;
744     gbc1.weightx = 1.0;
745     filterPanel.add(filterTB, gbc1);
746
747     GridBagConstraints gbc2 = new GridBagConstraints();
748     gbc2.gridx = 3;
749     gbc2.fill = GridBagConstraints.NONE;
750     gbc2.anchor = GridBagConstraints.WEST;
751     filterPanel.add(doReset, gbc2);
752
753     GridBagConstraints gbc3 = new GridBagConstraints();
754     gbc3.gridx = 4;
755     gbc3.fill = GridBagConstraints.NONE;
756     gbc3.anchor = GridBagConstraints.WEST;
757     filterPanel.add(userOnly, gbc3);
758
759     return filterPanel;
760   }
761
762   private JPanel initLinkTabUrlButtons()
763   {
764     // Buttons for new / edit / delete Url links
765     JButton newLink = new JButton();
766     newLink.setText(MessageManager.getString("action.new"));
767
768     editLink.setText(MessageManager.getString("action.edit"));
769
770     deleteLink.setText(MessageManager.getString("action.delete"));
771
772     // no current selection, so initially disable delete/edit buttons
773     editLink.setEnabled(false);
774     deleteLink.setEnabled(false);
775
776     newLink.addActionListener(new java.awt.event.ActionListener()
777     {
778       @Override
779       public void actionPerformed(ActionEvent e)
780       {
781         newLink_actionPerformed(e);
782       }
783     });
784
785     editLink.setText(MessageManager.getString("action.edit"));
786     editLink.addActionListener(new java.awt.event.ActionListener()
787     {
788       @Override
789       public void actionPerformed(ActionEvent e)
790       {
791         editLink_actionPerformed(e);
792       }
793     });
794
795     deleteLink.setText(MessageManager.getString("action.delete"));
796     deleteLink.addActionListener(new java.awt.event.ActionListener()
797     {
798       @Override
799       public void actionPerformed(ActionEvent e)
800       {
801         deleteLink_actionPerformed(e);
802       }
803     });
804
805     JPanel buttonPanel = new JPanel(new GridBagLayout());
806     buttonPanel.setBorder(new TitledBorder("Edit links"));
807     GridBagConstraints gbc = new GridBagConstraints();
808     gbc.gridx = 0;
809     gbc.gridy = 0;
810     gbc.fill = GridBagConstraints.NONE;
811     buttonPanel.add(newLink, gbc);
812
813     GridBagConstraints gbc1 = new GridBagConstraints();
814     gbc1.gridx = 1;
815     gbc1.gridy = 0;
816     gbc1.fill = GridBagConstraints.NONE;
817     buttonPanel.add(editLink, gbc1);
818
819     GridBagConstraints gbc2 = new GridBagConstraints();
820     gbc2.gridx = 2;
821     gbc2.gridy = 0;
822     gbc2.fill = GridBagConstraints.NONE;
823     buttonPanel.add(deleteLink, gbc2);
824
825     GridBagConstraints gbc3 = new GridBagConstraints();
826     gbc3.gridx = 3;
827     gbc3.gridy = 0;
828     gbc3.fill = GridBagConstraints.HORIZONTAL;
829     gbc3.weightx = 1.0;
830     JPanel spacePanel = new JPanel();
831     spacePanel.setBorder(null);
832     buttonPanel.add(spacePanel, gbc3);
833
834     return buttonPanel;
835   }
836
837   /**
838    * Initialises the proxy server panel in the Connections tab
839    * 
840    * @return the proxy server panel
841    */
842   private JPanel initConnTabProxyPanel()
843   {
844     // Label for server text box
845     serverLabel.setText(MessageManager.getString("label.address"));
846     serverLabel.setHorizontalAlignment(SwingConstants.RIGHT);
847     serverLabel.setFont(LABEL_FONT);
848
849     // Proxy server and port text boxes
850     proxyServerTB.setFont(LABEL_FONT);
851     proxyPortTB.setFont(LABEL_FONT);
852
853     // Label for Port text box
854     portLabel.setFont(LABEL_FONT);
855     portLabel.setHorizontalAlignment(SwingConstants.RIGHT);
856     portLabel.setText(MessageManager.getString("label.port"));
857
858     // Use proxy server checkbox
859     useProxy.setFont(LABEL_FONT);
860     useProxy.setHorizontalAlignment(SwingConstants.RIGHT);
861     useProxy.setHorizontalTextPosition(SwingConstants.LEADING);
862     useProxy.setText(MessageManager.getString("label.use_proxy_server"));
863     useProxy.addActionListener(new ActionListener()
864     {
865       @Override
866       public void actionPerformed(ActionEvent e)
867       {
868         useProxy_actionPerformed();
869       }
870     });
871
872     // Make proxy server panel
873     JPanel proxyPanel = new JPanel();
874     TitledBorder titledBorder1 = new TitledBorder(
875             MessageManager.getString("label.proxy_server"));
876     proxyPanel.setBorder(titledBorder1);
877     proxyPanel.setLayout(new GridBagLayout());
878     proxyPanel.add(serverLabel,
879             new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
880                     GridBagConstraints.WEST, GridBagConstraints.NONE,
881                     new Insets(0, 2, 2, 0), 5, 0));
882     proxyPanel.add(portLabel,
883             new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0,
884                     GridBagConstraints.WEST, GridBagConstraints.NONE,
885                     new Insets(0, 0, 2, 0), 11, 0));
886     proxyPanel.add(useProxy,
887             new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0,
888                     GridBagConstraints.WEST, GridBagConstraints.NONE,
889                     new Insets(0, 2, 5, 185), 2, -4));
890     proxyPanel.add(proxyPortTB,
891             new GridBagConstraints(3, 1, 1, 1, 1.0, 0.0,
892                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
893                     new Insets(0, 2, 2, 2), 54, 1));
894     proxyPanel.add(proxyServerTB,
895             new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0,
896                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
897                     new Insets(0, 2, 2, 0), 263, 1));
898
899     return proxyPanel;
900   }
901
902   /**
903    * Initialises the checkboxes in the Connections tab
904    */
905   private void initConnTabCheckboxes()
906   {
907     // Usage stats checkbox label
908     usagestats.setText(
909             MessageManager.getString("label.send_usage_statistics"));
910     usagestats.setFont(LABEL_FONT);
911     usagestats.setHorizontalAlignment(SwingConstants.RIGHT);
912     usagestats.setHorizontalTextPosition(SwingConstants.LEADING);
913
914     // Questionnaire checkbox label
915     questionnaire.setText(
916             MessageManager.getString("label.check_for_questionnaires"));
917     questionnaire.setFont(LABEL_FONT);
918     questionnaire.setHorizontalAlignment(SwingConstants.RIGHT);
919     questionnaire.setHorizontalTextPosition(SwingConstants.LEADING);
920
921     // Check for latest version checkbox label
922     versioncheck.setText(
923             MessageManager.getString("label.check_for_latest_version"));
924     versioncheck.setFont(LABEL_FONT);
925     versioncheck.setHorizontalAlignment(SwingConstants.RIGHT);
926     versioncheck.setHorizontalTextPosition(SwingConstants.LEADING);
927   }
928
929   /**
930    * Initialises the parent panel which contains the tabbed sections.
931    * 
932    * @return
933    */
934   private JPanel initOkCancelPanel()
935   {
936     JButton ok = new JButton();
937     ok.setText(MessageManager.getString("action.ok"));
938     ok.addActionListener(new ActionListener()
939     {
940       @Override
941       public void actionPerformed(ActionEvent e)
942       {
943         ok_actionPerformed(e);
944       }
945     });
946     JButton cancel = new JButton();
947     cancel.setText(MessageManager.getString("action.cancel"));
948     cancel.addActionListener(new ActionListener()
949     {
950       @Override
951       public void actionPerformed(ActionEvent e)
952       {
953         cancel_actionPerformed(e);
954       }
955     });
956     JPanel okCancelPanel = new JPanel();
957     okCancelPanel.add(ok);
958     okCancelPanel.add(cancel);
959     return okCancelPanel;
960   }
961
962   /**
963    * Initialises the Colours tabbed panel.
964    * 
965    * @return
966    */
967   private JPanel initColoursTab()
968   {
969     JPanel coloursTab = new JPanel();
970     coloursTab.setBorder(new TitledBorder(
971             MessageManager.getString("action.open_new_alignment")));
972     coloursTab.setLayout(new FlowLayout());
973     JLabel mincolourLabel = new JLabel();
974     mincolourLabel.setFont(LABEL_FONT);
975     mincolourLabel.setHorizontalAlignment(SwingConstants.RIGHT);
976     mincolourLabel.setText(MessageManager.getString("label.min_colour"));
977     minColour.setFont(LABEL_FONT);
978     minColour.setBorder(BorderFactory.createEtchedBorder());
979     minColour.setPreferredSize(new Dimension(40, 20));
980     minColour.addMouseListener(new MouseAdapter()
981     {
982       @Override
983       public void mousePressed(MouseEvent e)
984       {
985         minColour_actionPerformed(minColour);
986       }
987     });
988     JLabel maxcolourLabel = new JLabel();
989     maxcolourLabel.setFont(LABEL_FONT);
990     maxcolourLabel.setHorizontalAlignment(SwingConstants.RIGHT);
991     maxcolourLabel.setText(MessageManager.getString("label.max_colour"));
992     maxColour.setFont(LABEL_FONT);
993     maxColour.setBorder(BorderFactory.createEtchedBorder());
994     maxColour.setPreferredSize(new Dimension(40, 20));
995     maxColour.addMouseListener(new MouseAdapter()
996     {
997       @Override
998       public void mousePressed(MouseEvent e)
999       {
1000         maxColour_actionPerformed(maxColour);
1001       }
1002     });
1003
1004     protColour.setFont(LABEL_FONT);
1005     protColour.setBounds(new Rectangle(172, 225, 155, 21));
1006     JLabel protColourLabel = new JLabel();
1007     protColourLabel.setFont(LABEL_FONT);
1008     protColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
1009     protColourLabel.setText(
1010             MessageManager.getString("label.prot_alignment_colour") + " ");
1011     JvSwingUtils.addtoLayout(coloursTab,
1012             MessageManager
1013                     .getString("label.default_colour_scheme_for_alignment"),
1014             protColourLabel, protColour);
1015
1016     nucColour.setFont(LABEL_FONT);
1017     nucColour.setBounds(new Rectangle(172, 240, 155, 21));
1018     JLabel nucColourLabel = new JLabel();
1019     nucColourLabel.setFont(LABEL_FONT);
1020     nucColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
1021     nucColourLabel.setText(
1022             MessageManager.getString("label.nuc_alignment_colour") + " ");
1023     JvSwingUtils.addtoLayout(coloursTab,
1024             MessageManager
1025                     .getString("label.default_colour_scheme_for_alignment"),
1026             nucColourLabel, nucColour);
1027
1028     JPanel annotationShding = new JPanel();
1029     annotationShding.setBorder(new TitledBorder(
1030             MessageManager.getString("label.annotation_shading_default")));
1031     annotationShding.setLayout(new GridLayout(1, 2));
1032     JvSwingUtils.addtoLayout(annotationShding,
1033             MessageManager.getString(
1034                     "label.default_minimum_colour_annotation_shading"),
1035             mincolourLabel, minColour);
1036     JvSwingUtils.addtoLayout(annotationShding,
1037             MessageManager.getString(
1038                     "label.default_maximum_colour_annotation_shading"),
1039             maxcolourLabel, maxColour);
1040     coloursTab.add(annotationShding); // , FlowLayout.LEFT);
1041     return coloursTab;
1042   }
1043
1044   /**
1045    * Initialises the Overview tabbed panel.
1046    * 
1047    * @return
1048    */
1049   private JPanel initOverviewTab()
1050   {
1051     JPanel overviewPanel = new JPanel();
1052     overviewPanel.setBorder(new TitledBorder(
1053             MessageManager.getString("label.overview_settings")));
1054
1055     gapColour.setFont(LABEL_FONT);
1056     // fixing the border colours stops apparent colour bleed from the panel
1057     gapColour.setBorder(
1058             BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
1059     gapColour.setPreferredSize(new Dimension(40, 20));
1060     gapColour.addMouseListener(new MouseAdapter()
1061     {
1062       @Override
1063       public void mousePressed(MouseEvent e)
1064       {
1065         gapColour_actionPerformed(gapColour);
1066       }
1067     });
1068
1069     hiddenColour.setFont(LABEL_FONT);
1070     // fixing the border colours stops apparent colour bleed from the panel
1071     hiddenColour.setBorder(
1072             BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
1073     hiddenColour.setPreferredSize(new Dimension(40, 20));
1074     hiddenColour.addMouseListener(new MouseAdapter()
1075     {
1076       @Override
1077       public void mousePressed(MouseEvent e)
1078       {
1079         hiddenColour_actionPerformed(hiddenColour);
1080       }
1081     });
1082
1083     useLegacyGap = new JCheckBox(
1084             MessageManager.getString("label.ov_legacy_gap"));
1085     useLegacyGap.setFont(LABEL_FONT);
1086     useLegacyGap.setHorizontalAlignment(SwingConstants.LEFT);
1087     useLegacyGap.setVerticalTextPosition(SwingConstants.TOP);
1088     gapLabel = new JLabel(MessageManager.getString("label.gap_colour"));
1089     gapLabel.setFont(LABEL_FONT);
1090     gapLabel.setHorizontalAlignment(SwingConstants.LEFT);
1091     gapLabel.setVerticalTextPosition(SwingConstants.TOP);
1092     showHiddenAtStart = new JCheckBox(
1093             MessageManager.getString("label.ov_show_hide_default"));
1094     showHiddenAtStart.setFont(LABEL_FONT);
1095     showHiddenAtStart.setHorizontalAlignment(SwingConstants.LEFT);
1096     showHiddenAtStart.setVerticalTextPosition(SwingConstants.TOP);
1097     JLabel hiddenLabel = new JLabel(
1098             MessageManager.getString("label.hidden_colour"));
1099     hiddenLabel.setFont(LABEL_FONT);
1100     hiddenLabel.setHorizontalAlignment(SwingConstants.LEFT);
1101     hiddenLabel.setVerticalTextPosition(SwingConstants.TOP);
1102
1103     useLegacyGap.addActionListener(new ActionListener()
1104     {
1105       @Override
1106       public void actionPerformed(ActionEvent e)
1107       {
1108         useLegacyGaps_actionPerformed(e);
1109       }
1110     });
1111
1112     overviewPanel.setLayout(new GridBagLayout());
1113     GridBagConstraints c1 = new GridBagConstraints();
1114
1115     c1.fill = GridBagConstraints.HORIZONTAL;
1116     c1.gridx = 0;
1117     c1.gridy = 0;
1118     c1.weightx = 1;
1119     c1.ipady = 20;
1120     c1.anchor = GridBagConstraints.FIRST_LINE_START;
1121     overviewPanel.add(useLegacyGap, c1);
1122
1123     GridBagConstraints c2 = new GridBagConstraints();
1124     c2.fill = GridBagConstraints.HORIZONTAL;
1125     c2.gridx = 1;
1126     c2.gridy = 0;
1127     c2.insets = new Insets(0, 15, 0, 10);
1128     overviewPanel.add(gapLabel, c2);
1129
1130     GridBagConstraints c3 = new GridBagConstraints();
1131     c3.fill = GridBagConstraints.HORIZONTAL;
1132     c3.gridx = 2;
1133     c3.gridy = 0;
1134     c3.insets = new Insets(0, 0, 0, 15);
1135     overviewPanel.add(gapColour, c3);
1136
1137     GridBagConstraints c4 = new GridBagConstraints();
1138     c4.fill = GridBagConstraints.HORIZONTAL;
1139     c4.gridx = 0;
1140     c4.gridy = 1;
1141     c4.weightx = 1;
1142     overviewPanel.add(showHiddenAtStart, c4);
1143
1144     GridBagConstraints c5 = new GridBagConstraints();
1145     c5.fill = GridBagConstraints.HORIZONTAL;
1146     c5.gridx = 1;
1147     c5.gridy = 1;
1148     c5.insets = new Insets(0, 15, 0, 10);
1149     overviewPanel.add(hiddenLabel, c5);
1150
1151     GridBagConstraints c6 = new GridBagConstraints();
1152     c6.fill = GridBagConstraints.HORIZONTAL;
1153     c6.gridx = 2;
1154     c6.gridy = 1;
1155     c6.insets = new Insets(0, 0, 0, 15);
1156     overviewPanel.add(hiddenColour, c6);
1157
1158     JButton resetButton = new JButton(
1159             MessageManager.getString("label.reset_to_defaults"));
1160
1161     resetButton.addActionListener(new ActionListener()
1162     {
1163       @Override
1164       public void actionPerformed(ActionEvent e)
1165       {
1166         resetOvDefaults_actionPerformed(e);
1167       }
1168     });
1169
1170     GridBagConstraints c7 = new GridBagConstraints();
1171     c7.fill = GridBagConstraints.NONE;
1172     c7.gridx = 0;
1173     c7.gridy = 2;
1174     c7.insets = new Insets(10, 0, 0, 0);
1175     c7.anchor = GridBagConstraints.WEST;
1176     overviewPanel.add(resetButton, c7);
1177
1178     // Add padding so the panel doesn't look ridiculous
1179     JPanel spacePanel = new JPanel();
1180     overviewPanel.add(spacePanel,
1181             new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0,
1182                     GridBagConstraints.WEST, GridBagConstraints.BOTH,
1183                     new Insets(0, 0, 0, 5), 0, 0));
1184
1185     return overviewPanel;
1186   }
1187
1188   /**
1189    * Initialises the Structure tabbed panel.
1190    * 
1191    * @return
1192    */
1193   private JPanel initStructureTab()
1194   {
1195     structureTab = new JPanel();
1196
1197     structureTab.setBorder(new TitledBorder(
1198             MessageManager.getString("label.structure_options")));
1199     structureTab.setLayout(null);
1200     final int width = 420;
1201     final int height = 22;
1202     final int lineSpacing = 25;
1203     int ypos = 15;
1204
1205     structFromPdb.setFont(LABEL_FONT);
1206     structFromPdb
1207             .setText(MessageManager.getString("label.struct_from_pdb"));
1208     structFromPdb.setBounds(new Rectangle(5, ypos, width, height));
1209     structFromPdb.addActionListener(new ActionListener()
1210     {
1211       @Override
1212       public void actionPerformed(ActionEvent e)
1213       {
1214         boolean selected = structFromPdb.isSelected();
1215         // enable other options only when the first is checked
1216         useRnaView.setEnabled(selected);
1217         addSecondaryStructure.setEnabled(selected);
1218         addTempFactor.setEnabled(selected);
1219       }
1220     });
1221     structureTab.add(structFromPdb);
1222
1223     // indent checkboxes that are conditional on the first one
1224     ypos += lineSpacing;
1225     useRnaView.setFont(LABEL_FONT);
1226     useRnaView.setText(MessageManager.getString("label.use_rnaview"));
1227     useRnaView.setBounds(new Rectangle(25, ypos, width, height));
1228     structureTab.add(useRnaView);
1229
1230     ypos += lineSpacing;
1231     addSecondaryStructure.setFont(LABEL_FONT);
1232     addSecondaryStructure
1233             .setText(MessageManager.getString("label.autoadd_secstr"));
1234     addSecondaryStructure.setBounds(new Rectangle(25, ypos, width, height));
1235     structureTab.add(addSecondaryStructure);
1236
1237     ypos += lineSpacing;
1238     addTempFactor.setFont(LABEL_FONT);
1239     addTempFactor.setText(MessageManager.getString("label.autoadd_temp"));
1240     addTempFactor.setBounds(new Rectangle(25, ypos, width, height));
1241     structureTab.add(addTempFactor);
1242
1243     ypos += lineSpacing;
1244     JLabel viewerLabel = new JLabel();
1245     viewerLabel.setFont(LABEL_FONT);
1246     viewerLabel.setHorizontalAlignment(SwingConstants.LEFT);
1247     viewerLabel.setText(MessageManager.getString("label.structure_viewer"));
1248     viewerLabel.setBounds(new Rectangle(10, ypos, 220, height));
1249     structureTab.add(viewerLabel);
1250
1251     /*
1252      * add all external viewers as options here - check 
1253      * when selected whether the program is installed
1254      */
1255     structViewer.setFont(LABEL_FONT);
1256     structViewer.setBounds(new Rectangle(190, ypos, 120, height));
1257     structViewer.addItem(ViewerType.JMOL.name());
1258     structViewer.addItem(ViewerType.CHIMERA.name());
1259     structViewer.addItem(ViewerType.CHIMERAX.name());
1260     structViewer.addItem(ViewerType.PYMOL.name());
1261     structViewer.addActionListener(new ActionListener()
1262     {
1263       @Override
1264       public void actionPerformed(ActionEvent e)
1265       {
1266         structureViewer_actionPerformed(
1267                 (String) structViewer.getSelectedItem());
1268       }
1269     });
1270     structureTab.add(structViewer);
1271
1272     ypos += lineSpacing;
1273     structureViewerPathLabel = new JLabel();
1274     structureViewerPathLabel.setFont(LABEL_FONT);// new Font("SansSerif", 0, 11));
1275     structureViewerPathLabel.setHorizontalAlignment(SwingConstants.LEFT);
1276     structureViewerPathLabel.setText(MessageManager
1277             .formatMessage("label.viewer_path", "Chimera(X)"));
1278     structureViewerPathLabel.setBounds(new Rectangle(10, ypos, 170, height));
1279     structureViewerPathLabel.setEnabled(false);
1280     structureTab.add(structureViewerPathLabel);
1281
1282     structureViewerPath.setFont(LABEL_FONT);
1283     structureViewerPath.setText("");
1284     structureViewerPath.setEnabled(false);
1285     final String tooltip = JvSwingUtils.wrapTooltip(true,
1286             MessageManager.getString("label.viewer_path_tip"));
1287     structureViewerPath.setToolTipText(tooltip);
1288     structureViewerPath.setBounds(new Rectangle(190, ypos, 290, height));
1289     structureViewerPath.addMouseListener(new MouseAdapter()
1290     {
1291       @Override
1292       public void mouseClicked(MouseEvent e)
1293       {
1294         if (structureViewerPath.isEnabled() && e.getClickCount() == 2)
1295         {
1296           String chosen = openFileChooser();
1297           if (chosen != null)
1298           {
1299             structureViewerPath.setText(chosen);
1300           }
1301         }
1302       }
1303     });
1304     structureTab.add(structureViewerPath);
1305
1306     ypos += lineSpacing;
1307     nwMapping.setFont(LABEL_FONT);
1308     nwMapping.setText(MessageManager.getString("label.nw_mapping"));
1309     siftsMapping.setFont(LABEL_FONT);
1310     siftsMapping.setText(MessageManager.getString("label.sifts_mapping"));
1311     mappingMethod.add(nwMapping);
1312     mappingMethod.add(siftsMapping);
1313     JPanel mappingPanel = new JPanel();
1314     mappingPanel.setFont(LABEL_FONT);
1315     TitledBorder mmTitledBorder = new TitledBorder(
1316             MessageManager.getString("label.mapping_method"));
1317     mmTitledBorder.setTitleFont(LABEL_FONT);
1318     mappingPanel.setBorder(mmTitledBorder);
1319     mappingPanel.setBounds(new Rectangle(10, ypos, 472, 45));
1320     // GridLayout mappingLayout = new GridLayout();
1321     mappingPanel.setLayout(new GridLayout());
1322     mappingPanel.add(nwMapping);
1323     mappingPanel.add(siftsMapping);
1324     structureTab.add(mappingPanel);
1325
1326     ypos += lineSpacing;
1327     ypos += lineSpacing;
1328     FTSDataColumnPreferences docFieldPref = new FTSDataColumnPreferences(
1329             PreferenceSource.PREFERENCES, PDBFTSRestClient.getInstance());
1330     docFieldPref.setBounds(new Rectangle(10, ypos, 470, 120));
1331     structureTab.add(docFieldPref);
1332
1333     return structureTab;
1334   }
1335
1336   /**
1337    * Action on choosing a structure viewer from combobox options.
1338    * 
1339    * @param selectedItem
1340    */
1341   protected void structureViewer_actionPerformed(String selectedItem)
1342   {
1343   }
1344
1345   /**
1346    * Show a dialog for the user to choose a file. Returns the chosen path, or
1347    * null on Cancel.
1348    * 
1349    * @return
1350    */
1351   protected String openFileChooser()
1352   {
1353     String choice = null;
1354     JFileChooser chooser = new JFileChooser();
1355
1356     // chooser.setFileView(new JalviewFileView());
1357     chooser.setDialogTitle(
1358             MessageManager.getString("label.open_local_file"));
1359     chooser.setToolTipText(MessageManager.getString("action.open"));
1360
1361     int value = chooser.showOpenDialog(this);
1362
1363     if (value == JFileChooser.APPROVE_OPTION)
1364     {
1365       choice = chooser.getSelectedFile().getPath();
1366     }
1367     return choice;
1368   }
1369
1370   /**
1371    * Validate the structure tab preferences; if invalid, set focus on this tab.
1372    * 
1373    * @param e
1374    */
1375   protected boolean validateStructure(FocusEvent e)
1376   {
1377     if (!validateStructure())
1378     {
1379       e.getComponent().requestFocusInWindow();
1380       return false;
1381     }
1382     return true;
1383   }
1384
1385   protected boolean validateStructure()
1386   {
1387     return false;
1388   }
1389
1390   /**
1391    * Initialises the Visual tabbed panel.
1392    * 
1393    * @return
1394    */
1395   private JPanel initVisualTab()
1396   {
1397     JPanel visualTab = new JPanel();
1398     visualTab.setBorder(new TitledBorder(
1399             MessageManager.getString("action.open_new_alignment")));
1400     visualTab.setLayout(null);
1401     fullScreen.setFont(LABEL_FONT);
1402     fullScreen.setHorizontalAlignment(SwingConstants.RIGHT);
1403     fullScreen.setHorizontalTextPosition(SwingConstants.LEFT);
1404     fullScreen.setText(MessageManager.getString("label.maximize_window"));
1405     quality.setEnabled(false);
1406     quality.setFont(LABEL_FONT);
1407     quality.setHorizontalAlignment(SwingConstants.RIGHT);
1408     quality.setHorizontalTextPosition(SwingConstants.LEFT);
1409     quality.setSelected(true);
1410     quality.setText(MessageManager.getString("label.quality"));
1411     conservation.setEnabled(false);
1412     conservation.setFont(LABEL_FONT);
1413     conservation.setHorizontalAlignment(SwingConstants.RIGHT);
1414     conservation.setHorizontalTextPosition(SwingConstants.LEFT);
1415     conservation.setSelected(true);
1416     conservation.setText(MessageManager.getString("label.conservation"));
1417     identity.setEnabled(false);
1418     identity.setFont(LABEL_FONT);
1419     identity.setHorizontalAlignment(SwingConstants.RIGHT);
1420     identity.setHorizontalTextPosition(SwingConstants.LEFT);
1421     identity.setSelected(true);
1422     identity.setText(MessageManager.getString("label.consensus"));
1423     showOccupancy.setFont(LABEL_FONT);
1424     showOccupancy.setEnabled(false);
1425     showOccupancy.setHorizontalAlignment(SwingConstants.RIGHT);
1426     showOccupancy.setHorizontalTextPosition(SwingConstants.LEFT);
1427     showOccupancy.setSelected(true);
1428     showOccupancy.setText(MessageManager.getString("label.occupancy"));
1429
1430     JLabel showGroupbits = new JLabel();
1431     showGroupbits.setFont(LABEL_FONT);
1432     showGroupbits.setHorizontalAlignment(SwingConstants.RIGHT);
1433     showGroupbits.setHorizontalTextPosition(SwingConstants.LEFT);
1434     showGroupbits
1435             .setText(MessageManager.getString("action.show_group") + ":");
1436     JLabel showConsensbits = new JLabel();
1437     showConsensbits.setFont(LABEL_FONT);
1438     showConsensbits.setHorizontalAlignment(SwingConstants.RIGHT);
1439     showConsensbits.setHorizontalTextPosition(SwingConstants.LEFT);
1440     showConsensbits
1441             .setText(MessageManager.getString("label.consensus") + ":");
1442     showConsensHistogram.setEnabled(false);
1443     showConsensHistogram.setFont(LABEL_FONT);
1444     showConsensHistogram.setHorizontalAlignment(SwingConstants.RIGHT);
1445     showConsensHistogram.setHorizontalTextPosition(SwingConstants.LEFT);
1446     showConsensHistogram.setSelected(true);
1447     showConsensHistogram
1448             .setText(MessageManager.getString("label.histogram"));
1449     showConsensLogo.setEnabled(false);
1450     showConsensLogo.setFont(LABEL_FONT);
1451     showConsensLogo.setHorizontalAlignment(SwingConstants.RIGHT);
1452     showConsensLogo.setHorizontalTextPosition(SwingConstants.LEFT);
1453     showConsensLogo.setSelected(true);
1454     showConsensLogo.setText(MessageManager.getString("label.logo"));
1455     showGroupConsensus.setEnabled(false);
1456     showGroupConsensus.setFont(LABEL_FONT);
1457     showGroupConsensus.setHorizontalAlignment(SwingConstants.RIGHT);
1458     showGroupConsensus.setHorizontalTextPosition(SwingConstants.LEFT);
1459     showGroupConsensus.setSelected(true);
1460     showGroupConsensus.setText(MessageManager.getString("label.consensus"));
1461     showGroupConservation.setEnabled(false);
1462     showGroupConservation.setFont(LABEL_FONT);
1463     showGroupConservation.setHorizontalAlignment(SwingConstants.RIGHT);
1464     showGroupConservation.setHorizontalTextPosition(SwingConstants.LEFT);
1465     showGroupConservation.setSelected(true);
1466     showGroupConservation
1467             .setText(MessageManager.getString("label.conservation"));
1468     showNpTooltip.setEnabled(true);
1469     showNpTooltip.setFont(LABEL_FONT);
1470     showNpTooltip.setHorizontalAlignment(SwingConstants.RIGHT);
1471     showNpTooltip.setHorizontalTextPosition(SwingConstants.LEFT);
1472     showNpTooltip.setSelected(true);
1473     showNpTooltip.setText(
1474             MessageManager.getString("label.non_positional_features"));
1475     showDbRefTooltip.setEnabled(true);
1476     showDbRefTooltip.setFont(LABEL_FONT);
1477     showDbRefTooltip.setHorizontalAlignment(SwingConstants.RIGHT);
1478     showDbRefTooltip.setHorizontalTextPosition(SwingConstants.LEFT);
1479     showDbRefTooltip.setSelected(true);
1480     showDbRefTooltip
1481             .setText(MessageManager.getString("label.database_references"));
1482     annotations.setFont(LABEL_FONT);
1483     annotations.setHorizontalAlignment(SwingConstants.RIGHT);
1484     annotations.setHorizontalTextPosition(SwingConstants.LEFT);
1485     annotations.setSelected(true);
1486     annotations.setText(MessageManager.getString("label.show_annotations"));
1487     // annotations.setBounds(new Rectangle(169, 12, 200, 23));
1488     annotations.addActionListener(new ActionListener()
1489     {
1490       @Override
1491       public void actionPerformed(ActionEvent e)
1492       {
1493         annotations_actionPerformed(e);
1494       }
1495     });
1496     identity.addActionListener(new ActionListener()
1497     {
1498       @Override
1499       public void actionPerformed(ActionEvent e)
1500       {
1501         annotations_actionPerformed(e);
1502       }
1503     });
1504     showGroupConsensus.addActionListener(new ActionListener()
1505     {
1506       @Override
1507       public void actionPerformed(ActionEvent e)
1508       {
1509         annotations_actionPerformed(e);
1510       }
1511     });
1512     showUnconserved.setFont(LABEL_FONT);
1513     showUnconserved.setHorizontalAlignment(SwingConstants.RIGHT);
1514     showUnconserved.setHorizontalTextPosition(SwingConstants.LEFT);
1515     showUnconserved.setSelected(true);
1516     showUnconserved
1517             .setText(MessageManager.getString("action.show_unconserved"));
1518     showUnconserved.addActionListener(new ActionListener()
1519     {
1520       @Override
1521       public void actionPerformed(ActionEvent e)
1522       {
1523         showunconserved_actionPerformed(e);
1524       }
1525     });
1526
1527     // TODO these are not yet added to / action from Preferences
1528     // JCheckBox shareSelections = new JCheckBox();
1529     // shareSelections.setFont(verdana11);
1530     // shareSelections.setHorizontalAlignment(SwingConstants.RIGHT);
1531     // shareSelections.setHorizontalTextPosition(SwingConstants.LEFT);
1532     // shareSelections.setSelected(true);
1533     // shareSelections.setText(MessageManager
1534     // .getString("label.share_selection_across_views"));
1535     // JCheckBox followHighlight = new JCheckBox();
1536     // followHighlight.setFont(verdana11);
1537     // followHighlight.setHorizontalAlignment(SwingConstants.RIGHT);
1538     // followHighlight.setHorizontalTextPosition(SwingConstants.LEFT);
1539     // // showUnconserved.setBounds(new Rectangle(169, 40, 200, 23));
1540     // followHighlight.setSelected(true);
1541     // followHighlight.setText(MessageManager
1542     // .getString("label.scroll_highlighted_regions"));
1543
1544     seqLimit.setFont(LABEL_FONT);
1545     seqLimit.setHorizontalAlignment(SwingConstants.RIGHT);
1546     seqLimit.setHorizontalTextPosition(SwingConstants.LEFT);
1547     seqLimit.setText(MessageManager.getString("label.full_sequence_id"));
1548     smoothFont.setFont(LABEL_FONT);
1549     smoothFont.setHorizontalAlignment(SwingConstants.RIGHT);
1550     smoothFont.setHorizontalTextPosition(SwingConstants.LEADING);
1551     smoothFont.setText(MessageManager.getString("label.smooth_font"));
1552     scaleProteinToCdna.setFont(LABEL_FONT);
1553     scaleProteinToCdna.setHorizontalAlignment(SwingConstants.RIGHT);
1554     scaleProteinToCdna.setHorizontalTextPosition(SwingConstants.LEADING);
1555     scaleProteinToCdna.setText(
1556             MessageManager.getString("label.scale_protein_to_cdna"));
1557     scaleProteinToCdna.setToolTipText(
1558             MessageManager.getString("label.scale_protein_to_cdna_tip"));
1559     JLabel gapLabel = new JLabel();
1560     gapLabel.setFont(LABEL_FONT);
1561     gapLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1562     gapLabel.setText(MessageManager.getString("label.gap_symbol") + " ");
1563     JLabel fontLabel = new JLabel();
1564     fontLabel.setFont(LABEL_FONT);
1565     fontLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1566     fontLabel.setText(MessageManager.getString("label.font"));
1567     fontSizeCB.setFont(LABEL_FONT);
1568     fontSizeCB.setBounds(new Rectangle(320, 112, 65, 23));
1569     fontStyleCB.setFont(LABEL_FONT);
1570     fontStyleCB.setBounds(new Rectangle(382, 112, 80, 23));
1571     fontNameCB.setFont(LABEL_FONT);
1572     fontNameCB.setBounds(new Rectangle(172, 112, 147, 23));
1573     gapSymbolCB.setFont(LABEL_FONT);
1574     gapSymbolCB.setBounds(new Rectangle(172, 215, 69, 23));
1575     DefaultListCellRenderer dlcr = new DefaultListCellRenderer();
1576     dlcr.setHorizontalAlignment(DefaultListCellRenderer.CENTER);
1577     gapSymbolCB.setRenderer(dlcr);
1578
1579     startupCheckbox.setText(MessageManager.getString("action.open_file"));
1580     startupCheckbox.setFont(LABEL_FONT);
1581     startupCheckbox.setHorizontalAlignment(SwingConstants.RIGHT);
1582     startupCheckbox.setHorizontalTextPosition(SwingConstants.LEFT);
1583     startupCheckbox.setSelected(true);
1584     startupFileTextfield.setFont(LABEL_FONT);
1585     startupFileTextfield.setBounds(new Rectangle(172, 310, 330, 20));
1586     final String tooltip = JvSwingUtils.wrapTooltip(true,
1587             MessageManager.getString("label.double_click_to_browse"));
1588     startupFileTextfield.setToolTipText(tooltip);
1589     startupFileTextfield.addMouseListener(new MouseAdapter()
1590     {
1591       @Override
1592       public void mouseClicked(MouseEvent e)
1593       {
1594         if (e.getClickCount() > 1)
1595         {
1596           startupFileTextfield_mouseClicked();
1597         }
1598       }
1599     });
1600
1601     sortby.setFont(LABEL_FONT);
1602     sortby.setBounds(new Rectangle(172, 260, 155, 21));
1603     JLabel sortLabel = new JLabel();
1604     sortLabel.setFont(LABEL_FONT);
1605     sortLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1606     sortLabel.setText(MessageManager.getString("label.sort_by"));
1607     sortAnnBy.setFont(LABEL_FONT);
1608     sortAnnBy.setBounds(new Rectangle(172, 285, 110, 21));
1609     JLabel sortAnnLabel = new JLabel();
1610     sortAnnLabel.setFont(LABEL_FONT);
1611     sortAnnLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1612     sortAnnLabel.setText(MessageManager.getString("label.sort_ann_by"));
1613     sortAutocalc.setFont(LABEL_FONT);
1614     sortAutocalc.setBounds(new Rectangle(290, 285, 165, 21));
1615
1616     JPanel annsettingsPanel = new JPanel();
1617     annsettingsPanel.setBounds(new Rectangle(173, 13, 320, 96));
1618     annsettingsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
1619     annsettingsPanel.setBorder(new EtchedBorder());
1620     visualTab.add(annsettingsPanel);
1621     Border jb = new EmptyBorder(1, 1, 4, 5);
1622     annotations.setBorder(jb);
1623     showOccupancy.setBorder(jb);
1624     quality.setBorder(jb);
1625     conservation.setBorder(jb);
1626     identity.setBorder(jb);
1627     showConsensbits.setBorder(jb);
1628     showGroupbits.setBorder(jb);
1629     showGroupConsensus.setBorder(jb);
1630     showGroupConservation.setBorder(jb);
1631     showConsensHistogram.setBorder(jb);
1632     showConsensLogo.setBorder(jb);
1633
1634     JPanel autoAnnotSettings = new JPanel();
1635     annsettingsPanel.add(autoAnnotSettings);
1636     autoAnnotSettings.setLayout(new GridLayout(0, 2));
1637     autoAnnotSettings.add(annotations);
1638     autoAnnotSettings.add(quality);
1639     // second row of autoannotation box
1640     autoAnnotSettings = new JPanel();
1641     annsettingsPanel.add(autoAnnotSettings);
1642
1643     autoAnnotSettings.setLayout(new GridLayout(0, 3));
1644     autoAnnotSettings.add(conservation);
1645     autoAnnotSettings.add(identity);
1646     autoAnnotSettings.add(showOccupancy);
1647     autoAnnotSettings.add(showGroupbits);
1648     autoAnnotSettings.add(showGroupConservation);
1649     autoAnnotSettings.add(showGroupConsensus);
1650     autoAnnotSettings.add(showConsensbits);
1651     autoAnnotSettings.add(showConsensHistogram);
1652     autoAnnotSettings.add(showConsensLogo);
1653
1654     JPanel tooltipSettings = new JPanel();
1655     tooltipSettings.setBorder(new TitledBorder(
1656             MessageManager.getString("label.sequence_id_tooltip")));
1657     tooltipSettings.setBounds(173, 140, 220, 62);
1658     tooltipSettings.setLayout(new GridLayout(2, 1));
1659     tooltipSettings.add(showDbRefTooltip);
1660     tooltipSettings.add(showNpTooltip);
1661     visualTab.add(tooltipSettings);
1662
1663     wrap.setFont(LABEL_FONT);
1664     wrap.setHorizontalAlignment(SwingConstants.TRAILING);
1665     wrap.setHorizontalTextPosition(SwingConstants.LEADING);
1666     wrap.setText(MessageManager.getString("label.wrap_alignment"));
1667     rightAlign.setFont(LABEL_FONT);
1668     rightAlign.setForeground(Color.black);
1669     rightAlign.setHorizontalAlignment(SwingConstants.RIGHT);
1670     rightAlign.setHorizontalTextPosition(SwingConstants.LEFT);
1671     rightAlign.setText(MessageManager.getString("label.right_align_ids"));
1672     idItalics.setFont(LABEL_FONT_ITALIC);
1673     idItalics.setHorizontalAlignment(SwingConstants.RIGHT);
1674     idItalics.setHorizontalTextPosition(SwingConstants.LEADING);
1675     idItalics.setText(
1676             MessageManager.getString("label.sequence_name_italics"));
1677     openoverv.setFont(LABEL_FONT);
1678     openoverv.setActionCommand(
1679             MessageManager.getString("label.open_overview"));
1680     openoverv.setHorizontalAlignment(SwingConstants.RIGHT);
1681     openoverv.setHorizontalTextPosition(SwingConstants.LEFT);
1682     openoverv.setText(MessageManager.getString("label.open_overview"));
1683     JPanel jPanel2 = new JPanel();
1684     jPanel2.setBounds(new Rectangle(7, 17, 158, 310));
1685     jPanel2.setLayout(new GridLayout(14, 1));
1686     jPanel2.add(fullScreen);
1687     jPanel2.add(openoverv);
1688     jPanel2.add(seqLimit);
1689     jPanel2.add(rightAlign);
1690     jPanel2.add(fontLabel);
1691     jPanel2.add(showUnconserved);
1692     jPanel2.add(idItalics);
1693     jPanel2.add(smoothFont);
1694     jPanel2.add(scaleProteinToCdna);
1695     jPanel2.add(gapLabel);
1696     jPanel2.add(wrap);
1697     jPanel2.add(sortLabel);
1698     jPanel2.add(sortAnnLabel);
1699     jPanel2.add(startupCheckbox);
1700     visualTab.add(jPanel2);
1701     visualTab.add(startupFileTextfield);
1702     visualTab.add(sortby);
1703     visualTab.add(sortAnnBy);
1704     visualTab.add(sortAutocalc);
1705     visualTab.add(gapSymbolCB);
1706     visualTab.add(fontNameCB);
1707     visualTab.add(fontSizeCB);
1708     visualTab.add(fontStyleCB);
1709     return visualTab;
1710   }
1711
1712   /**
1713    * Load the saved Backups options EXCEPT "Enabled" and "Scheme"
1714    */
1715
1716   protected void loadLastSavedBackupsOptions()
1717   {
1718     BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
1719             .getSavedBackupEntry();
1720     enableBackupFiles
1721             .setSelected(Cache.getDefault(BackupFiles.ENABLED, true));
1722
1723     BackupFilesPresetEntry backupfilesCustomEntry = BackupFilesPresetEntry
1724             .createBackupFilesPresetEntry(Cache
1725                     .getDefault(BackupFilesPresetEntry.CUSTOMCONFIG, null));
1726     if (backupfilesCustomEntry == null)
1727     {
1728       backupfilesCustomEntry = BackupFilesPresetEntry.backupfilesPresetEntriesValues
1729               .get(BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT);
1730     }
1731     BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
1732             BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM,
1733             backupfilesCustomEntry);
1734
1735     setComboIntStringKey(backupfilesPresetsCombo,
1736             Cache.getDefault(BackupFiles.NS + "_PRESET",
1737                     BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT));
1738
1739     backupsSetOptions(savedPreset);
1740
1741     backupsOptionsSetEnabled();
1742     updateBackupFilesExampleLabel();
1743   }
1744
1745   private boolean warnAboutSuffixReverseChange()
1746   {
1747     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
1748             .getSavedBackupEntry();
1749     boolean savedSuffixReverse = bfpe.reverse;
1750     int savedSuffixDigits = bfpe.digits;
1751     String savedSuffixTemplate = bfpe.suffix;
1752
1753     boolean nowSuffixReverse = suffixReverse.isSelected();
1754     int nowSuffixDigits = getSpinnerInt(suffixDigitsSpinner, 3);
1755     String nowSuffixTemplate = suffixTemplate.getText();
1756     return nowSuffixReverse != savedSuffixReverse
1757             && nowSuffixDigits == savedSuffixDigits
1758             && nowSuffixTemplate != null
1759             && nowSuffixTemplate.equals(savedSuffixTemplate);
1760   }
1761
1762   /**
1763    * Initialises the Backups tabbed panel.
1764    * 
1765    * @return
1766    */
1767   private JPanel initBackupsTab()
1768   {
1769     JPanel backupsTab = new JPanel();
1770     backupsTab.setBorder(new TitledBorder(
1771             MessageManager.getString("label.backup_files")));
1772     backupsTab.setLayout(new GridBagLayout());
1773
1774     GridBagConstraints gbc = new GridBagConstraints();
1775     gbc.weightx = 0.0;
1776     gbc.weighty = 0.0;
1777     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
1778     gbc.fill = GridBagConstraints.NONE;
1779
1780     initBackupsTabPresetsPanel();
1781     initBackupsTabSuffixPanel();
1782     initBackupsTabKeepFilesPanel();
1783     initBackupsTabFilenameExamplesPanel();
1784
1785     enableBackupFiles.setFont(LABEL_FONT_BOLD);
1786     enableBackupFiles
1787             .setText(MessageManager.getString("label.enable_backupfiles"));
1788     enableBackupFiles.addActionListener(new ActionListener()
1789     {
1790       @Override
1791       public void actionPerformed(ActionEvent e)
1792       {
1793         // enable other options only when the first is checked
1794         backupsOptionsSetEnabled();
1795       }
1796     });
1797
1798
1799     // enable checkbox 1 col
1800     gbc.gridwidth = 1;
1801     gbc.gridheight = 1;
1802     gbc.gridx = 0;
1803     gbc.gridy = 0; // row 0
1804     backupsTab.add(enableBackupFiles, gbc);
1805
1806     // summary of scheme box (over two rows)
1807     gbc.gridx = 1;
1808     gbc.weightx = 0.0;
1809     gbc.gridheight = 2;
1810     gbc.anchor = GridBagConstraints.FIRST_LINE_END;
1811     gbc.fill = GridBagConstraints.BOTH;
1812     backupsTab.add(exampleFilesPanel, gbc);
1813     gbc.gridheight = 1;
1814     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
1815     gbc.fill = GridBagConstraints.NONE;
1816
1817     // fill empty space on right
1818     gbc.gridx++;
1819     gbc.weightx = 1.0;
1820     backupsTab.add(new JPanel(), gbc);
1821
1822     // schemes box
1823     gbc.weightx = 0.0;
1824     gbc.gridx = 0;
1825     gbc.gridy++; // row 1
1826     backupsTab.add(presetsPanel, gbc);
1827
1828     // now using whole row
1829     gbc.gridwidth = 2;
1830     gbc.gridheight = 1;
1831     // keep files box
1832     gbc.gridx = 0;
1833     gbc.gridy++; // row 2
1834     backupsTab.add(keepfilesPanel, gbc);
1835
1836     // filename strategy box
1837     gbc.gridy++; // row 3
1838     backupsTab.add(suffixPanel, gbc);
1839
1840     // fill empty space
1841     gbc.gridy++; // row 4
1842     gbc.weighty = 1.0;
1843     backupsTab.add(new JPanel(), gbc);
1844
1845     backupsOptionsSetEnabled();
1846     return backupsTab;
1847   }
1848
1849   private JPanel initBackupsTabPresetsPanel()
1850   {
1851
1852     String title = MessageManager.getString("label.schemes");
1853
1854     presetsPanel.setLayout(new GridBagLayout());
1855
1856     GridBagConstraints gbc = new GridBagConstraints();
1857     gbc.weightx = 0.0;
1858     gbc.weighty = 0.0;
1859     gbc.anchor = GridBagConstraints.BASELINE_LEADING;
1860     gbc.fill = GridBagConstraints.NONE;
1861     gbc.gridwidth = 1;
1862     gbc.gridheight = 1;
1863
1864     // "Scheme: "
1865     gbc.gridx = 0;
1866     gbc.gridy = 0;
1867
1868     presetsComboLabel = new JLabel(title + ":");
1869     presetsPanel.add(presetsComboLabel, gbc);
1870
1871     List<Object> entries = Arrays
1872             .asList((Object[]) BackupFilesPresetEntry.backupfilesPresetEntries);
1873     List<String> tooltips = Arrays.asList(
1874             BackupFilesPresetEntry.backupfilesPresetEntryDescriptions);
1875     backupfilesPresetsCombo = JvSwingUtils.buildComboWithTooltips(entries,
1876             tooltips);
1877     /*
1878     for (int i = 0; i < BackupFilesPresetEntry.backupfilesPresetEntries.length; i++)
1879     {
1880       backupfilesPresetsCombo
1881               .addItem(BackupFilesPresetEntry.backupfilesPresetEntries[i]);
1882     }
1883     */
1884
1885     backupfilesPresetsCombo.addActionListener(new ActionListener()
1886     {
1887       @Override
1888       public void actionPerformed(ActionEvent e)
1889       {
1890         int key = getComboIntStringKey(backupfilesPresetsCombo);
1891         if (!customiseCheckbox.isSelected())
1892         {
1893           backupfilesPresetsComboLastSelected = key;
1894         }
1895         if (key == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
1896         {
1897           if (customiseCheckbox.isSelected())
1898           {
1899             // got here by clicking on customiseCheckbox so don't change the values
1900             backupfilesCustomOptionsSetEnabled();
1901           }
1902           else
1903           {
1904             backupsTabUpdatePresets();
1905             backupfilesCustomOptionsSetEnabled();
1906           }
1907         }
1908         else
1909         {
1910           customiseCheckbox.setSelected(false);
1911           backupsTabUpdatePresets();
1912           backupfilesCustomOptionsSetEnabled();
1913         }
1914       }
1915     });
1916
1917     // dropdown list of preset schemes
1918     gbc.gridx = 1;
1919     presetsPanel.add(backupfilesPresetsCombo, gbc);
1920
1921     revertButton.setText(MessageManager.getString("label.cancel_changes"));
1922     revertButton.setToolTipText(
1923             MessageManager.getString("label.cancel_changes_description"));
1924     revertButton.addActionListener(new ActionListener()
1925     {
1926       @Override
1927       public void actionPerformed(ActionEvent e)
1928       {
1929         backupsSetOptions(
1930                 BackupFilesPresetEntry.backupfilesPresetEntriesValues.get(
1931                         BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM));
1932         backupfilesCustomOptionsSetEnabled();
1933       }
1934
1935     });
1936     revertButton.setFont(LABEL_FONT);
1937
1938     customiseCheckbox.setFont(LABEL_FONT);
1939     customiseCheckbox.setText(MessageManager.getString("label.customise"));
1940     customiseCheckbox.addActionListener(new ActionListener()
1941     {
1942       @Override
1943       public void actionPerformed(ActionEvent e)
1944       {
1945         int currently = getComboIntStringKey(backupfilesPresetsCombo);
1946         if (customiseCheckbox.isSelected())
1947         {
1948           backupfilesPresetsComboLastSelected = currently;
1949           setComboIntStringKey(backupfilesPresetsCombo,
1950                   BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
1951         }
1952         else
1953         {
1954           setComboIntStringKey(backupfilesPresetsCombo,
1955                   backupfilesPresetsComboLastSelected);
1956
1957         }
1958         backupfilesCustomOptionsSetEnabled();
1959       }
1960     });
1961     customiseCheckbox.setToolTipText(
1962             MessageManager.getString("label.customise_description"));
1963
1964     // customise checkbox
1965     gbc.gridx = 0;
1966     gbc.gridy++;
1967     presetsPanel.add(customiseCheckbox, gbc);
1968
1969     // "Cancel changes" button (aligned with combo box above)
1970     gbc.gridx = 1;
1971     presetsPanel.add(revertButton, gbc);
1972
1973     return presetsPanel;
1974   }
1975
1976   private JPanel initBackupsTabFilenameExamplesPanel()
1977   {
1978     String title = MessageManager
1979             .getString("label.scheme_examples");
1980     TitledBorder tb = new TitledBorder(title);
1981     exampleFilesPanel.setBorder(tb);
1982     exampleFilesPanel.setLayout(new GridBagLayout());
1983
1984
1985     backupfilesExampleLabel.setEditable(false);
1986     backupfilesExampleLabel
1987             .setBackground(exampleFilesPanel.getBackground());
1988
1989     updateBackupFilesExampleLabel();
1990
1991     GridBagConstraints gbc = new GridBagConstraints();
1992     gbc.weightx = 1.0;
1993     gbc.weighty = 1.0;
1994     gbc.fill = GridBagConstraints.NONE;
1995     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
1996
1997     exampleFilesPanel.add(backupfilesExampleLabel, gbc);
1998     return exampleFilesPanel;
1999   }
2000
2001   private void backupsTabUpdatePresets()
2002   {
2003     IntKeyStringValueEntry entry = (IntKeyStringValueEntry) backupfilesPresetsCombo
2004             .getSelectedItem();
2005     int key = entry.k;
2006     String value = entry.v;
2007
2008     if (BackupFilesPresetEntry.backupfilesPresetEntriesValues
2009             .containsKey(key))
2010     {
2011       backupsSetOptions(
2012               BackupFilesPresetEntry.backupfilesPresetEntriesValues
2013                       .get(key));
2014     }
2015     else
2016     {
2017       Cache.log.error(
2018               "Preset '" + value + "' [key:" + key + "] not implemented");
2019     }
2020
2021     // Custom options will now be enabled when the customiseCheckbox is checked
2022     // (performed above)
2023     // backupfilesCustomOptionsSetEnabled();
2024     updateBackupFilesExampleLabel();
2025   }
2026
2027   protected int getComboIntStringKey(
2028           JComboBox<Object> backupfilesPresetsCombo2)
2029   {
2030     IntKeyStringValueEntry e;
2031     try
2032     {
2033       e = (IntKeyStringValueEntry) backupfilesPresetsCombo2
2034               .getSelectedItem();
2035     } catch (Exception ex)
2036     {
2037       Cache.log.error(
2038               "Problem casting Combo entry to IntKeyStringValueEntry.");
2039       e = null;
2040     }
2041     return e != null ? e.k : 0;
2042   }
2043
2044   protected void setComboIntStringKey(
2045           JComboBox<Object> backupfilesPresetsCombo2,
2046           int key)
2047   {
2048     for (int i = 0; i < backupfilesPresetsCombo2.getItemCount(); i++)
2049     {
2050       IntKeyStringValueEntry e;
2051       try
2052       {
2053         e = (IntKeyStringValueEntry) backupfilesPresetsCombo2.getItemAt(i);
2054       } catch (Exception ex)
2055       {
2056         Cache.log.error(
2057                 "Problem casting Combo entry to IntKeyStringValueEntry. Skipping item. ");
2058         continue;
2059       }
2060       if (e.k == key)
2061       {
2062         backupfilesPresetsCombo2.setSelectedIndex(i);
2063         break;
2064       }
2065     }
2066     // backupsTabUpdatePresets();
2067   }
2068
2069   private JPanel initBackupsTabSuffixPanel()
2070   {
2071     suffixPanel.setBorder(new TitledBorder(
2072             MessageManager.getString("label.backup_filename_strategy")));
2073     suffixPanel.setLayout(new GridBagLayout());
2074
2075     suffixTemplateLabel
2076             .setText(MessageManager.getString("label.append_to_filename"));
2077     suffixTemplateLabel.setHorizontalAlignment(SwingConstants.LEFT);
2078     suffixTemplateLabel.setFont(LABEL_FONT);
2079
2080     final String tooltip = JvSwingUtils.wrapTooltip(true,
2081             MessageManager.getString("label.append_to_filename_tooltip"));
2082     suffixTemplate.setToolTipText(tooltip);
2083     suffixTemplate.addActionListener(new ActionListener()
2084     {
2085       @Override
2086       public void actionPerformed(ActionEvent e)
2087       {
2088         updateBackupFilesExampleLabel();
2089         backupfilesCustomOptionsSetEnabled();
2090         backupfilesRevertButtonSetEnabled(true);
2091       }
2092
2093     });
2094     suffixTemplate.addKeyListener(new KeyListener()
2095     {
2096       @Override
2097       public void keyReleased(KeyEvent e)
2098       {
2099         updateBackupFilesExampleLabel();
2100         backupfilesCustomOptionsSetEnabled();
2101         backupfilesRevertButtonSetEnabled(true);
2102       }
2103
2104       @Override
2105       public void keyPressed(KeyEvent e)
2106       {
2107       }
2108
2109       // disable use of ':' or '/' or '\'
2110       @Override
2111       public void keyTyped(KeyEvent e)
2112       {
2113         char c = e.getKeyChar();
2114         if (c == ':' || c == '/' || c == '\\')
2115         {
2116           // don't process ':' or '/' or '\'
2117           e.consume();
2118         }
2119       }
2120
2121     });
2122
2123     // digits spinner
2124     suffixDigitsLabel
2125             .setText(MessageManager.getString("label.index_digits"));
2126     suffixDigitsLabel.setHorizontalAlignment(SwingConstants.LEFT);
2127     suffixDigitsLabel.setFont(LABEL_FONT);
2128     ChangeListener c = new ChangeListener()
2129     {
2130       @Override
2131       public void stateChanged(ChangeEvent e)
2132       {
2133         backupfilesRevertButtonSetEnabled(true);
2134         updateBackupFilesExampleLabel();
2135       }
2136
2137     };
2138     setIntegerSpinner(suffixDigitsSpinner, BackupFilesPresetEntry.DIGITSMIN,
2139             BackupFilesPresetEntry.DIGITSMAX, 3, c);
2140
2141     suffixReverse.setLabels(MessageManager.getString("label.reverse_roll"),
2142             MessageManager.getString("label.increment_index"));
2143     suffixReverse.addActionListener(new ActionListener()
2144     {
2145       @Override
2146       public void actionPerformed(ActionEvent e)
2147       {
2148         boolean okay = true;
2149         if (warnAboutSuffixReverseChange())
2150         {
2151           // Warning popup
2152           okay = confirmSuffixReverseChange();
2153         }
2154         if (okay)
2155         {
2156           backupfilesRevertButtonSetEnabled(true);
2157           updateBackupFilesExampleLabel();
2158         }
2159         else
2160         {
2161           boolean savedSuffixReverse = BackupFilesPresetEntry
2162                   .getSavedBackupEntry().reverse;
2163           suffixReverse.setSelected(savedSuffixReverse);
2164         }
2165       }
2166     });
2167
2168     GridBagConstraints sgbc = new GridBagConstraints();
2169
2170     // first row (template text box)
2171     sgbc.anchor = GridBagConstraints.WEST;
2172     sgbc.gridx = 0;
2173     sgbc.gridy = 0;
2174     sgbc.gridwidth = 1;
2175     sgbc.gridheight = 1;
2176     sgbc.weightx = 1.0;
2177     sgbc.weighty = 0.0;
2178     sgbc.fill = GridBagConstraints.NONE;
2179     suffixPanel.add(suffixTemplateLabel, sgbc);
2180
2181     sgbc.gridx = 1;
2182     sgbc.fill = GridBagConstraints.HORIZONTAL;
2183     suffixPanel.add(suffixTemplate, sgbc);
2184
2185     // second row (number of digits spinner)
2186     sgbc.gridy = 1;
2187
2188     sgbc.gridx = 0;
2189     sgbc.fill = GridBagConstraints.NONE;
2190     suffixPanel.add(suffixDigitsLabel, sgbc);
2191
2192     sgbc.gridx = 1;
2193     sgbc.fill = GridBagConstraints.HORIZONTAL;
2194     suffixPanel.add(suffixDigitsSpinner, sgbc);
2195
2196     // third row (forward order radio selection)
2197     sgbc.gridx = 0;
2198     sgbc.gridy = 2;
2199     sgbc.gridwidth = GridBagConstraints.REMAINDER;
2200     sgbc.fill = GridBagConstraints.HORIZONTAL;
2201     suffixPanel.add(suffixReverse.getFalseButton(), sgbc);
2202
2203     // fourth row (reverse order radio selection)
2204     sgbc.gridy = 3;
2205     suffixPanel.add(suffixReverse.getTrueButton(), sgbc);
2206     return suffixPanel;
2207   }
2208
2209   private boolean confirmSuffixReverseChange()
2210   {
2211     boolean ret = false;
2212     String warningMessage = MessageManager
2213             .getString("label.warning_confirm_change_reverse");
2214     int confirm = JvOptionPane.showConfirmDialog(Desktop.desktop,
2215             warningMessage,
2216             MessageManager.getString("label.change_increment_decrement"),
2217             JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE);
2218
2219     ret = (confirm == JvOptionPane.YES_OPTION);
2220     return ret;
2221   }
2222
2223   private JPanel initBackupsTabKeepFilesPanel()
2224   {
2225     keepfilesPanel.setBorder(
2226             new TitledBorder(MessageManager.getString("label.keep_files")));
2227     keepfilesPanel.setLayout(new GridBagLayout());
2228
2229     backupfilesKeepAll.setLabels(
2230             MessageManager.getString("label.keep_all_backup_files"),
2231             MessageManager.getString(
2232                     "label.keep_only_this_number_of_backup_files"));
2233     backupfilesKeepAll.addTrueActionListener(new ActionListener()
2234     {
2235       @Override
2236       public void actionPerformed(ActionEvent e)
2237       {
2238         backupfilesRevertButtonSetEnabled(true);
2239         updateBackupFilesExampleLabel();
2240       }
2241     });
2242     backupfilesKeepAll.addActionListener(new ActionListener()
2243     {
2244       @Override
2245       public void actionPerformed(ActionEvent e)
2246       {
2247         backupfilesRevertButtonSetEnabled(true);
2248         keepRollMaxOptionsEnabled();
2249         updateBackupFilesExampleLabel();
2250       }
2251     });
2252
2253     ChangeListener c = new ChangeListener()
2254     {
2255       @Override
2256       public void stateChanged(ChangeEvent e)
2257       {
2258         backupfilesRevertButtonSetEnabled(true);
2259         updateBackupFilesExampleLabel();
2260       }
2261
2262     };
2263     setIntegerSpinner(backupfilesRollMaxSpinner,
2264             BackupFilesPresetEntry.ROLLMAXMIN,
2265             BackupFilesPresetEntry.ROLLMAXMAX, 4, true, c);
2266
2267     backupfilesConfirmDelete.setLabels(
2268             MessageManager.getString("label.always_ask"),
2269             MessageManager.getString("label.auto_delete"));
2270     backupfilesConfirmDelete.addActionListener(new ActionListener()
2271     {
2272       @Override
2273       public void actionPerformed(ActionEvent e)
2274       {
2275         backupfilesRevertButtonSetEnabled(true);
2276       }
2277     });
2278     // update the enabled section
2279     keepRollMaxOptionsEnabled();
2280
2281     GridBagConstraints kgbc = new GridBagConstraints();
2282
2283     // first row (template text box)
2284     kgbc.anchor = GridBagConstraints.WEST;
2285     kgbc.gridx = 0;
2286     kgbc.gridy = 0;
2287     kgbc.gridwidth = GridBagConstraints.REMAINDER;
2288     kgbc.gridheight = 1;
2289     kgbc.weightx = 1.0;
2290     kgbc.weighty = 0.0;
2291     kgbc.fill = GridBagConstraints.HORIZONTAL;
2292     keepfilesPanel.add(backupfilesKeepAll.getTrueButton(), kgbc);
2293
2294     // second row
2295     kgbc.gridy = 1;
2296
2297     kgbc.gridx = 0;
2298     kgbc.gridwidth = GridBagConstraints.RELATIVE;
2299     keepfilesPanel.add(backupfilesKeepAll.getFalseButton(), kgbc);
2300
2301     kgbc.gridx = 1;
2302     kgbc.gridwidth = GridBagConstraints.REMAINDER;
2303     keepfilesPanel.add(backupfilesRollMaxSpinner, kgbc);
2304
2305     // third row (indented)
2306     kgbc.gridy = 2;
2307     kgbc.insets = new Insets(0, 20, 0, 0);
2308
2309     kgbc.gridx = 0;
2310     kgbc.gridwidth = GridBagConstraints.REMAINDER;
2311     kgbc.fill = GridBagConstraints.HORIZONTAL;
2312     kgbc.weightx = 1.0;
2313
2314     JPanel jp = new JPanel();
2315     jp.setLayout(new FlowLayout());
2316     oldBackupFilesLabel
2317             .setText(MessageManager
2318                     .getString("label.autodelete_old_backup_files"));
2319     oldBackupFilesLabel.setFont(LABEL_FONT);
2320     oldBackupFilesLabel.setHorizontalAlignment(SwingConstants.LEFT);
2321     jp.add(oldBackupFilesLabel);
2322     jp.add(backupfilesConfirmDelete.getTrueButton());
2323     jp.add(backupfilesConfirmDelete.getFalseButton());
2324     keepfilesPanel.add(jp, kgbc);
2325
2326     return keepfilesPanel;
2327   }
2328
2329   protected void updateBackupFilesExampleLabel()
2330   {
2331     int exampleindex = 12;
2332     String base = MessageManager.getString("label.filename") + ".fa";
2333     if (base == null || base.length() == 0)
2334     {
2335       base = "file_name.fa";
2336     }
2337
2338     boolean reverse = suffixReverse.isSelected();
2339     boolean keepAll = backupfilesKeepAll.isSelected();
2340     int rollMax = 4;
2341     String suffix = suffixTemplate.getText();
2342     int digits = 3;
2343
2344     backupfilesExampleLabel.setFont(LABEL_FONT_ITALIC);
2345     if (suffix == null || suffix.length() == 0)
2346     {
2347       backupfilesExampleLabel
2348               .setText(MessageManager.getString("label.no_backup_files"));
2349       backupfilesExampleLabel.setFont(LABEL_FONT_BOLD);
2350       return;
2351     }
2352
2353     rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 4);
2354     rollMax = rollMax < 1 ? 1 : rollMax;
2355
2356     if (suffix.indexOf(BackupFiles.NUM_PLACEHOLDER) == -1)
2357     {
2358       rollMax = 1;
2359     }
2360
2361     digits = getSpinnerInt(suffixDigitsSpinner, 3);
2362     digits = digits < 1 ? 1 : digits;
2363
2364     int lowersurround = 2;
2365     int uppersurround = 0;
2366     StringBuilder exampleSB = new StringBuilder();
2367     boolean firstLine = true;
2368     int lineNumber = 0;
2369     if (reverse)
2370     {
2371
2372       int min = 1;
2373       int max = keepAll ? exampleindex : rollMax;
2374       for (int index = min; index <= max; index++)
2375       {
2376         if (index == min + lowersurround && index < max - uppersurround - 1)
2377         {
2378           exampleSB.append("\n...");
2379           lineNumber++;
2380         }
2381         else if (index > min + lowersurround && index < max - uppersurround)
2382         {
2383           // nothing
2384         }
2385         else
2386         {
2387           if (firstLine)
2388           {
2389             firstLine = false;
2390           }
2391           else
2392           {
2393             exampleSB.append("\n");
2394             lineNumber++;
2395           }
2396           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
2397                   base, suffix, digits));
2398           if (min == max)
2399           {
2400             // no extra text needed
2401           }
2402           else if (index == min)
2403           {
2404             String newest = MessageManager.getString("label.braced_newest");
2405             if (newest != null && newest.length() > 0)
2406             {
2407               exampleSB.append(" " + newest);
2408             }
2409           }
2410           else if (index == max)
2411           {
2412             String oldest = MessageManager.getString("label.braced_oldest");
2413             if (oldest != null && oldest.length() > 0)
2414             {
2415               exampleSB.append(" " + oldest);
2416             }
2417           }
2418         }
2419       }
2420     }
2421     else
2422     {
2423
2424       int min = (keepAll || exampleindex - rollMax < 0) ? 1
2425               : exampleindex - rollMax + 1;
2426       int max = exampleindex;
2427
2428       for (int index = min; index <= max; index++)
2429       {
2430
2431         if (index == min + lowersurround && index < max - uppersurround - 1)
2432         {
2433           exampleSB.append("\n...");
2434           lineNumber++;
2435         }
2436         else if (index > min + lowersurround && index < max - uppersurround)
2437         {
2438           // nothing
2439         }
2440         else
2441         {
2442           if (firstLine)
2443           {
2444             firstLine = false;
2445           }
2446           else
2447           {
2448             exampleSB.append("\n");
2449             lineNumber++;
2450           }
2451           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
2452                   base, suffix, digits));
2453           if (min == max)
2454           {
2455             // no extra text needed
2456           }
2457           else if (index == min)
2458           {
2459             String oldest = MessageManager.getString("label.braced_oldest");
2460             if (oldest != null && oldest.length() > 0)
2461             {
2462               exampleSB.append(" " + oldest);
2463             }
2464           }
2465           else if (index == max)
2466           {
2467             String newest = MessageManager.getString("label.braced_newest");
2468             if (newest != null && newest.length() > 0)
2469             {
2470               exampleSB.append(" " + newest);
2471             }
2472           }
2473         }
2474       }
2475
2476     }
2477
2478     // add some extra empty lines to pad out the example files box. ugh, please tell
2479     // me how to do this better
2480     int remainingLines = lowersurround + uppersurround + 1 - lineNumber;
2481     if (remainingLines > 0)
2482     {
2483       for (int i = 0; i < remainingLines; i++)
2484       {
2485         exampleSB.append("\n ");
2486         lineNumber++;
2487       }
2488     }
2489
2490     backupfilesExampleLabel.setText(exampleSB.toString());
2491   }
2492
2493   protected void setIntegerSpinner(JSpinner s, int min, int max, int def,
2494           boolean useExistingVal, ChangeListener c)
2495   {
2496     int i = def;
2497     if (useExistingVal)
2498     {
2499       try
2500       {
2501         i = ((Integer) s.getValue()).intValue();
2502       } catch (Exception e)
2503       {
2504         Cache.log.error(
2505                 "Exception casting the initial value of s.getValue()");
2506       }
2507     }
2508
2509     setIntegerSpinner(s, min, max, i, c);
2510   }
2511
2512   protected void setIntegerSpinner(JSpinner s, int min, int max, int def,
2513           ChangeListener c)
2514   {
2515     // integer spinner for number of digits
2516     if (def > max)
2517     {
2518       max = def;
2519     }
2520     if (def < min)
2521     {
2522       def = min;
2523     }
2524     SpinnerModel sModel = new SpinnerNumberModel(def, min, max, 1);
2525     s.setModel(sModel);
2526
2527     s.addChangeListener(c);
2528
2529   }
2530
2531   protected static int getSpinnerInt(JSpinner s, int def)
2532   {
2533     int i = def;
2534     try
2535     {
2536       s.commitEdit();
2537       i = (Integer) s.getValue();
2538     } catch (Exception e)
2539     {
2540       Cache.log.error("Failed casting (Integer) JSpinner s.getValue()");
2541     }
2542     return i;
2543   }
2544
2545   private void keepRollMaxOptionsEnabled()
2546   {
2547     boolean enabled = backupfilesKeepAll.isEnabled()
2548             && !backupfilesKeepAll.isSelected();
2549     oldBackupFilesLabel.setEnabled(enabled);
2550     backupfilesRollMaxSpinner.setEnabled(enabled);
2551     backupfilesConfirmDelete.setEnabled(enabled);
2552   }
2553
2554   private void backupfilesKeepAllSetEnabled(boolean tryEnabled)
2555   {
2556     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
2557             && customiseCheckbox.isSelected()
2558             && suffixTemplate.getText()
2559                     .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
2560     keepfilesPanel.setEnabled(enabled);
2561     backupfilesKeepAll.setEnabled(enabled);
2562     oldBackupFilesLabel.setEnabled(enabled);
2563     keepRollMaxOptionsEnabled();
2564   }
2565
2566   private void backupfilesSuffixTemplateDigitsSetEnabled()
2567   {
2568     boolean enabled = suffixTemplate.isEnabled() && suffixTemplate.getText()
2569             .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
2570     suffixDigitsLabel.setEnabled(enabled);
2571     suffixDigitsSpinner.setEnabled(enabled);
2572     suffixReverse.setEnabled(enabled);
2573   }
2574
2575   private void backupfilesSuffixTemplateSetEnabled(boolean tryEnabled)
2576   {
2577     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
2578             && customiseCheckbox.isSelected();
2579     suffixPanel.setEnabled(enabled);
2580     suffixTemplateLabel.setEnabled(enabled);
2581     suffixTemplate.setEnabled(enabled);
2582     backupfilesSuffixTemplateDigitsSetEnabled();
2583   }
2584
2585   private void backupfilesRevertButtonSetEnabled(boolean tryEnabled)
2586   {
2587     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
2588             && customiseCheckbox.isSelected() && backupfilesCustomChanged();
2589     revertButton.setEnabled(enabled);
2590   }
2591
2592   private boolean backupfilesCustomChanged()
2593   {
2594     BackupFilesPresetEntry custom = BackupFilesPresetEntry.backupfilesPresetEntriesValues
2595             .get(BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
2596     BackupFilesPresetEntry current = getBackupfilesCurrentEntry();
2597     return !custom.equals(current);
2598   }
2599
2600   protected BackupFilesPresetEntry getBackupfilesCurrentEntry()
2601   {
2602     String suffix = suffixTemplate.getText();
2603     int digits = getSpinnerInt(suffixDigitsSpinner, 3);
2604     boolean reverse = suffixReverse.isSelected();
2605     boolean keepAll = backupfilesKeepAll.isSelected();
2606     int rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 3);
2607     boolean confirmDelete = backupfilesConfirmDelete.isSelected();
2608
2609     BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits,
2610             reverse, keepAll, rollMax, confirmDelete);
2611
2612     return bfpe;
2613   }
2614
2615   protected void backupfilesCustomOptionsSetEnabled()
2616   {
2617     boolean enabled = customiseCheckbox.isSelected();
2618
2619     backupfilesRevertButtonSetEnabled(enabled);
2620     backupfilesSuffixTemplateSetEnabled(enabled);
2621     backupfilesKeepAllSetEnabled(enabled);
2622   }
2623
2624   private void backupfilesSummarySetEnabled()
2625   {
2626     boolean enabled = enableBackupFiles.isSelected();
2627     backupfilesExampleLabel.setEnabled(enabled);
2628     exampleFilesPanel.setEnabled(enabled);
2629   }
2630
2631   private void backupfilesPresetsSetEnabled()
2632   {
2633     boolean enabled = enableBackupFiles.isSelected();
2634     presetsPanel.setEnabled(enabled);
2635     presetsComboLabel.setEnabled(enabled);
2636     backupfilesPresetsCombo.setEnabled(enabled);
2637     customiseCheckbox.setEnabled(enabled);
2638     revertButton.setEnabled(enabled);
2639   }
2640
2641   protected void backupsOptionsSetEnabled()
2642   {
2643     backupfilesPresetsSetEnabled();
2644     backupfilesSummarySetEnabled();
2645     backupfilesCustomOptionsSetEnabled();
2646   }
2647
2648   protected void backupsSetOptions(String suffix, int digits,
2649           boolean reverse, boolean keepAll, int rollMax,
2650           boolean confirmDelete)
2651   {
2652     suffixTemplate.setText(suffix);
2653     suffixDigitsSpinner.setValue(digits);
2654     suffixReverse.setSelected(reverse);
2655     backupfilesKeepAll.setSelected(keepAll);
2656     backupfilesRollMaxSpinner.setValue(rollMax);
2657     backupfilesConfirmDelete.setSelected(confirmDelete);
2658   }
2659
2660   protected void backupsSetOptions(BackupFilesPresetEntry p)
2661   {
2662     backupsSetOptions(p.suffix, p.digits, p.reverse, p.keepAll, p.rollMax,
2663             p.confirmDelete);
2664   }
2665
2666   protected void autoIdWidth_actionPerformed()
2667   {
2668     // TODO Auto-generated method stub
2669
2670   }
2671
2672   protected void userIdWidth_actionPerformed()
2673   {
2674     // TODO Auto-generated method stub
2675
2676   }
2677
2678   protected void maxColour_actionPerformed(JPanel panel)
2679   {
2680   }
2681
2682   protected void minColour_actionPerformed(JPanel panel)
2683   {
2684   }
2685
2686   protected void gapColour_actionPerformed(JPanel panel)
2687   {
2688   }
2689
2690   protected void hiddenColour_actionPerformed(JPanel panel)
2691   {
2692   }
2693
2694   protected void showunconserved_actionPerformed(ActionEvent e)
2695   {
2696     // TODO Auto-generated method stub
2697
2698   }
2699
2700   protected void useLegacyGaps_actionPerformed(ActionEvent e)
2701   {
2702   }
2703
2704   protected void resetOvDefaults_actionPerformed(ActionEvent e)
2705   {
2706   }
2707
2708   /**
2709    * DOCUMENT ME!
2710    * 
2711    * @param e
2712    *          DOCUMENT ME!
2713    */
2714   public void ok_actionPerformed(ActionEvent e)
2715   {
2716   }
2717
2718   /**
2719    * DOCUMENT ME!
2720    * 
2721    * @param e
2722    *          DOCUMENT ME!
2723    */
2724   public void cancel_actionPerformed(ActionEvent e)
2725   {
2726   }
2727
2728   /**
2729    * DOCUMENT ME!
2730    * 
2731    * @param e
2732    *          DOCUMENT ME!
2733    */
2734   public void annotations_actionPerformed(ActionEvent e)
2735   {
2736   }
2737
2738   /**
2739    * DOCUMENT ME!
2740    */
2741   public void startupFileTextfield_mouseClicked()
2742   {
2743   }
2744
2745   public void newLink_actionPerformed(ActionEvent e)
2746   {
2747
2748   }
2749
2750   public void editLink_actionPerformed(ActionEvent e)
2751   {
2752
2753   }
2754
2755   public void deleteLink_actionPerformed(ActionEvent e)
2756   {
2757
2758   }
2759
2760   public void defaultBrowser_mouseClicked(MouseEvent e)
2761   {
2762
2763   }
2764
2765   public void linkURLList_keyTyped(KeyEvent e)
2766   {
2767
2768   }
2769
2770   public void useProxy_actionPerformed()
2771   {
2772     boolean enabled = useProxy.isSelected();
2773     portLabel.setEnabled(enabled);
2774     serverLabel.setEnabled(enabled);
2775     proxyServerTB.setEnabled(enabled);
2776     proxyPortTB.setEnabled(enabled);
2777   }
2778
2779   /**
2780    * Customer renderer for JTable: supports column of radio buttons
2781    */
2782   public class RadioButtonRenderer extends JRadioButton
2783           implements TableCellRenderer
2784   {
2785     public RadioButtonRenderer()
2786     {
2787       setHorizontalAlignment(CENTER);
2788       setToolTipText(MessageManager.getString("label.urltooltip"));
2789     }
2790
2791     @Override
2792     public Component getTableCellRendererComponent(JTable table,
2793             Object value, boolean isSelected, boolean hasFocus, int row,
2794             int column)
2795     {
2796       setSelected((boolean) value);
2797
2798       // set colours to match rest of table
2799       if (isSelected)
2800       {
2801         setBackground(table.getSelectionBackground());
2802         setForeground(table.getSelectionForeground());
2803       }
2804       else
2805       {
2806         setBackground(table.getBackground());
2807         setForeground(table.getForeground());
2808       }
2809       return this;
2810     }
2811   }
2812
2813   /**
2814    * Customer cell editor for JTable: supports column of radio buttons in
2815    * conjunction with renderer
2816    */
2817   public class RadioButtonEditor extends AbstractCellEditor
2818           implements TableCellEditor
2819   {
2820     private JRadioButton button = new JRadioButton();
2821
2822     public RadioButtonEditor()
2823     {
2824       button.setHorizontalAlignment(SwingConstants.CENTER);
2825       this.button.addActionListener(new ActionListener()
2826       {
2827         @Override
2828         public void actionPerformed(ActionEvent e)
2829         {
2830           fireEditingStopped();
2831         }
2832       });
2833     }
2834
2835     @Override
2836     public Component getTableCellEditorComponent(JTable table, Object value,
2837             boolean isSelected, int row, int column)
2838     {
2839       button.setSelected((boolean) value);
2840       return button;
2841     }
2842
2843     @Override
2844     public Object getCellEditorValue()
2845     {
2846       return button.isSelected();
2847     }
2848
2849   }
2850 }
2851