JAL-4159 fix PairwiseAlignmentPanelTest - reinstate correct recording of the endRes...
[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.EnumSet;
43 import java.util.List;
44
45 import javax.swing.AbstractCellEditor;
46 import javax.swing.BorderFactory;
47 import javax.swing.BoxLayout;
48 import javax.swing.ButtonGroup;
49 import javax.swing.DefaultListCellRenderer;
50 import javax.swing.JButton;
51 import javax.swing.JCheckBox;
52 import javax.swing.JComboBox;
53 import javax.swing.JFileChooser;
54 import javax.swing.JLabel;
55 import javax.swing.JPanel;
56 import javax.swing.JPasswordField;
57 import javax.swing.JRadioButton;
58 import javax.swing.JScrollPane;
59 import javax.swing.JSlider;
60 import javax.swing.JSpinner;
61 import javax.swing.JTabbedPane;
62 import javax.swing.JTable;
63 import javax.swing.JTextArea;
64 import javax.swing.JTextField;
65 import javax.swing.ListSelectionModel;
66 import javax.swing.SpinnerModel;
67 import javax.swing.SpinnerNumberModel;
68 import javax.swing.SwingConstants;
69 import javax.swing.border.Border;
70 import javax.swing.border.EmptyBorder;
71 import javax.swing.border.EtchedBorder;
72 import javax.swing.border.TitledBorder;
73 import javax.swing.event.ChangeEvent;
74 import javax.swing.event.ChangeListener;
75 import javax.swing.event.DocumentEvent;
76 import javax.swing.event.DocumentListener;
77 import javax.swing.table.TableCellEditor;
78 import javax.swing.table.TableCellRenderer;
79
80 import jalview.bin.Cache;
81 import jalview.bin.Console;
82 import jalview.bin.MemorySetting;
83 import jalview.fts.core.FTSDataColumnPreferences;
84 import jalview.fts.core.FTSDataColumnPreferences.PreferenceSource;
85 import jalview.fts.service.pdb.PDBFTSRestClient;
86 import jalview.gui.Desktop;
87 import jalview.gui.JalviewBooleanRadioButtons;
88 import jalview.gui.JvOptionPane;
89 import jalview.gui.JvSwingUtils;
90 import jalview.gui.StructureViewer.ViewerType;
91 import jalview.io.BackupFilenameParts;
92 import jalview.io.BackupFiles;
93 import jalview.io.BackupFilesPresetEntry;
94 import jalview.io.IntKeyStringValueEntry;
95 import jalview.util.MessageManager;
96 import jalview.util.Platform;
97 import jalview.util.StringUtils;
98
99 /**
100  * Base class for the Preferences panel.
101  * 
102  * @author $author$
103  * @version $Revision$
104  */
105 public class GPreferences extends JPanel
106 {
107   private static final Font LABEL_FONT = JvSwingUtils.getLabelFont();
108
109   private static final Font LABEL_FONT_ITALIC = JvSwingUtils
110           .getLabelFont(false, true);
111
112   private static final Font LABEL_FONT_BOLD = JvSwingUtils
113           .getLabelFont(true, false);
114
115   /*
116    * Visual tab components
117    */
118   protected JCheckBox fullScreen = new JCheckBox();
119
120   protected JCheckBox openoverv = new JCheckBox();
121
122   protected JCheckBox seqLimit = new JCheckBox();
123
124   protected JCheckBox rightAlign = new JCheckBox();
125
126   protected JComboBox<String> fontSizeCB = new JComboBox<>();
127
128   protected JComboBox<String> fontStyleCB = new JComboBox<>();
129
130   protected JComboBox<String> fontNameCB = new JComboBox<>();
131
132   protected JCheckBox showOccupancy = new JCheckBox();
133
134   protected JCheckBox showUnconserved = new JCheckBox();
135
136   protected JCheckBox idItalics = new JCheckBox();
137
138   protected JCheckBox smoothFont = new JCheckBox();
139
140   protected JCheckBox scaleProteinToCdna = new JCheckBox();
141
142   protected JComboBox<String> gapSymbolCB = new JComboBox<>();
143
144   protected JCheckBox wrap = new JCheckBox();
145
146   protected JComboBox<String> sortby = new JComboBox<>();
147
148   protected JComboBox<String> sortAnnBy = new JComboBox<>();
149
150   protected JComboBox<String> sortAutocalc = new JComboBox<>();
151
152   protected JCheckBox startupCheckbox = new JCheckBox();
153
154   protected JTextField startupFileTextfield = new JTextField();
155
156   // below are in the 'second column'
157   protected JCheckBox annotations = new JCheckBox();
158
159   protected JCheckBox quality = new JCheckBox();
160
161   protected JCheckBox conservation = new JCheckBox();
162
163   protected JCheckBox identity = new JCheckBox();  
164
165   protected JCheckBox ssConsensus = new JCheckBox();
166
167   protected JCheckBox showGroupConsensus = new JCheckBox();
168
169   protected JCheckBox showGroupConservation = new JCheckBox();
170
171   protected JCheckBox showConsensHistogram = new JCheckBox();
172
173   protected JCheckBox showConsensLogo = new JCheckBox();
174
175   protected JCheckBox showDbRefTooltip = new JCheckBox();
176
177   protected JCheckBox showNpTooltip = new JCheckBox();
178
179   /*
180    * Structure tab and components
181    */
182   protected JPanel structureTab;
183
184   protected JCheckBox structFromPdb = new JCheckBox();
185
186   protected JCheckBox addSecondaryStructure = new JCheckBox();
187
188   protected JCheckBox addTempFactor = new JCheckBox();
189
190   protected JComboBox<String> structViewer = new JComboBox<>();
191
192   protected JLabel structureViewerPathLabel;
193
194   protected JTextField structureViewerPath = new JTextField();
195
196   protected ButtonGroup mappingMethod = new ButtonGroup();
197
198   protected JRadioButton siftsMapping = new JRadioButton();
199
200   protected JRadioButton nwMapping = new JRadioButton();
201
202   /*
203    * Colours tab components
204    */
205   protected JPanel minColour = new JPanel();
206
207   protected JPanel maxColour = new JPanel();
208
209   protected JComboBox<String> protColour = new JComboBox<>();
210
211   protected JComboBox<String> nucColour = new JComboBox<>();
212
213   /*
214    * Overview tab components
215    */
216   protected JPanel gapColour = new JPanel();
217
218   protected JPanel hiddenColour = new JPanel();
219
220   protected JCheckBox useLegacyGap;
221
222   protected JCheckBox showHiddenAtStart;
223
224   protected JLabel gapLabel;
225
226   /*
227    * Connections tab components
228    */
229   protected JPanel connectTab;
230
231   protected JTable linkUrlTable = new JTable();
232
233   protected JButton editLink = new JButton();
234
235   protected JButton deleteLink = new JButton();
236
237   protected JTextField filterTB = new JTextField();
238
239   protected JButton doReset = new JButton();
240
241   protected JButton userOnly = new JButton();
242
243   protected JLabel httpLabel = new JLabel();
244
245   protected JLabel httpsLabel = new JLabel();
246
247   protected JLabel portLabel = new JLabel();
248
249   protected JLabel serverLabel = new JLabel();
250
251   protected JLabel portLabel2 = new JLabel();
252
253   protected JLabel serverLabel2 = new JLabel();
254
255   protected JLabel proxyAuthUsernameLabel = new JLabel();
256
257   protected JLabel proxyAuthPasswordLabel = new JLabel();
258
259   protected JLabel passwordNotStoredLabel = new JLabel();
260
261   protected JTextField proxyServerHttpTB = new JTextField();
262
263   protected JTextField proxyPortHttpTB = new JTextField();
264
265   protected JTextField proxyServerHttpsTB = new JTextField();
266
267   protected JTextField proxyPortHttpsTB = new JTextField();
268
269   protected JCheckBox proxyAuth = new JCheckBox();
270
271   protected JTextField proxyAuthUsernameTB = new JTextField();
272
273   protected JPasswordField proxyAuthPasswordPB = new JPasswordField();
274
275   protected ButtonGroup proxyType = new ButtonGroup();
276
277   protected JRadioButton noProxy = new JRadioButton();
278
279   protected JRadioButton systemProxy = new JRadioButton();
280
281   protected JRadioButton customProxy = new JRadioButton();
282
283   protected JButton applyProxyButton = new JButton();
284
285   protected JCheckBox usagestats = new JCheckBox();
286
287   protected JCheckBox questionnaire = new JCheckBox();
288
289   protected JCheckBox versioncheck = new JCheckBox();
290
291   /*
292    * Output tab components
293    */
294   protected JComboBox<Object> epsRendering = new JComboBox<>();
295
296   protected JComboBox<Object> htmlRendering = new JComboBox<>();
297
298   protected JComboBox<Object> svgRendering = new JComboBox<>();
299
300   protected JLabel userIdWidthlabel = new JLabel();
301
302   protected JCheckBox autoIdWidth = new JCheckBox();
303
304   protected JTextField userIdWidth = new JTextField();
305
306   protected JCheckBox blcjv = new JCheckBox();
307
308   protected JCheckBox pileupjv = new JCheckBox();
309
310   protected JCheckBox clustaljv = new JCheckBox();
311
312   protected JCheckBox msfjv = new JCheckBox();
313
314   protected JCheckBox fastajv = new JCheckBox();
315
316   protected JCheckBox pfamjv = new JCheckBox();
317
318   protected JCheckBox pirjv = new JCheckBox();
319
320   protected JCheckBox modellerOutput = new JCheckBox();
321
322   protected JCheckBox embbedBioJSON = new JCheckBox();
323
324   /*
325    * Editing tab components
326    */
327   protected JCheckBox autoCalculateConsCheck = new JCheckBox();
328
329   protected JCheckBox padGaps = new JCheckBox();
330
331   protected JCheckBox sortByTree = new JCheckBox();
332
333   /*
334    * Web Services tab
335    */
336   protected JPanel wsTab = new JPanel();
337
338   /*
339    * Backups tab components
340    * a lot of these are member variables instead of local variables only so that they
341    * can be enabled/disabled easily in one go
342    */
343
344   protected JCheckBox enableBackupFiles = new JCheckBox();
345
346   protected JPanel presetsPanel = new JPanel();
347
348   protected JLabel presetsComboLabel = new JLabel();
349
350   protected JCheckBox customiseCheckbox = new JCheckBox();
351
352   protected JButton revertButton = new JButton();
353
354   protected JComboBox<Object> backupfilesPresetsCombo = new JComboBox<>();
355
356   private int backupfilesPresetsComboLastSelected = 0;
357
358   protected JPanel suffixPanel = new JPanel();
359
360   protected JPanel keepfilesPanel = new JPanel();
361
362   protected JPanel exampleFilesPanel = new JPanel();
363
364   protected JTextField suffixTemplate = new JTextField(null, 8);
365
366   protected JLabel suffixTemplateLabel = new JLabel();
367
368   protected JLabel suffixDigitsLabel = new JLabel();
369
370   protected JSpinner suffixDigitsSpinner = new JSpinner();
371
372   protected JalviewBooleanRadioButtons suffixReverse = new JalviewBooleanRadioButtons();
373
374   protected JalviewBooleanRadioButtons backupfilesKeepAll = new JalviewBooleanRadioButtons();
375
376   public JSpinner backupfilesRollMaxSpinner = new JSpinner();
377
378   protected JLabel oldBackupFilesLabel = new JLabel();
379
380   protected JalviewBooleanRadioButtons backupfilesConfirmDelete = new JalviewBooleanRadioButtons();
381
382   protected JTextArea backupfilesExampleLabel = new JTextArea();
383
384   private final JTabbedPane tabbedPane = new JTabbedPane();
385
386   private JLabel messageLabel = new JLabel("", JLabel.CENTER);
387
388   /*
389    * Startup tab components
390    */
391
392   protected JCheckBox customiseMemorySetting = new JCheckBox();
393
394   protected JLabel exampleMemoryLabel = new JLabel();
395
396   protected JTextArea exampleMemoryMessageTextArea = new JTextArea();
397
398   protected JLabel maxMemoryLabel = new JLabel();
399
400   protected JLabel jvmMemoryPercentLabel = new JLabel();
401
402   protected JSlider jvmMemoryPercentSlider = new JSlider();
403
404   protected JLabel jvmMemoryPercentDisplay = new JLabel();
405
406   protected JLabel jvmMemoryMaxLabel = new JLabel();
407
408   protected JTextField jvmMemoryMaxTextField = new JTextField(null, 8);
409
410   protected JComboBox<Object> lafCombo = new JComboBox<>();
411
412   /**
413    * Creates a new GPreferences object.
414    */
415   public GPreferences()
416   {
417     try
418     {
419       jbInit();
420     } catch (Exception ex)
421     {
422       ex.printStackTrace();
423     }
424   }
425
426   /**
427    * Construct the panel and its tabbed sub-panels.
428    * 
429    * @throws Exception
430    */
431   private void jbInit() throws Exception
432   {
433     // final JTabbedPane tabbedPane = new JTabbedPane();
434     this.setLayout(new BorderLayout());
435
436     // message label at top
437     this.add(messageLabel, BorderLayout.NORTH);
438
439     JPanel okCancelPanel = initOkCancelPanel();
440     this.add(tabbedPane, BorderLayout.CENTER);
441     this.add(okCancelPanel, BorderLayout.SOUTH);
442
443     tabbedPane.add(initVisualTab(),
444             MessageManager.getString("label.visual"));
445
446     tabbedPane.add(initColoursTab(),
447             MessageManager.getString("label.colours"));
448
449     tabbedPane.add(initOverviewTab(),
450             MessageManager.getString("label.overview"));
451
452     tabbedPane.add(initStructureTab(),
453             MessageManager.getString("label.structure"));
454
455     tabbedPane.add(initConnectionsTab(),
456             MessageManager.getString("label.connections"));
457
458     if (!Platform.isJS())
459     {
460       tabbedPane.add(initBackupsTab(),
461               MessageManager.getString("label.backups"));
462     }
463
464     tabbedPane.add(initLinksTab(),
465             MessageManager.getString("label.urllinks"));
466
467     tabbedPane.add(initOutputTab(),
468             MessageManager.getString("label.output"));
469
470     tabbedPane.add(initEditingTab(),
471             MessageManager.getString("label.editing"));
472
473     tabbedPane.add(initStartupTab(),
474             MessageManager.getString("label.startup"));
475
476     /*
477      * See WsPreferences for the real work of configuring this tab.
478      */
479     if (!Platform.isJS())
480     {
481       wsTab.setLayout(new BorderLayout());
482       tabbedPane.add(wsTab, MessageManager.getString("label.web_services"));
483     }
484
485     /*
486      * Handler to validate a tab before leaving it - currently only for
487      * Structure.
488      * Adding a clearMessage() so messages are cleared when changing tabs.
489      */
490     tabbedPane.addChangeListener(new ChangeListener()
491     {
492       private Component lastTab;
493
494       @Override
495       public void stateChanged(ChangeEvent e)
496       {
497         if (lastTab == structureTab
498                 && tabbedPane.getSelectedComponent() != structureTab)
499         {
500           if (!validateStructure())
501           {
502             tabbedPane.setSelectedComponent(structureTab);
503             return;
504           }
505         }
506         lastTab = tabbedPane.getSelectedComponent();
507
508         clearMessage();
509       }
510
511     });
512   }
513
514   public void setMessage(String message)
515   {
516     if (message != null)
517     {
518       messageLabel.setText(message);
519       messageLabel.setFont(LABEL_FONT_BOLD);
520       messageLabel.setForeground(Color.RED.darker());
521       messageLabel.revalidate();
522       messageLabel.repaint();
523     }
524     // note message not cleared if message is null. call clearMessage()
525     // directly.
526     this.revalidate();
527     this.repaint();
528   }
529
530   public void clearMessage()
531   {
532     // only repaint if message exists
533     if (messageLabel.getText() != null
534             && messageLabel.getText().length() > 0)
535     {
536       messageLabel.setText("");
537       messageLabel.revalidate();
538       messageLabel.repaint();
539       this.revalidate();
540       this.repaint();
541     }
542   }
543
544   public static enum TabRef
545   {
546     CONNECTIONS_TAB, STRUCTURE_TAB
547   };
548
549   public void selectTab(TabRef selectTab)
550   {
551     // select a given tab - currently only for Connections
552     switch (selectTab)
553     {
554     case CONNECTIONS_TAB:
555       tabbedPane.setSelectedComponent(connectTab);
556       break;
557     case STRUCTURE_TAB:
558       tabbedPane.setSelectedComponent(structureTab);
559       break;
560     default:
561     }
562   }
563
564   /**
565    * Initialises the Editing tabbed panel.
566    * 
567    * @return
568    */
569   private JPanel initEditingTab()
570   {
571     JPanel editingTab = new JPanel();
572     editingTab.setLayout(null);
573     autoCalculateConsCheck.setFont(LABEL_FONT);
574     autoCalculateConsCheck.setText(
575             MessageManager.getString("label.autocalculate_consensus"));
576     autoCalculateConsCheck.setBounds(new Rectangle(21, 52, 209, 23));
577     padGaps.setFont(LABEL_FONT);
578     padGaps.setText(
579             MessageManager.getString("label.pad_gaps_when_editing"));
580     padGaps.setBounds(new Rectangle(22, 94, 168, 23));
581     sortByTree.setFont(LABEL_FONT);
582     sortByTree
583             .setText(MessageManager.getString("label.sort_with_new_tree"));
584     sortByTree.setToolTipText(MessageManager.getString(
585             "label.any_trees_calculated_or_loaded_alignment_automatically_sort"));
586     sortByTree.setBounds(new Rectangle(22, 136, 168, 23));
587     editingTab.add(autoCalculateConsCheck);
588     editingTab.add(padGaps);
589     editingTab.add(sortByTree);
590     return editingTab;
591   }
592
593   /**
594    * Initialises the Output tab
595    * 
596    * @return
597    */
598   private JPanel initOutputTab()
599   {
600     JPanel outputTab = new JPanel();
601     outputTab.setLayout(null);
602
603     JLabel epsLabel = new JLabel(
604             MessageManager.formatMessage("label.rendering_style", "EPS"));
605     epsLabel.setFont(LABEL_FONT);
606     epsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
607     epsLabel.setBounds(new Rectangle(9, 31, 160, 24));
608     epsRendering.setFont(LABEL_FONT);
609     epsRendering.setBounds(new Rectangle(174, 34, 187, 21));
610     JLabel htmlLabel = new JLabel(
611             MessageManager.formatMessage("label.rendering_style", "HTML"));
612     htmlLabel.setFont(LABEL_FONT);
613     htmlLabel.setHorizontalAlignment(SwingConstants.RIGHT);
614     htmlLabel.setBounds(new Rectangle(9, 55, 160, 24));
615     htmlRendering.setFont(LABEL_FONT);
616     htmlRendering.setBounds(new Rectangle(174, 58, 187, 21));
617     JLabel svgLabel = new JLabel(
618             MessageManager.formatMessage("label.rendering_style", "SVG"));
619     svgLabel.setFont(LABEL_FONT);
620     svgLabel.setHorizontalAlignment(SwingConstants.RIGHT);
621     svgLabel.setBounds(new Rectangle(9, 79, 160, 24));
622     svgRendering.setFont(LABEL_FONT);
623     svgRendering.setBounds(new Rectangle(174, 82, 187, 21));
624
625     JLabel jLabel1 = new JLabel();
626     jLabel1.setFont(LABEL_FONT);
627     jLabel1.setHorizontalAlignment(SwingConstants.CENTER);
628     jLabel1.setText(MessageManager.getString("label.append_start_end"));
629     jLabel1.setFont(LABEL_FONT);
630
631     fastajv.setFont(LABEL_FONT);
632     fastajv.setHorizontalAlignment(SwingConstants.LEFT);
633     clustaljv.setText(MessageManager.getString("label.clustal") + "     ");
634     blcjv.setText(MessageManager.getString("label.blc") + "     ");
635     fastajv.setText(MessageManager.getString("label.fasta") + "     ");
636     msfjv.setText(MessageManager.getString("label.msf") + "     ");
637     pfamjv.setText(MessageManager.getString("label.pfam") + "     ");
638     pileupjv.setText(MessageManager.getString("label.pileup") + "     ");
639     msfjv.setFont(LABEL_FONT);
640     msfjv.setHorizontalAlignment(SwingConstants.LEFT);
641     pirjv.setText(MessageManager.getString("label.pir") + "     ");
642     JPanel jPanel11 = new JPanel();
643     jPanel11.setFont(LABEL_FONT);
644     TitledBorder titledBorder2 = new TitledBorder(
645             MessageManager.getString("label.file_output"));
646     jPanel11.setBorder(titledBorder2);
647     jPanel11.setBounds(new Rectangle(30, 120, 196, 182));
648     GridLayout gridLayout3 = new GridLayout();
649     jPanel11.setLayout(gridLayout3);
650     gridLayout3.setRows(8);
651     blcjv.setFont(LABEL_FONT);
652     blcjv.setHorizontalAlignment(SwingConstants.LEFT);
653     clustaljv.setFont(LABEL_FONT);
654     clustaljv.setHorizontalAlignment(SwingConstants.LEFT);
655     pfamjv.setFont(LABEL_FONT);
656     pfamjv.setHorizontalAlignment(SwingConstants.LEFT);
657     pileupjv.setFont(LABEL_FONT);
658     pileupjv.setHorizontalAlignment(SwingConstants.LEFT);
659     pirjv.setFont(LABEL_FONT);
660     pirjv.setHorizontalAlignment(SwingConstants.LEFT);
661     autoIdWidth.setFont(LABEL_FONT);
662     autoIdWidth.setText(
663             MessageManager.getString("label.automatically_set_id_width"));
664     autoIdWidth.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager
665             .getString("label.adjusts_width_generated_eps_png")));
666     autoIdWidth.setBounds(new Rectangle(228, 144, 320, 23));
667     autoIdWidth.addActionListener(new ActionListener()
668     {
669
670       @Override
671       public void actionPerformed(ActionEvent e)
672       {
673         autoIdWidth_actionPerformed();
674       }
675     });
676     userIdWidthlabel.setFont(LABEL_FONT);
677     userIdWidthlabel.setText(
678             MessageManager.getString("label.figure_id_column_width"));
679     userIdWidth.setToolTipText(JvSwingUtils.wrapTooltip(true, MessageManager
680             .getString("label.manually_specify_width_left_column")));
681     userIdWidthlabel.setToolTipText(
682             JvSwingUtils.wrapTooltip(true, MessageManager.getString(
683                     "label.manually_specify_width_left_column")));
684     userIdWidthlabel.setBounds(new Rectangle(236, 168, 320, 23));
685     userIdWidth.setFont(JvSwingUtils.getTextAreaFont());
686     userIdWidth.setText("");
687     userIdWidth.setBounds(new Rectangle(232, 192, 84, 23));
688     userIdWidth.addActionListener(new ActionListener()
689     {
690
691       @Override
692       public void actionPerformed(ActionEvent e)
693       {
694         userIdWidth_actionPerformed();
695       }
696     });
697     modellerOutput.setFont(LABEL_FONT);
698     modellerOutput
699             .setText(MessageManager.getString("label.use_modeller_output"));
700     modellerOutput.setBounds(new Rectangle(228, 274, 320, 23));
701     embbedBioJSON.setFont(LABEL_FONT);
702     embbedBioJSON.setText(MessageManager.getString("label.embbed_biojson"));
703     embbedBioJSON.setBounds(new Rectangle(228, 248, 250, 23));
704
705     jPanel11.add(jLabel1);
706     jPanel11.add(blcjv);
707     jPanel11.add(clustaljv);
708     jPanel11.add(fastajv);
709     jPanel11.add(msfjv);
710     jPanel11.add(pfamjv);
711     jPanel11.add(pileupjv);
712     jPanel11.add(pirjv);
713     outputTab.add(autoIdWidth);
714     outputTab.add(userIdWidth);
715     outputTab.add(userIdWidthlabel);
716     outputTab.add(modellerOutput);
717     if (!Platform.isJS())
718     {
719       /*
720        * JalviewJS doesn't support Lineart option or SVG output
721        */
722       outputTab.add(embbedBioJSON);
723       outputTab.add(epsLabel);
724       outputTab.add(epsRendering);
725       outputTab.add(htmlLabel);
726       outputTab.add(htmlRendering);
727       outputTab.add(svgLabel);
728       outputTab.add(svgRendering);
729     }
730     outputTab.add(jPanel11);
731     return outputTab;
732   }
733
734   /**
735    * Initialises the Connections tabbed panel.
736    * 
737    * @return
738    */
739   private JPanel initConnectionsTab()
740   {
741     connectTab = new JPanel();
742     connectTab.setLayout(new GridBagLayout());
743
744     JPanel proxyPanel = initConnTabProxyPanel();
745     initConnTabCheckboxes();
746
747     // Add proxy server panel
748     connectTab.add(proxyPanel, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0,
749             GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
750             new Insets(10, 0, 5, 12), 4, 10));
751
752     // Add usage stats, version check and questionnaire checkboxes
753     connectTab.add(usagestats,
754             new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0,
755                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
756                     new Insets(0, 2, 5, 5), 70, 1));
757     connectTab.add(questionnaire,
758             new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0,
759                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
760                     new Insets(0, 2, 5, 10), 70, 1));
761     connectTab.add(versioncheck,
762             new GridBagConstraints(0, 3, 1, 1, 1.0, 0.0,
763                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
764                     new Insets(0, 2, 5, 5), 70, 1));
765
766     versioncheck.setVisible(false);
767
768     // Add padding so the panel doesn't look ridiculous
769     JPanel spacePanel = new JPanel();
770     connectTab.add(spacePanel,
771             new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0,
772                     GridBagConstraints.WEST, GridBagConstraints.BOTH,
773                     new Insets(0, 0, 0, 5), 70, 1));
774
775     return connectTab;
776   }
777
778   /**
779    * Initialises the Links tabbed panel.
780    * 
781    * @return
782    */
783   private JPanel initLinksTab()
784   {
785     JPanel linkTab = new JPanel();
786     linkTab.setLayout(new GridBagLayout());
787
788     // Set up table for Url links
789     linkUrlTable.getTableHeader().setReorderingAllowed(false);
790     linkUrlTable.setFillsViewportHeight(true);
791     linkUrlTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
792     linkUrlTable.setAutoCreateRowSorter(true);
793     linkUrlTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
794
795     // adjust row height so radio buttons actually fit
796     // don't do this in the renderer, it causes the awt thread to activate
797     // constantly
798     JRadioButton temp = new JRadioButton();
799     linkUrlTable.setRowHeight(temp.getMinimumSize().height);
800
801     // Table in scrollpane so that the table is given a scrollbar
802     JScrollPane linkScrollPane = new JScrollPane(linkUrlTable);
803     linkScrollPane.setBorder(null);
804
805     // Panel for links functionality
806     JPanel linkPanel = new JPanel(new GridBagLayout());
807     linkPanel.setBorder(new TitledBorder(
808             MessageManager.getString("label.url_linkfrom_sequence_id")));
809
810     // Put the Url links panel together
811
812     // Buttons go at top right, resizing only resizes the blank space vertically
813     JPanel buttonPanel = initLinkTabUrlButtons();
814     GridBagConstraints linkConstraints1 = new GridBagConstraints();
815     linkConstraints1.insets = new Insets(0, 0, 5, 0);
816     linkConstraints1.gridx = 0;
817     linkConstraints1.gridy = 0;
818     linkConstraints1.weightx = 1.0;
819     linkConstraints1.fill = GridBagConstraints.HORIZONTAL;
820     linkTab.add(buttonPanel, linkConstraints1);
821
822     // Links table goes at top left, resizing resizes the table
823     GridBagConstraints linkConstraints2 = new GridBagConstraints();
824     linkConstraints2.insets = new Insets(0, 0, 5, 5);
825     linkConstraints2.gridx = 0;
826     linkConstraints2.gridy = 1;
827     linkConstraints2.weightx = 1.0;
828     linkConstraints2.weighty = 1.0;
829     linkConstraints2.fill = GridBagConstraints.BOTH;
830     linkTab.add(linkScrollPane, linkConstraints2);
831
832     // Filter box and buttons goes at bottom left, resizing resizes the text box
833     JPanel filterPanel = initLinkTabFilterPanel();
834     GridBagConstraints linkConstraints3 = new GridBagConstraints();
835     linkConstraints3.insets = new Insets(0, 0, 0, 5);
836     linkConstraints3.gridx = 0;
837     linkConstraints3.gridy = 2;
838     linkConstraints3.weightx = 1.0;
839     linkConstraints3.fill = GridBagConstraints.HORIZONTAL;
840     linkTab.add(filterPanel, linkConstraints3);
841
842     return linkTab;
843   }
844
845   private JPanel initLinkTabFilterPanel()
846   {
847     // Filter textbox and reset button
848     JLabel filterLabel = new JLabel(
849             MessageManager.getString("label.filter"));
850     filterLabel.setFont(LABEL_FONT);
851     filterLabel.setHorizontalAlignment(SwingConstants.RIGHT);
852     filterLabel.setHorizontalTextPosition(SwingConstants.LEADING);
853
854     filterTB.setFont(LABEL_FONT);
855     filterTB.setText("");
856
857     doReset.setText(MessageManager.getString("action.showall"));
858     userOnly.setText(MessageManager.getString("action.customfilter"));
859
860     // Panel for filter functionality
861     JPanel filterPanel = new JPanel(new GridBagLayout());
862     filterPanel.setBorder(new TitledBorder("Filter"));
863     GridBagConstraints gbc = new GridBagConstraints();
864     gbc.gridx = 0;
865     gbc.gridy = 0;
866     gbc.fill = GridBagConstraints.NONE;
867     gbc.anchor = GridBagConstraints.WEST;
868
869     filterPanel.add(filterLabel, gbc);
870
871     GridBagConstraints gbc1 = new GridBagConstraints();
872     gbc1.gridx = 1;
873     gbc1.gridwidth = 2;
874     gbc1.fill = GridBagConstraints.HORIZONTAL;
875     gbc1.anchor = GridBagConstraints.WEST;
876     gbc1.weightx = 1.0;
877     filterPanel.add(filterTB, gbc1);
878
879     GridBagConstraints gbc2 = new GridBagConstraints();
880     gbc2.gridx = 3;
881     gbc2.fill = GridBagConstraints.NONE;
882     gbc2.anchor = GridBagConstraints.WEST;
883     filterPanel.add(doReset, gbc2);
884
885     GridBagConstraints gbc3 = new GridBagConstraints();
886     gbc3.gridx = 4;
887     gbc3.fill = GridBagConstraints.NONE;
888     gbc3.anchor = GridBagConstraints.WEST;
889     filterPanel.add(userOnly, gbc3);
890
891     return filterPanel;
892   }
893
894   private JPanel initLinkTabUrlButtons()
895   {
896     // Buttons for new / edit / delete Url links
897     JButton newLink = new JButton();
898     newLink.setText(MessageManager.getString("action.new"));
899
900     editLink.setText(MessageManager.getString("action.edit"));
901
902     deleteLink.setText(MessageManager.getString("action.delete"));
903
904     // no current selection, so initially disable delete/edit buttons
905     editLink.setEnabled(false);
906     deleteLink.setEnabled(false);
907
908     newLink.addActionListener(new java.awt.event.ActionListener()
909     {
910       @Override
911       public void actionPerformed(ActionEvent e)
912       {
913         newLink_actionPerformed(e);
914       }
915     });
916
917     editLink.setText(MessageManager.getString("action.edit"));
918     editLink.addActionListener(new java.awt.event.ActionListener()
919     {
920       @Override
921       public void actionPerformed(ActionEvent e)
922       {
923         editLink_actionPerformed(e);
924       }
925     });
926
927     deleteLink.setText(MessageManager.getString("action.delete"));
928     deleteLink.addActionListener(new java.awt.event.ActionListener()
929     {
930       @Override
931       public void actionPerformed(ActionEvent e)
932       {
933         deleteLink_actionPerformed(e);
934       }
935     });
936
937     JPanel buttonPanel = new JPanel(new GridBagLayout());
938     buttonPanel.setBorder(new TitledBorder("Edit links"));
939     GridBagConstraints gbc = new GridBagConstraints();
940     gbc.gridx = 0;
941     gbc.gridy = 0;
942     gbc.fill = GridBagConstraints.NONE;
943     buttonPanel.add(newLink, gbc);
944
945     GridBagConstraints gbc1 = new GridBagConstraints();
946     gbc1.gridx = 1;
947     gbc1.gridy = 0;
948     gbc1.fill = GridBagConstraints.NONE;
949     buttonPanel.add(editLink, gbc1);
950
951     GridBagConstraints gbc2 = new GridBagConstraints();
952     gbc2.gridx = 2;
953     gbc2.gridy = 0;
954     gbc2.fill = GridBagConstraints.NONE;
955     buttonPanel.add(deleteLink, gbc2);
956
957     GridBagConstraints gbc3 = new GridBagConstraints();
958     gbc3.gridx = 3;
959     gbc3.gridy = 0;
960     gbc3.fill = GridBagConstraints.HORIZONTAL;
961     gbc3.weightx = 1.0;
962     JPanel spacePanel = new JPanel();
963     spacePanel.setBorder(null);
964     buttonPanel.add(spacePanel, gbc3);
965
966     return buttonPanel;
967   }
968
969   /**
970    * Initialises the proxy server panel in the Connections tab
971    * 
972    * @return the proxy server panel
973    */
974   private JPanel initConnTabProxyPanel()
975   {
976     // Label for server text box
977     serverLabel.setText(MessageManager.getString("label.host") + ": ");
978     serverLabel.setHorizontalAlignment(SwingConstants.RIGHT);
979     serverLabel.setFont(LABEL_FONT);
980     serverLabel2.setText(MessageManager.getString("label.host") + ": ");
981     serverLabel2.setHorizontalAlignment(SwingConstants.RIGHT);
982     serverLabel2.setFont(LABEL_FONT);
983
984     // Proxy server and port text boxes
985     proxyServerHttpTB.setFont(LABEL_FONT);
986     proxyServerHttpTB.setColumns(40);
987     proxyPortHttpTB.setFont(LABEL_FONT);
988     proxyPortHttpTB.setColumns(4);
989     proxyServerHttpsTB.setFont(LABEL_FONT);
990     proxyServerHttpsTB.setColumns(40);
991     proxyPortHttpsTB.setFont(LABEL_FONT);
992     proxyPortHttpsTB.setColumns(4);
993     proxyAuthUsernameTB.setFont(LABEL_FONT);
994     proxyAuthUsernameTB.setColumns(30);
995
996     // check for any change to enable applyProxyButton
997     DocumentListener d = new DocumentListener()
998     {
999       @Override
1000       public void changedUpdate(DocumentEvent e)
1001       {
1002         applyProxyButtonEnabled(true);
1003       }
1004
1005       @Override
1006       public void insertUpdate(DocumentEvent e)
1007       {
1008         applyProxyButtonEnabled(true);
1009       }
1010
1011       @Override
1012       public void removeUpdate(DocumentEvent e)
1013       {
1014         applyProxyButtonEnabled(true);
1015       }
1016     };
1017     proxyServerHttpTB.getDocument().addDocumentListener(d);
1018     proxyPortHttpTB.getDocument().addDocumentListener(d);
1019     proxyServerHttpsTB.getDocument().addDocumentListener(d);
1020     proxyPortHttpsTB.getDocument().addDocumentListener(d);
1021     proxyAuthUsernameTB.getDocument().addDocumentListener(d);
1022     proxyAuthPasswordPB.setFont(LABEL_FONT);
1023     proxyAuthPasswordPB.setColumns(30);
1024     proxyAuthPasswordPB.getDocument()
1025             .addDocumentListener(new DocumentListener()
1026             {
1027               @Override
1028               public void changedUpdate(DocumentEvent e)
1029               {
1030                 proxyAuthPasswordCheckHighlight(true);
1031                 applyProxyButtonEnabled(true);
1032               }
1033
1034               @Override
1035               public void insertUpdate(DocumentEvent e)
1036               {
1037                 proxyAuthPasswordCheckHighlight(true);
1038                 applyProxyButtonEnabled(true);
1039               }
1040
1041               @Override
1042               public void removeUpdate(DocumentEvent e)
1043               {
1044                 proxyAuthPasswordCheckHighlight(true);
1045                 applyProxyButtonEnabled(true);
1046               }
1047
1048             });
1049
1050     // Label for Port text box
1051     portLabel.setFont(LABEL_FONT);
1052     portLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1053     portLabel.setText(MessageManager.getString("label.port") + ": ");
1054     portLabel2.setFont(LABEL_FONT);
1055     portLabel2.setHorizontalAlignment(SwingConstants.RIGHT);
1056     portLabel2.setText(MessageManager.getString("label.port") + ": ");
1057
1058     httpLabel.setText("HTTP");
1059     httpLabel.setFont(LABEL_FONT_BOLD);
1060     httpLabel.setHorizontalAlignment(SwingConstants.LEFT);
1061     httpsLabel.setText("HTTPS");
1062     httpsLabel.setFont(LABEL_FONT_BOLD);
1063     httpsLabel.setHorizontalAlignment(SwingConstants.LEFT);
1064
1065     proxyAuthUsernameLabel
1066             .setText(MessageManager.getString("label.username") + ": ");
1067     proxyAuthUsernameLabel.setFont(LABEL_FONT);
1068     proxyAuthUsernameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1069     proxyAuthPasswordLabel
1070             .setText(MessageManager.getString("label.password") + ": ");
1071     proxyAuthPasswordLabel.setFont(LABEL_FONT);
1072     proxyAuthPasswordLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1073     passwordNotStoredLabel.setText(
1074             "(" + MessageManager.getString("label.not_stored") + ")");
1075     passwordNotStoredLabel.setFont(LABEL_FONT_ITALIC);
1076     passwordNotStoredLabel.setHorizontalAlignment(SwingConstants.LEFT);
1077
1078     // Proxy type radio buttons
1079     noProxy.setFont(LABEL_FONT);
1080     noProxy.setHorizontalAlignment(SwingConstants.LEFT);
1081     noProxy.setText(MessageManager.getString("label.no_proxy"));
1082     systemProxy.setFont(LABEL_FONT);
1083     systemProxy.setHorizontalAlignment(SwingConstants.LEFT);
1084     systemProxy.setText(MessageManager.formatMessage("label.system_proxy",
1085             displayUserHostPort(Cache.startupProxyProperties[4],
1086                     Cache.startupProxyProperties[0],
1087                     Cache.startupProxyProperties[1]),
1088             displayUserHostPort(Cache.startupProxyProperties[6],
1089                     Cache.startupProxyProperties[2],
1090                     Cache.startupProxyProperties[3])));
1091     customProxy.setFont(LABEL_FONT);
1092     customProxy.setHorizontalAlignment(SwingConstants.LEFT);
1093     customProxy.setText(
1094             MessageManager.getString("label.use_proxy_server") + ":");
1095     ActionListener al = new ActionListener()
1096     {
1097       @Override
1098       public void actionPerformed(ActionEvent e)
1099       {
1100         proxyType_actionPerformed();
1101       }
1102     };
1103     noProxy.addActionListener(al);
1104     systemProxy.addActionListener(al);
1105     customProxy.addActionListener(al);
1106     proxyType.add(noProxy);
1107     proxyType.add(systemProxy);
1108     proxyType.add(customProxy);
1109
1110     proxyAuth.setFont(LABEL_FONT);
1111     proxyAuth.setHorizontalAlignment(SwingConstants.LEFT);
1112     proxyAuth.setText(MessageManager.getString("label.auth_required"));
1113     proxyAuth.addActionListener(new ActionListener()
1114     {
1115       @Override
1116       public void actionPerformed(ActionEvent e)
1117       {
1118         proxyAuth_actionPerformed();
1119       }
1120     });
1121
1122     setCustomProxyEnabled();
1123
1124     // Make proxy server panel
1125     JPanel proxyPanel = new JPanel();
1126     TitledBorder titledBorder1 = new TitledBorder(
1127             MessageManager.getString("label.proxy_servers"));
1128     proxyPanel.setBorder(titledBorder1);
1129     proxyPanel.setLayout(new GridBagLayout());
1130     GridBagConstraints gbc = new GridBagConstraints();
1131     gbc.fill = GridBagConstraints.HORIZONTAL;
1132     gbc.weightx = 1.0;
1133
1134     GridBagConstraints c = new GridBagConstraints();
1135     // Proxy type radio buttons (3)
1136     JPanel ptPanel = new JPanel();
1137     ptPanel.setLayout(new GridBagLayout());
1138     c.weightx = 1.0;
1139     c.gridy = 0;
1140     c.gridx = 0;
1141     c.gridwidth = 1;
1142     c.fill = GridBagConstraints.HORIZONTAL;
1143     ptPanel.add(noProxy, c);
1144     c.gridy++;
1145     ptPanel.add(systemProxy, c);
1146     c.gridy++;
1147     ptPanel.add(customProxy, c);
1148
1149     gbc.gridy = 0;
1150     proxyPanel.add(ptPanel, gbc);
1151
1152     // host and port text boxes
1153     JPanel hpPanel = new JPanel();
1154     hpPanel.setLayout(new GridBagLayout());
1155     // HTTP host port row
1156     c.gridy = 0;
1157     c.gridx = 0;
1158
1159     c.weightx = 0.1;
1160     c.anchor = GridBagConstraints.LINE_START;
1161     hpPanel.add(httpLabel, c);
1162
1163     c.gridx++;
1164     c.weightx = 0.1;
1165     c.anchor = GridBagConstraints.LINE_END;
1166     hpPanel.add(serverLabel, c);
1167
1168     c.gridx++;
1169     c.weightx = 1.0;
1170     c.anchor = GridBagConstraints.LINE_START;
1171     hpPanel.add(proxyServerHttpTB, c);
1172
1173     c.gridx++;
1174     c.weightx = 0.1;
1175     c.anchor = GridBagConstraints.LINE_END;
1176     hpPanel.add(portLabel, c);
1177
1178     c.gridx++;
1179     c.weightx = 0.2;
1180     c.anchor = GridBagConstraints.LINE_START;
1181     hpPanel.add(proxyPortHttpTB, c);
1182
1183     // HTTPS host port row
1184     c.gridy++;
1185     c.gridx = 0;
1186     c.gridwidth = 1;
1187
1188     c.anchor = GridBagConstraints.LINE_START;
1189     hpPanel.add(httpsLabel, c);
1190
1191     c.gridx++;
1192     c.anchor = GridBagConstraints.LINE_END;
1193     hpPanel.add(serverLabel2, c);
1194
1195     c.gridx++;
1196     c.anchor = GridBagConstraints.LINE_START;
1197     hpPanel.add(proxyServerHttpsTB, c);
1198
1199     c.gridx++;
1200     c.anchor = GridBagConstraints.LINE_END;
1201     hpPanel.add(portLabel2, c);
1202
1203     c.gridx++;
1204     c.anchor = GridBagConstraints.LINE_START;
1205     hpPanel.add(proxyPortHttpsTB, c);
1206
1207     gbc.gridy++;
1208     proxyPanel.add(hpPanel, gbc);
1209
1210     if (!Platform.isJS())
1211     /**
1212      * java.net.Authenticator is not implemented in SwingJS. Not displaying the
1213      * Authentication options in Preferences.
1214      * 
1215      * @j2sIgnore
1216      * 
1217      */
1218     {
1219       // Require authentication checkbox
1220       gbc.gridy++;
1221       proxyPanel.add(proxyAuth, gbc);
1222
1223       // username and password
1224       JPanel upPanel = new JPanel();
1225       upPanel.setLayout(new GridBagLayout());
1226       // username row
1227       c.gridy = 0;
1228       c.gridx = 0;
1229       c.gridwidth = 1;
1230       c.weightx = 0.4;
1231       c.anchor = GridBagConstraints.LINE_END;
1232       upPanel.add(proxyAuthUsernameLabel, c);
1233
1234       c.gridx++;
1235       c.weightx = 1.0;
1236       c.anchor = GridBagConstraints.LINE_START;
1237       upPanel.add(proxyAuthUsernameTB, c);
1238
1239       // password row
1240       c.gridy++;
1241       c.gridx = 0;
1242       c.weightx = 0.4;
1243       c.anchor = GridBagConstraints.LINE_END;
1244       upPanel.add(proxyAuthPasswordLabel, c);
1245
1246       c.gridx++;
1247       c.weightx = 1.0;
1248       c.anchor = GridBagConstraints.LINE_START;
1249       upPanel.add(proxyAuthPasswordPB, c);
1250
1251       c.gridx++;
1252       c.weightx = 0.4;
1253       c.anchor = GridBagConstraints.LINE_START;
1254       upPanel.add(passwordNotStoredLabel, c);
1255
1256       gbc.gridy++;
1257       proxyPanel.add(upPanel, gbc);
1258
1259     } // end j2sIgnore
1260
1261     applyProxyButton.setText(MessageManager.getString("action.apply"));
1262     applyProxyButton.addActionListener(new ActionListener()
1263     {
1264       @Override
1265       public void actionPerformed(ActionEvent e)
1266       {
1267         saveProxySettings();
1268         applyProxyButton.setEnabled(false);
1269       }
1270     });
1271     gbc.gridy++;
1272     gbc.fill = GridBagConstraints.NONE;
1273     gbc.anchor = GridBagConstraints.LINE_END;
1274     proxyPanel.add(applyProxyButton, gbc);
1275
1276     return proxyPanel;
1277   }
1278
1279   public void proxyAuthPasswordCheckHighlight(boolean enabled)
1280   {
1281     proxyAuthPasswordCheckHighlight(enabled, false);
1282   }
1283
1284   public void proxyAuthPasswordCheckHighlight(boolean enabled,
1285           boolean grabFocus)
1286   {
1287     if (enabled && proxyType.isSelected(customProxy.getModel())
1288             && proxyAuth.isSelected()
1289             && !proxyAuthUsernameTB.getText().isEmpty()
1290             && proxyAuthPasswordPB.getDocument().getLength() == 0)
1291     {
1292       if (grabFocus)
1293         proxyAuthPasswordPB.grabFocus();
1294       proxyAuthPasswordPB.setBackground(Color.PINK);
1295     }
1296     else
1297     {
1298       proxyAuthPasswordPB.setBackground(Color.WHITE);
1299     }
1300   }
1301
1302   public void applyProxyButtonEnabled(boolean enabled)
1303   {
1304     applyProxyButton.setEnabled(enabled);
1305   }
1306
1307   public void saveProxySettings()
1308   {
1309     // overridden in Preferences
1310   }
1311
1312   private String displayUserHostPort(String user, String host, String port)
1313   {
1314     boolean hostBlank = (host == null || host.isEmpty());
1315     boolean portBlank = (port == null || port.isEmpty());
1316     if (hostBlank && portBlank)
1317     {
1318       return MessageManager.getString("label.none");
1319     }
1320
1321     StringBuilder sb = new StringBuilder();
1322     if (user != null)
1323     {
1324       sb.append(user.isEmpty() || user.indexOf(" ") > -1 ? '"' + user + '"'
1325               : user);
1326       sb.append("@");
1327     }
1328     sb.append(hostBlank ? "" : host);
1329     if (!portBlank)
1330     {
1331       sb.append(":");
1332       sb.append(port);
1333     }
1334     return sb.toString();
1335   }
1336
1337   /**
1338    * Initialises the checkboxes in the Connections tab
1339    */
1340   private void initConnTabCheckboxes()
1341   {
1342     // Usage stats checkbox label
1343     usagestats.setText(
1344             MessageManager.getString("label.send_usage_statistics"));
1345     usagestats.setFont(LABEL_FONT);
1346     usagestats.setHorizontalAlignment(SwingConstants.RIGHT);
1347     usagestats.setHorizontalTextPosition(SwingConstants.LEADING);
1348
1349     // Questionnaire checkbox label
1350     questionnaire.setText(
1351             MessageManager.getString("label.check_for_questionnaires"));
1352     questionnaire.setFont(LABEL_FONT);
1353     questionnaire.setHorizontalAlignment(SwingConstants.RIGHT);
1354     questionnaire.setHorizontalTextPosition(SwingConstants.LEADING);
1355
1356     // Check for latest version checkbox label
1357     versioncheck.setText(
1358             MessageManager.getString("label.check_for_latest_version"));
1359     versioncheck.setFont(LABEL_FONT);
1360     versioncheck.setHorizontalAlignment(SwingConstants.RIGHT);
1361     versioncheck.setHorizontalTextPosition(SwingConstants.LEADING);
1362   }
1363
1364   /**
1365    * Initialises the parent panel which contains the tabbed sections.
1366    * 
1367    * @return
1368    */
1369   private JPanel initOkCancelPanel()
1370   {
1371     JButton ok = new JButton();
1372     ok.setText(MessageManager.getString("action.ok"));
1373     ok.addActionListener(new ActionListener()
1374     {
1375       @Override
1376       public void actionPerformed(ActionEvent e)
1377       {
1378         ok_actionPerformed(e);
1379       }
1380     });
1381     JButton cancel = new JButton();
1382     cancel.setText(MessageManager.getString("action.cancel"));
1383     cancel.addActionListener(new ActionListener()
1384     {
1385       @Override
1386       public void actionPerformed(ActionEvent e)
1387       {
1388         cancel_actionPerformed(e);
1389       }
1390     });
1391     JPanel okCancelPanel = new JPanel();
1392     okCancelPanel.add(ok);
1393     okCancelPanel.add(cancel);
1394     return okCancelPanel;
1395   }
1396
1397   /**
1398    * Initialises the Colours tabbed panel.
1399    * 
1400    * @return
1401    */
1402   private JPanel initColoursTab()
1403   {
1404     JPanel coloursTab = new JPanel();
1405     coloursTab.setBorder(new TitledBorder(
1406             MessageManager.getString("action.open_new_alignment")));
1407     coloursTab.setLayout(new FlowLayout());
1408     JLabel mincolourLabel = new JLabel();
1409     mincolourLabel.setFont(LABEL_FONT);
1410     mincolourLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1411     mincolourLabel.setText(MessageManager.getString("label.min_colour"));
1412     minColour.setFont(LABEL_FONT);
1413     minColour.setBorder(BorderFactory.createEtchedBorder());
1414     minColour.setPreferredSize(new Dimension(40, 20));
1415     minColour.addMouseListener(new MouseAdapter()
1416     {
1417       @Override
1418       public void mousePressed(MouseEvent e)
1419       {
1420         minColour_actionPerformed(minColour);
1421       }
1422     });
1423     JLabel maxcolourLabel = new JLabel();
1424     maxcolourLabel.setFont(LABEL_FONT);
1425     maxcolourLabel.setHorizontalAlignment(SwingConstants.RIGHT);
1426     maxcolourLabel.setText(MessageManager.getString("label.max_colour"));
1427     maxColour.setFont(LABEL_FONT);
1428     maxColour.setBorder(BorderFactory.createEtchedBorder());
1429     maxColour.setPreferredSize(new Dimension(40, 20));
1430     maxColour.addMouseListener(new MouseAdapter()
1431     {
1432       @Override
1433       public void mousePressed(MouseEvent e)
1434       {
1435         maxColour_actionPerformed(maxColour);
1436       }
1437     });
1438
1439     protColour.setFont(LABEL_FONT);
1440     protColour.setBounds(new Rectangle(172, 225, 155, 21));
1441     JLabel protColourLabel = new JLabel();
1442     protColourLabel.setFont(LABEL_FONT);
1443     protColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
1444     protColourLabel.setText(
1445             MessageManager.getString("label.prot_alignment_colour") + " ");
1446     JvSwingUtils.addtoLayout(coloursTab,
1447             MessageManager
1448                     .getString("label.default_colour_scheme_for_alignment"),
1449             protColourLabel, protColour);
1450
1451     nucColour.setFont(LABEL_FONT);
1452     nucColour.setBounds(new Rectangle(172, 240, 155, 21));
1453     JLabel nucColourLabel = new JLabel();
1454     nucColourLabel.setFont(LABEL_FONT);
1455     nucColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
1456     nucColourLabel.setText(
1457             MessageManager.getString("label.nuc_alignment_colour") + " ");
1458     JvSwingUtils.addtoLayout(coloursTab,
1459             MessageManager
1460                     .getString("label.default_colour_scheme_for_alignment"),
1461             nucColourLabel, nucColour);
1462
1463     JPanel annotationShding = new JPanel();
1464     annotationShding.setBorder(new TitledBorder(
1465             MessageManager.getString("label.annotation_shading_default")));
1466     annotationShding.setLayout(new GridLayout(1, 2));
1467     JvSwingUtils.addtoLayout(annotationShding,
1468             MessageManager.getString(
1469                     "label.default_minimum_colour_annotation_shading"),
1470             mincolourLabel, minColour);
1471     JvSwingUtils.addtoLayout(annotationShding,
1472             MessageManager.getString(
1473                     "label.default_maximum_colour_annotation_shading"),
1474             maxcolourLabel, maxColour);
1475     coloursTab.add(annotationShding); // , FlowLayout.LEFT);
1476     return coloursTab;
1477   }
1478
1479   /**
1480    * Initialises the Overview tabbed panel.
1481    * 
1482    * @return
1483    */
1484   private JPanel initOverviewTab()
1485   {
1486     JPanel overviewPanel = new JPanel();
1487     overviewPanel.setBorder(new TitledBorder(
1488             MessageManager.getString("label.overview_settings")));
1489
1490     gapColour.setFont(LABEL_FONT);
1491     // fixing the border colours stops apparent colour bleed from the panel
1492     gapColour.setBorder(
1493             BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
1494     gapColour.setPreferredSize(new Dimension(40, 20));
1495     gapColour.addMouseListener(new MouseAdapter()
1496     {
1497       @Override
1498       public void mousePressed(MouseEvent e)
1499       {
1500         gapColour_actionPerformed(gapColour);
1501       }
1502     });
1503
1504     hiddenColour.setFont(LABEL_FONT);
1505     // fixing the border colours stops apparent colour bleed from the panel
1506     hiddenColour.setBorder(
1507             BorderFactory.createEtchedBorder(Color.white, Color.lightGray));
1508     hiddenColour.setPreferredSize(new Dimension(40, 20));
1509     hiddenColour.addMouseListener(new MouseAdapter()
1510     {
1511       @Override
1512       public void mousePressed(MouseEvent e)
1513       {
1514         hiddenColour_actionPerformed(hiddenColour);
1515       }
1516     });
1517
1518     useLegacyGap = new JCheckBox(
1519             MessageManager.getString("label.ov_legacy_gap"));
1520     useLegacyGap.setFont(LABEL_FONT);
1521     useLegacyGap.setHorizontalAlignment(SwingConstants.LEFT);
1522     useLegacyGap.setVerticalTextPosition(SwingConstants.TOP);
1523     gapLabel = new JLabel(MessageManager.getString("label.gap_colour"));
1524     gapLabel.setFont(LABEL_FONT);
1525     gapLabel.setHorizontalAlignment(SwingConstants.LEFT);
1526     gapLabel.setVerticalTextPosition(SwingConstants.TOP);
1527     showHiddenAtStart = new JCheckBox(
1528             MessageManager.getString("label.ov_show_hide_default"));
1529     showHiddenAtStart.setFont(LABEL_FONT);
1530     showHiddenAtStart.setHorizontalAlignment(SwingConstants.LEFT);
1531     showHiddenAtStart.setVerticalTextPosition(SwingConstants.TOP);
1532     JLabel hiddenLabel = new JLabel(
1533             MessageManager.getString("label.hidden_colour"));
1534     hiddenLabel.setFont(LABEL_FONT);
1535     hiddenLabel.setHorizontalAlignment(SwingConstants.LEFT);
1536     hiddenLabel.setVerticalTextPosition(SwingConstants.TOP);
1537
1538     useLegacyGap.addActionListener(new ActionListener()
1539     {
1540       @Override
1541       public void actionPerformed(ActionEvent e)
1542       {
1543         useLegacyGaps_actionPerformed(e);
1544       }
1545     });
1546
1547     overviewPanel.setLayout(new GridBagLayout());
1548     GridBagConstraints c1 = new GridBagConstraints();
1549
1550     c1.fill = GridBagConstraints.HORIZONTAL;
1551     c1.gridx = 0;
1552     c1.gridy = 0;
1553     c1.weightx = 1;
1554     c1.ipady = 20;
1555     c1.anchor = GridBagConstraints.FIRST_LINE_START;
1556     overviewPanel.add(useLegacyGap, c1);
1557
1558     GridBagConstraints c2 = new GridBagConstraints();
1559     c2.fill = GridBagConstraints.HORIZONTAL;
1560     c2.gridx = 1;
1561     c2.gridy = 0;
1562     c2.insets = new Insets(0, 15, 0, 10);
1563     overviewPanel.add(gapLabel, c2);
1564
1565     GridBagConstraints c3 = new GridBagConstraints();
1566     c3.fill = GridBagConstraints.HORIZONTAL;
1567     c3.gridx = 2;
1568     c3.gridy = 0;
1569     c3.insets = new Insets(0, 0, 0, 15);
1570     overviewPanel.add(gapColour, c3);
1571
1572     GridBagConstraints c4 = new GridBagConstraints();
1573     c4.fill = GridBagConstraints.HORIZONTAL;
1574     c4.gridx = 0;
1575     c4.gridy = 1;
1576     c4.weightx = 1;
1577     overviewPanel.add(showHiddenAtStart, c4);
1578
1579     GridBagConstraints c5 = new GridBagConstraints();
1580     c5.fill = GridBagConstraints.HORIZONTAL;
1581     c5.gridx = 1;
1582     c5.gridy = 1;
1583     c5.insets = new Insets(0, 15, 0, 10);
1584     overviewPanel.add(hiddenLabel, c5);
1585
1586     GridBagConstraints c6 = new GridBagConstraints();
1587     c6.fill = GridBagConstraints.HORIZONTAL;
1588     c6.gridx = 2;
1589     c6.gridy = 1;
1590     c6.insets = new Insets(0, 0, 0, 15);
1591     overviewPanel.add(hiddenColour, c6);
1592
1593     JButton resetButton = new JButton(
1594             MessageManager.getString("label.reset_to_defaults"));
1595
1596     resetButton.addActionListener(new ActionListener()
1597     {
1598       @Override
1599       public void actionPerformed(ActionEvent e)
1600       {
1601         resetOvDefaults_actionPerformed(e);
1602       }
1603     });
1604
1605     GridBagConstraints c7 = new GridBagConstraints();
1606     c7.fill = GridBagConstraints.NONE;
1607     c7.gridx = 0;
1608     c7.gridy = 2;
1609     c7.insets = new Insets(10, 0, 0, 0);
1610     c7.anchor = GridBagConstraints.WEST;
1611     overviewPanel.add(resetButton, c7);
1612
1613     // Add padding so the panel doesn't look ridiculous
1614     JPanel spacePanel = new JPanel();
1615     overviewPanel.add(spacePanel,
1616             new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0,
1617                     GridBagConstraints.WEST, GridBagConstraints.BOTH,
1618                     new Insets(0, 0, 0, 5), 0, 0));
1619
1620     return overviewPanel;
1621   }
1622
1623   /**
1624    * Initialises the Structure tabbed panel.
1625    * 
1626    * @return
1627    */
1628   private JPanel initStructureTab()
1629   {
1630     structureTab = new JPanel();
1631
1632     structureTab.setBorder(new TitledBorder(
1633             MessageManager.getString("label.structure_options")));
1634     structureTab.setLayout(null);
1635     final int width = 420;
1636     final int height = 22;
1637     final int lineSpacing = 25;
1638     int ypos = 15;
1639
1640     structFromPdb.setFont(LABEL_FONT);
1641     structFromPdb
1642             .setText(MessageManager.getString("label.struct_from_pdb"));
1643     structFromPdb.setBounds(new Rectangle(5, ypos, width, height));
1644     structFromPdb.addActionListener(new ActionListener()
1645     {
1646       @Override
1647       public void actionPerformed(ActionEvent e)
1648       {
1649         boolean selected = structFromPdb.isSelected();
1650         // enable other options only when the first is checked
1651         addSecondaryStructure.setEnabled(selected);
1652         addTempFactor.setEnabled(selected);
1653       }
1654     });
1655     structureTab.add(structFromPdb);
1656
1657     // indent checkboxes that are conditional on the first one
1658     ypos += lineSpacing;
1659     addSecondaryStructure.setFont(LABEL_FONT);
1660     addSecondaryStructure
1661             .setText(MessageManager.getString("label.autoadd_secstr"));
1662     addSecondaryStructure.setBounds(new Rectangle(25, ypos, width, height));
1663     structureTab.add(addSecondaryStructure);
1664
1665     ypos += lineSpacing;
1666     addTempFactor.setFont(LABEL_FONT);
1667     addTempFactor.setText(MessageManager.getString("label.autoadd_temp"));
1668     addTempFactor.setBounds(new Rectangle(25, ypos, width, height));
1669     structureTab.add(addTempFactor);
1670
1671     ypos += lineSpacing;
1672     JLabel viewerLabel = new JLabel();
1673     viewerLabel.setFont(LABEL_FONT);
1674     viewerLabel.setHorizontalAlignment(SwingConstants.LEFT);
1675     viewerLabel.setText(MessageManager.getString("label.structure_viewer"));
1676     viewerLabel.setBounds(new Rectangle(10, ypos, 220, height));
1677     structureTab.add(viewerLabel);
1678
1679     /*
1680      * add all external viewers as options here - check 
1681      * when selected whether the program is installed
1682      */
1683     structViewer.setFont(LABEL_FONT);
1684     structViewer.setBounds(new Rectangle(190, ypos, 120, height));
1685     for (ViewerType v : EnumSet.allOf(ViewerType.class))
1686     {
1687       structViewer.addItem(v.name());
1688     }
1689     /*
1690     structViewer.addItem(ViewerType.JMOL.name());
1691     structViewer.addItem(ViewerType.CHIMERA.name());
1692     structViewer.addItem(ViewerType.CHIMERAX.name());
1693     structViewer.addItem(ViewerType.PYMOL.name());
1694     */
1695     structViewer.addActionListener(new ActionListener()
1696     {
1697       @Override
1698       public void actionPerformed(ActionEvent e)
1699       {
1700         structureViewer_actionPerformed(
1701                 (String) structViewer.getSelectedItem());
1702       }
1703     });
1704     structureTab.add(structViewer);
1705
1706     ypos += lineSpacing;
1707     structureViewerPathLabel = new JLabel();
1708     structureViewerPathLabel.setFont(LABEL_FONT);// new Font("SansSerif", 0,
1709                                                  // 11));
1710     structureViewerPathLabel.setHorizontalAlignment(SwingConstants.LEFT);
1711     structureViewerPathLabel.setText(MessageManager
1712             .formatMessage("label.viewer_path", "Chimera(X)"));
1713     structureViewerPathLabel
1714             .setBounds(new Rectangle(10, ypos, 170, height));
1715     structureViewerPathLabel.setEnabled(false);
1716     structureTab.add(structureViewerPathLabel);
1717
1718     structureViewerPath.setFont(LABEL_FONT);
1719     structureViewerPath.setText("");
1720     structureViewerPath.setEnabled(false);
1721     final String tooltip = JvSwingUtils.wrapTooltip(true,
1722             MessageManager.getString("label.viewer_path_tip"));
1723     structureViewerPath.setToolTipText(tooltip);
1724     structureViewerPath.setBounds(new Rectangle(190, ypos, 290, height));
1725     structureViewerPath.addMouseListener(new MouseAdapter()
1726     {
1727       @Override
1728       public void mouseClicked(MouseEvent e)
1729       {
1730         if (structureViewerPath.isEnabled() && e.getClickCount() == 2)
1731         {
1732           String chosen = openFileChooser();
1733           if (chosen != null)
1734           {
1735             structureViewerPath.setText(chosen);
1736           }
1737         }
1738       }
1739     });
1740     structureTab.add(structureViewerPath);
1741
1742     ypos += lineSpacing;
1743     nwMapping.setFont(LABEL_FONT);
1744     nwMapping.setText(MessageManager.getString("label.nw_mapping"));
1745     siftsMapping.setFont(LABEL_FONT);
1746     siftsMapping.setText(MessageManager.getString("label.sifts_mapping"));
1747     mappingMethod.add(nwMapping);
1748     mappingMethod.add(siftsMapping);
1749     JPanel mappingPanel = new JPanel();
1750     mappingPanel.setFont(LABEL_FONT);
1751     TitledBorder mmTitledBorder = new TitledBorder(
1752             MessageManager.getString("label.mapping_method"));
1753     mmTitledBorder.setTitleFont(LABEL_FONT);
1754     mappingPanel.setBorder(mmTitledBorder);
1755     mappingPanel.setBounds(new Rectangle(10, ypos, 472, 45));
1756     // GridLayout mappingLayout = new GridLayout();
1757     mappingPanel.setLayout(new GridLayout());
1758     mappingPanel.add(nwMapping);
1759     mappingPanel.add(siftsMapping);
1760     structureTab.add(mappingPanel);
1761
1762     ypos += lineSpacing;
1763     ypos += lineSpacing;
1764     FTSDataColumnPreferences docFieldPref = new FTSDataColumnPreferences(
1765             PreferenceSource.PREFERENCES, PDBFTSRestClient.getInstance());
1766     docFieldPref.setBounds(new Rectangle(10, ypos, 470, 120));
1767     structureTab.add(docFieldPref);
1768
1769     /*
1770      * hide Chimera options in JalviewJS
1771      */
1772     if (Platform.isJS())
1773     {
1774       structureViewerPathLabel.setVisible(false);
1775       structureViewerPath.setVisible(false);
1776       viewerLabel.setVisible(false);
1777       structViewer.setVisible(false);
1778     }
1779
1780     return structureTab;
1781   }
1782
1783   /**
1784    * Action on choosing a structure viewer from combobox options.
1785    * 
1786    * @param selectedItem
1787    */
1788   protected void structureViewer_actionPerformed(String selectedItem)
1789   {
1790   }
1791
1792   /**
1793    * Show a dialog for the user to choose a file. Returns the chosen path, or
1794    * null on Cancel.
1795    * 
1796    * @return
1797    */
1798   protected String openFileChooser()
1799   {
1800     String choice = null;
1801     JFileChooser chooser = new JFileChooser();
1802
1803     // Enable appBundleIsTraversable in macOS FileChooser to allow selecting
1804     // hidden executables within .app dirs
1805     if (Platform.isMac())
1806     {
1807       chooser.putClientProperty("JFileChooser.appBundleIsTraversable",
1808               true);
1809     }
1810
1811     // chooser.setFileView(new JalviewFileView());
1812     chooser.setDialogTitle(
1813             MessageManager.getString("label.open_local_file"));
1814     chooser.setToolTipText(MessageManager.getString("action.open"));
1815
1816     int value = chooser.showOpenDialog(this);
1817
1818     if (value == JFileChooser.APPROVE_OPTION)
1819     {
1820       choice = chooser.getSelectedFile().getPath();
1821     }
1822     return choice;
1823   }
1824
1825   /**
1826    * Validate the structure tab preferences; if invalid, set focus on this tab.
1827    * 
1828    * @param e
1829    */
1830   protected boolean validateStructure(FocusEvent e)
1831   {
1832     if (!validateStructure())
1833     {
1834       e.getComponent().requestFocusInWindow();
1835       return false;
1836     }
1837     return true;
1838   }
1839
1840   protected boolean validateStructure()
1841   {
1842     return false;
1843   }
1844
1845   /**
1846    * Initialises the Visual tabbed panel.
1847    * 
1848    * @return
1849    */
1850   private JPanel initVisualTab()
1851   {
1852     JPanel visualTab = new JPanel();
1853     visualTab.setBorder(new TitledBorder(
1854             MessageManager.getString("action.open_new_alignment")));
1855     visualTab.setLayout(null);
1856     fullScreen.setFont(LABEL_FONT);
1857     fullScreen.setHorizontalAlignment(SwingConstants.RIGHT);
1858     fullScreen.setHorizontalTextPosition(SwingConstants.LEFT);
1859     fullScreen.setText(MessageManager.getString("label.maximize_window"));
1860     quality.setEnabled(false);
1861     quality.setFont(LABEL_FONT);
1862     quality.setHorizontalAlignment(SwingConstants.RIGHT);
1863     quality.setHorizontalTextPosition(SwingConstants.LEFT);
1864     quality.setSelected(true);
1865     quality.setText(MessageManager.getString("label.quality"));
1866     conservation.setEnabled(false);
1867     conservation.setFont(LABEL_FONT);
1868     conservation.setHorizontalAlignment(SwingConstants.RIGHT);
1869     conservation.setHorizontalTextPosition(SwingConstants.LEFT);
1870     conservation.setSelected(true);
1871     conservation.setText(MessageManager.getString("label.conservation"));
1872     identity.setEnabled(false);
1873     identity.setFont(LABEL_FONT);
1874     identity.setHorizontalAlignment(SwingConstants.RIGHT);
1875     identity.setHorizontalTextPosition(SwingConstants.LEFT);
1876     identity.setSelected(true);
1877     identity.setText(MessageManager.getString("label.consensus"));
1878     ssConsensus.setEnabled(false);
1879     ssConsensus.setFont(LABEL_FONT);
1880     ssConsensus.setHorizontalAlignment(SwingConstants.RIGHT);
1881     ssConsensus.setHorizontalTextPosition(SwingConstants.LEFT);
1882     ssConsensus.setSelected(false);
1883     ssConsensus.setText(MessageManager.getString("label.ssConsensus"));
1884     showOccupancy.setFont(LABEL_FONT);
1885     showOccupancy.setEnabled(false);
1886     showOccupancy.setHorizontalAlignment(SwingConstants.RIGHT);
1887     showOccupancy.setHorizontalTextPosition(SwingConstants.LEFT);
1888     showOccupancy.setSelected(true);
1889     showOccupancy.setText(MessageManager.getString("label.occupancy"));
1890
1891     JLabel showGroupbits = new JLabel();
1892     showGroupbits.setFont(LABEL_FONT);
1893     showGroupbits.setHorizontalAlignment(SwingConstants.RIGHT);
1894     showGroupbits.setHorizontalTextPosition(SwingConstants.LEFT);
1895     showGroupbits
1896             .setText(MessageManager.getString("action.show_group") + ":");
1897     JLabel showConsensbits = new JLabel();
1898     showConsensbits.setFont(LABEL_FONT);
1899     showConsensbits.setHorizontalAlignment(SwingConstants.RIGHT);
1900     showConsensbits.setHorizontalTextPosition(SwingConstants.LEFT);
1901     showConsensbits
1902             .setText(MessageManager.getString("label.consensus") + ":");
1903     showConsensHistogram.setEnabled(false);
1904     showConsensHistogram.setFont(LABEL_FONT);
1905     showConsensHistogram.setHorizontalAlignment(SwingConstants.RIGHT);
1906     showConsensHistogram.setHorizontalTextPosition(SwingConstants.LEFT);
1907     showConsensHistogram.setSelected(true);
1908     showConsensHistogram
1909             .setText(MessageManager.getString("label.histogram"));
1910     showConsensLogo.setEnabled(false);
1911     showConsensLogo.setFont(LABEL_FONT);
1912     showConsensLogo.setHorizontalAlignment(SwingConstants.RIGHT);
1913     showConsensLogo.setHorizontalTextPosition(SwingConstants.LEFT);
1914     showConsensLogo.setSelected(true);
1915     showConsensLogo.setText(MessageManager.getString("label.logo"));
1916     showGroupConsensus.setEnabled(false);
1917     showGroupConsensus.setFont(LABEL_FONT);
1918     showGroupConsensus.setHorizontalAlignment(SwingConstants.RIGHT);
1919     showGroupConsensus.setHorizontalTextPosition(SwingConstants.LEFT);
1920     showGroupConsensus.setSelected(true);
1921     showGroupConsensus.setText(MessageManager.getString("label.consensus"));
1922     showGroupConservation.setEnabled(false);
1923     showGroupConservation.setFont(LABEL_FONT);
1924     showGroupConservation.setHorizontalAlignment(SwingConstants.RIGHT);
1925     showGroupConservation.setHorizontalTextPosition(SwingConstants.LEFT);
1926     showGroupConservation.setSelected(true);
1927     showGroupConservation
1928             .setText(MessageManager.getString("label.conservation"));
1929     showNpTooltip.setEnabled(true);
1930     showNpTooltip.setFont(LABEL_FONT);
1931     showNpTooltip.setHorizontalAlignment(SwingConstants.RIGHT);
1932     showNpTooltip.setHorizontalTextPosition(SwingConstants.LEFT);
1933     showNpTooltip.setSelected(true);
1934     showNpTooltip.setText(
1935             MessageManager.getString("label.non_positional_features"));
1936     showDbRefTooltip.setEnabled(true);
1937     showDbRefTooltip.setFont(LABEL_FONT);
1938     showDbRefTooltip.setHorizontalAlignment(SwingConstants.RIGHT);
1939     showDbRefTooltip.setHorizontalTextPosition(SwingConstants.LEFT);
1940     showDbRefTooltip.setSelected(true);
1941     showDbRefTooltip
1942             .setText(MessageManager.getString("label.database_references"));
1943     annotations.setFont(LABEL_FONT);
1944     annotations.setHorizontalAlignment(SwingConstants.RIGHT);
1945     annotations.setHorizontalTextPosition(SwingConstants.LEFT);
1946     annotations.setSelected(true);
1947     annotations.setText(MessageManager.getString("label.show_annotations"));
1948     // annotations.setBounds(new Rectangle(169, 12, 200, 23));
1949     annotations.addActionListener(new ActionListener()
1950     {
1951       @Override
1952       public void actionPerformed(ActionEvent e)
1953       {
1954         annotations_actionPerformed(e);
1955       }
1956     });
1957     identity.addActionListener(new ActionListener()
1958     {
1959       @Override
1960       public void actionPerformed(ActionEvent e)
1961       {
1962         annotations_actionPerformed(e);
1963       }
1964     });
1965     showGroupConsensus.addActionListener(new ActionListener()
1966     {
1967       @Override
1968       public void actionPerformed(ActionEvent e)
1969       {
1970         annotations_actionPerformed(e);
1971       }
1972     });
1973     showUnconserved.setFont(LABEL_FONT);
1974     showUnconserved.setHorizontalAlignment(SwingConstants.RIGHT);
1975     showUnconserved.setHorizontalTextPosition(SwingConstants.LEFT);
1976     showUnconserved.setSelected(true);
1977     showUnconserved
1978             .setText(MessageManager.getString("action.show_unconserved"));
1979     showUnconserved.addActionListener(new ActionListener()
1980     {
1981       @Override
1982       public void actionPerformed(ActionEvent e)
1983       {
1984         showunconserved_actionPerformed(e);
1985       }
1986     });
1987
1988     // TODO these are not yet added to / action from Preferences
1989     // JCheckBox shareSelections = new JCheckBox();
1990     // shareSelections.setFont(verdana11);
1991     // shareSelections.setHorizontalAlignment(SwingConstants.RIGHT);
1992     // shareSelections.setHorizontalTextPosition(SwingConstants.LEFT);
1993     // shareSelections.setSelected(true);
1994     // shareSelections.setText(MessageManager
1995     // .getString("label.share_selection_across_views"));
1996     // JCheckBox followHighlight = new JCheckBox();
1997     // followHighlight.setFont(verdana11);
1998     // followHighlight.setHorizontalAlignment(SwingConstants.RIGHT);
1999     // followHighlight.setHorizontalTextPosition(SwingConstants.LEFT);
2000     // // showUnconserved.setBounds(new Rectangle(169, 40, 200, 23));
2001     // followHighlight.setSelected(true);
2002     // followHighlight.setText(MessageManager
2003     // .getString("label.scroll_highlighted_regions"));
2004
2005     seqLimit.setFont(LABEL_FONT);
2006     seqLimit.setHorizontalAlignment(SwingConstants.RIGHT);
2007     seqLimit.setHorizontalTextPosition(SwingConstants.LEFT);
2008     seqLimit.setText(MessageManager.getString("label.full_sequence_id"));
2009     smoothFont.setFont(LABEL_FONT);
2010     smoothFont.setHorizontalAlignment(SwingConstants.RIGHT);
2011     smoothFont.setHorizontalTextPosition(SwingConstants.LEADING);
2012     smoothFont.setText(MessageManager.getString("label.smooth_font"));
2013     scaleProteinToCdna.setFont(LABEL_FONT);
2014     scaleProteinToCdna.setHorizontalAlignment(SwingConstants.RIGHT);
2015     scaleProteinToCdna.setHorizontalTextPosition(SwingConstants.LEADING);
2016     scaleProteinToCdna.setText(
2017             MessageManager.getString("label.scale_protein_to_cdna"));
2018     scaleProteinToCdna.setToolTipText(
2019             MessageManager.getString("label.scale_protein_to_cdna_tip"));
2020     JLabel gapLabel = new JLabel();
2021     gapLabel.setFont(LABEL_FONT);
2022     gapLabel.setHorizontalAlignment(SwingConstants.RIGHT);
2023     gapLabel.setText(MessageManager.getString("label.gap_symbol") + " ");
2024     JLabel fontLabel = new JLabel();
2025     fontLabel.setFont(LABEL_FONT);
2026     fontLabel.setHorizontalAlignment(SwingConstants.RIGHT);
2027     fontLabel.setText(MessageManager.getString("label.font"));
2028     fontSizeCB.setFont(LABEL_FONT);
2029     fontSizeCB.setBounds(new Rectangle(320, 112, 65, 23));
2030     fontStyleCB.setFont(LABEL_FONT);
2031     fontStyleCB.setBounds(new Rectangle(382, 112, 80, 23));
2032     fontNameCB.setFont(LABEL_FONT);
2033     fontNameCB.setBounds(new Rectangle(172, 112, 147, 23));
2034     gapSymbolCB.setFont(LABEL_FONT);
2035     gapSymbolCB.setBounds(new Rectangle(172, 215, 69, 23));
2036     DefaultListCellRenderer dlcr = new DefaultListCellRenderer();
2037     dlcr.setHorizontalAlignment(DefaultListCellRenderer.CENTER);
2038     gapSymbolCB.setRenderer(dlcr);
2039
2040     startupCheckbox.setText(MessageManager.getString("action.open_file"));
2041     startupCheckbox.setFont(LABEL_FONT);
2042     startupCheckbox.setHorizontalAlignment(SwingConstants.RIGHT);
2043     startupCheckbox.setHorizontalTextPosition(SwingConstants.LEFT);
2044     startupCheckbox.setSelected(true);
2045     startupFileTextfield.setFont(LABEL_FONT);
2046     startupFileTextfield.setBounds(new Rectangle(172, 310, 330, 20));
2047     final String tooltip = JvSwingUtils.wrapTooltip(true,
2048             MessageManager.getString("label.double_click_to_browse"));
2049     startupFileTextfield.setToolTipText(tooltip);
2050     startupFileTextfield.addMouseListener(new MouseAdapter()
2051     {
2052       @Override
2053       public void mouseClicked(MouseEvent e)
2054       {
2055         if (e.getClickCount() > 1)
2056         {
2057           startupFileTextfield_mouseClicked();
2058         }
2059       }
2060     });
2061
2062     sortby.setFont(LABEL_FONT);
2063     sortby.setBounds(new Rectangle(172, 260, 155, 21));
2064     JLabel sortLabel = new JLabel();
2065     sortLabel.setFont(LABEL_FONT);
2066     sortLabel.setHorizontalAlignment(SwingConstants.RIGHT);
2067     sortLabel.setText(MessageManager.getString("label.sort_by"));
2068     sortAnnBy.setFont(LABEL_FONT);
2069     sortAnnBy.setBounds(new Rectangle(172, 285, 110, 21));
2070     JLabel sortAnnLabel = new JLabel();
2071     sortAnnLabel.setFont(LABEL_FONT);
2072     sortAnnLabel.setHorizontalAlignment(SwingConstants.RIGHT);
2073     sortAnnLabel.setText(MessageManager.getString("label.sort_ann_by"));
2074     sortAutocalc.setFont(LABEL_FONT);
2075     sortAutocalc.setBounds(new Rectangle(290, 285, 165, 21));
2076
2077     JPanel annsettingsPanel = new JPanel();
2078     annsettingsPanel.setBounds(new Rectangle(173, 13, 320, 101));
2079     annsettingsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
2080     annsettingsPanel.setBorder(new EtchedBorder());
2081     visualTab.add(annsettingsPanel);
2082     Border jb = new EmptyBorder(1, 1, 4, 5);
2083     annotations.setBorder(jb);
2084     showOccupancy.setBorder(jb);
2085     quality.setBorder(jb);
2086     conservation.setBorder(jb);
2087     identity.setBorder(jb);
2088     ssConsensus.setBorder(jb);
2089     showConsensbits.setBorder(jb);
2090     showGroupbits.setBorder(jb);
2091     showGroupConsensus.setBorder(jb);
2092     showGroupConservation.setBorder(jb);
2093     showConsensHistogram.setBorder(jb);
2094     showConsensLogo.setBorder(jb);
2095
2096     JPanel autoAnnotSettings = new JPanel();
2097     annsettingsPanel.add(autoAnnotSettings);
2098     autoAnnotSettings.setLayout(new GridLayout(0, 2));
2099     autoAnnotSettings.add(annotations);
2100     autoAnnotSettings.add(quality);
2101     // second row of autoannotation box
2102     autoAnnotSettings = new JPanel();
2103     annsettingsPanel.add(autoAnnotSettings);
2104     autoAnnotSettings.setLayout(new GridLayout(0, 1));
2105     autoAnnotSettings.add(ssConsensus);
2106
2107     // third row of autoannotation box
2108     autoAnnotSettings = new JPanel();
2109     annsettingsPanel.add(autoAnnotSettings);
2110
2111     autoAnnotSettings.setLayout(new GridLayout(0, 3));
2112     autoAnnotSettings.add(conservation);
2113     autoAnnotSettings.add(identity);
2114     autoAnnotSettings.add(showOccupancy);
2115     autoAnnotSettings.add(showGroupbits);
2116     autoAnnotSettings.add(showGroupConservation);
2117     autoAnnotSettings.add(showGroupConsensus);
2118     autoAnnotSettings.add(showConsensbits);
2119     autoAnnotSettings.add(showConsensHistogram);
2120     autoAnnotSettings.add(showConsensLogo);
2121
2122     JPanel tooltipSettings = new JPanel();
2123     tooltipSettings.setBorder(new TitledBorder(
2124             MessageManager.getString("label.sequence_id_tooltip")));
2125     tooltipSettings.setBounds(173, 140, 220, 62);
2126     tooltipSettings.setLayout(new GridLayout(2, 1));
2127     tooltipSettings.add(showDbRefTooltip);
2128     tooltipSettings.add(showNpTooltip);
2129     visualTab.add(tooltipSettings);
2130
2131     wrap.setFont(LABEL_FONT);
2132     wrap.setHorizontalAlignment(SwingConstants.TRAILING);
2133     wrap.setHorizontalTextPosition(SwingConstants.LEADING);
2134     wrap.setText(MessageManager.getString("label.wrap_alignment"));
2135     rightAlign.setFont(LABEL_FONT);
2136     rightAlign.setForeground(Color.black);
2137     rightAlign.setHorizontalAlignment(SwingConstants.RIGHT);
2138     rightAlign.setHorizontalTextPosition(SwingConstants.LEFT);
2139     rightAlign.setText(MessageManager.getString("label.right_align_ids"));
2140     idItalics.setFont(LABEL_FONT_ITALIC);
2141     idItalics.setHorizontalAlignment(SwingConstants.RIGHT);
2142     idItalics.setHorizontalTextPosition(SwingConstants.LEADING);
2143     idItalics.setText(
2144             MessageManager.getString("label.sequence_name_italics"));
2145     openoverv.setFont(LABEL_FONT);
2146     openoverv.setActionCommand(
2147             MessageManager.getString("label.open_overview"));
2148     openoverv.setHorizontalAlignment(SwingConstants.RIGHT);
2149     openoverv.setHorizontalTextPosition(SwingConstants.LEFT);
2150     openoverv.setText(MessageManager.getString("label.open_overview"));
2151     JPanel jPanel2 = new JPanel();
2152     jPanel2.setBounds(new Rectangle(7, 17, 158, 310));
2153     jPanel2.setLayout(new GridLayout(14, 1));
2154     jPanel2.add(fullScreen);
2155     jPanel2.add(openoverv);
2156     jPanel2.add(seqLimit);
2157     jPanel2.add(rightAlign);
2158     jPanel2.add(fontLabel);
2159     jPanel2.add(showUnconserved);
2160     jPanel2.add(idItalics);
2161     jPanel2.add(smoothFont);
2162     jPanel2.add(scaleProteinToCdna);
2163     jPanel2.add(gapLabel);
2164     jPanel2.add(wrap);
2165     jPanel2.add(sortLabel);
2166     jPanel2.add(sortAnnLabel);
2167     jPanel2.add(startupCheckbox);
2168     visualTab.add(jPanel2);
2169     visualTab.add(startupFileTextfield);
2170     visualTab.add(sortby);
2171     visualTab.add(sortAnnBy);
2172     visualTab.add(sortAutocalc);
2173     visualTab.add(gapSymbolCB);
2174     visualTab.add(fontNameCB);
2175     visualTab.add(fontSizeCB);
2176     visualTab.add(fontStyleCB);
2177
2178     if (Platform.isJS())
2179     {
2180       startupCheckbox.setVisible(false);
2181       startupFileTextfield.setVisible(false);
2182     }
2183
2184     return visualTab;
2185   }
2186
2187   /**
2188    * Load the saved Backups options EXCEPT "Enabled" and "Scheme"
2189    */
2190
2191   protected void loadLastSavedBackupsOptions()
2192   {
2193     BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
2194             .getSavedBackupEntry();
2195     enableBackupFiles.setSelected(
2196             Cache.getDefault(BackupFiles.ENABLED, !Platform.isJS()));
2197
2198     BackupFilesPresetEntry backupfilesCustomEntry = BackupFilesPresetEntry
2199             .createBackupFilesPresetEntry(Cache
2200                     .getDefault(BackupFilesPresetEntry.CUSTOMCONFIG, null));
2201     if (backupfilesCustomEntry == null)
2202     {
2203       backupfilesCustomEntry = BackupFilesPresetEntry.backupfilesPresetEntriesValues
2204               .get(BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT);
2205     }
2206     BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
2207             BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM,
2208             backupfilesCustomEntry);
2209
2210     setComboIntStringKey(backupfilesPresetsCombo,
2211             Cache.getDefault(BackupFiles.NS + "_PRESET",
2212                     BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT));
2213
2214     backupsSetOptions(savedPreset);
2215
2216     backupsOptionsSetEnabled();
2217     updateBackupFilesExampleLabel();
2218   }
2219
2220   /*
2221    * Load the saved Memory settings
2222    */
2223   protected void loadLastSavedMemorySettings()
2224   {
2225     customiseMemorySetting.setSelected(
2226             Cache.getDefault(MemorySetting.CUSTOMISED_SETTINGS, false));
2227     jvmMemoryPercentSlider
2228             .setValue(Cache.getDefault(MemorySetting.MEMORY_JVMMEMPC, 90));
2229     jvmMemoryMaxTextField.setText(
2230             Cache.getDefault(MemorySetting.MEMORY_JVMMEMMAX, "32g"));
2231   }
2232
2233   private boolean warnAboutSuffixReverseChange()
2234   {
2235     BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
2236             .getSavedBackupEntry();
2237     boolean savedSuffixReverse = bfpe.reverse;
2238     int savedSuffixDigits = bfpe.digits;
2239     String savedSuffixTemplate = bfpe.suffix;
2240
2241     boolean nowSuffixReverse = suffixReverse.isSelected();
2242     int nowSuffixDigits = getSpinnerInt(suffixDigitsSpinner, 3);
2243     String nowSuffixTemplate = suffixTemplate.getText();
2244     return nowSuffixReverse != savedSuffixReverse
2245             && nowSuffixDigits == savedSuffixDigits
2246             && nowSuffixTemplate != null
2247             && nowSuffixTemplate.equals(savedSuffixTemplate);
2248   }
2249
2250   /* Initialises the Startup tabbed panel.
2251    * 
2252    * @return
2253    * */
2254
2255   private JPanel initStartupTab()
2256   {
2257     JPanel startupTab = new JPanel();
2258     startupTab.setBorder(
2259             new TitledBorder(MessageManager.getString("label.memory")));
2260     startupTab.setLayout(new GridBagLayout());
2261
2262     GridBagConstraints gbc = new GridBagConstraints();
2263     gbc.weightx = 0.0;
2264     gbc.weighty = 0.0;
2265     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
2266     gbc.fill = GridBagConstraints.NONE;
2267
2268     initMemoryPanel();
2269
2270     gbc.gridheight = 1;
2271     gbc.gridwidth = 3;
2272
2273     gbc.gridy = 0; // row 1
2274     gbc.gridx = 0;
2275     JLabel memoryText = new JLabel();
2276     memoryText.setFont(LABEL_FONT_ITALIC);
2277     memoryText
2278             .setText(MessageManager.getString("label.memory_setting_text"));
2279     startupTab.add(memoryText, gbc);
2280
2281     gbc.gridy++; // row 2
2282     gbc.gridx = 0;
2283     JPanel exampleMemoryPanel = new JPanel();
2284     exampleMemoryPanel
2285             .setLayout(new BoxLayout(exampleMemoryPanel, BoxLayout.Y_AXIS));
2286     exampleMemoryPanel.setToolTipText(JvSwingUtils.wrapTooltip(true,
2287             MessageManager.getString("label.memory_example_tooltip")));
2288     JLabel exampleTextLabel = new JLabel();
2289     exampleTextLabel
2290             .setText(MessageManager.getString("label.memory_example_text"));
2291     exampleTextLabel.setForeground(Color.GRAY);
2292     exampleTextLabel.setFont(LABEL_FONT);
2293     exampleMemoryPanel.add(exampleTextLabel);
2294     exampleMemoryPanel.add(exampleMemoryLabel);
2295     exampleMemoryPanel.setBackground(Color.WHITE);
2296     exampleMemoryPanel.setBorder(BorderFactory.createEtchedBorder());
2297     startupTab.add(exampleMemoryPanel, gbc);
2298
2299     gbc.gridy++; // row 3
2300     gbc.gridx = 0;
2301     startupTab.add(customiseMemorySetting, gbc);
2302
2303     gbc.gridy += 2; // row 4 with a gap
2304     gbc.gridx = 0;
2305     startupTab.add(maxMemoryLabel, gbc);
2306
2307     gbc.gridy += 2; // row 5
2308     gbc.gridx = 0;
2309     gbc.gridwidth = 1;
2310     startupTab.add(jvmMemoryPercentLabel, gbc);
2311     gbc.gridx++;
2312     startupTab.add(jvmMemoryPercentSlider, gbc);
2313     gbc.gridx++;
2314     // gbc.weightx = 0.1;
2315     startupTab.add(jvmMemoryPercentDisplay, gbc);
2316     // gbc.weightx = 1.0;
2317     gbc.gridwidth = 3;
2318
2319     gbc.gridy++; // row 6
2320     gbc.gridx = 0;
2321     startupTab.add(jvmMemoryMaxLabel, gbc);
2322     gbc.gridx++;
2323     startupTab.add(jvmMemoryMaxTextField, gbc);
2324
2325     gbc.gridy++; // row 7
2326     gbc.gridx = 0;
2327     gbc.gridwidth = 4;
2328     exampleMemoryMessageTextArea.setBackground(startupTab.getBackground());
2329     JScrollPane sp = new JScrollPane(exampleMemoryMessageTextArea);
2330     sp.setBorder(BorderFactory.createEmptyBorder());
2331     sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
2332     sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
2333     startupTab.add(sp, gbc);
2334
2335     // fill empty space to push widget to top left
2336     gbc.gridy++;
2337     gbc.weighty = 1.0;
2338     gbc.gridx = 100;
2339     gbc.gridwidth = 1;
2340     gbc.weightx = 1.0;
2341     startupTab.add(new JPanel(), gbc);
2342
2343     setMemoryPercentDisplay();
2344     memoryOptionsSetEnabled();
2345     return startupTab;
2346   }
2347
2348   private void initMemoryPanel()
2349   {
2350     // Enable memory settings checkbox
2351     customiseMemorySetting.setFont(LABEL_FONT_BOLD);
2352     customiseMemorySetting.setText(
2353             MessageManager.getString("label.customise_memory_settings"));
2354     customiseMemorySetting.addActionListener(new ActionListener()
2355     {
2356       @Override
2357       public void actionPerformed(ActionEvent e)
2358       {
2359         memoryOptionsSetEnabled();
2360       }
2361     });
2362
2363     loadLastSavedMemorySettings();
2364
2365     exampleMemoryLabel.setFont(LABEL_FONT_BOLD);
2366     exampleMemoryLabel.setBackground(Color.WHITE);
2367
2368     maxMemoryLabel = new JLabel(
2369             MessageManager.getString("label.maximum_memory_used"));
2370     maxMemoryLabel.setFont(LABEL_FONT_BOLD);
2371
2372     // Maximum memory percentage slider
2373     jvmMemoryPercentLabel.setFont(LABEL_FONT);
2374     jvmMemoryPercentLabel.setText(
2375             MessageManager.getString("label.percent_of_physical_memory"));
2376     jvmMemoryPercentSlider.setPaintLabels(true);
2377     jvmMemoryPercentSlider.setPaintTicks(true);
2378     jvmMemoryPercentSlider.setPaintTrack(true);
2379     jvmMemoryPercentSlider.setMajorTickSpacing(50);
2380     jvmMemoryPercentSlider.setMinorTickSpacing(10);
2381     jvmMemoryPercentSlider.addChangeListener(new ChangeListener()
2382     {
2383       @Override
2384       public void stateChanged(ChangeEvent e)
2385       {
2386         setMemoryPercentDisplay();
2387       }
2388     });
2389     jvmMemoryPercentDisplay.setFont(LABEL_FONT);
2390     setMemoryPercentDisplay();
2391
2392     // Maximum memory cap textbox
2393     jvmMemoryMaxLabel.setFont(LABEL_FONT);
2394     jvmMemoryMaxLabel
2395             .setText(MessageManager.getString("label.maximum_memory"));
2396     initMemoryMaxTextField();
2397
2398     exampleMemoryMessageTextArea.setFont(LABEL_FONT_ITALIC);
2399     exampleMemoryMessageTextArea.setForeground(Color.GRAY);
2400     exampleMemoryMessageTextArea.setEditable(false);
2401     exampleMemoryMessageTextArea.setLineWrap(true);
2402     exampleMemoryMessageTextArea.setWrapStyleWord(true);
2403     exampleMemoryMessageTextArea.setText(" ");
2404     exampleMemoryMessageTextArea.setRows(2);
2405     exampleMemoryMessageTextArea.setColumns(40);
2406
2407     setExampleMemoryLabel();
2408   }
2409
2410   private void initMemoryMaxTextField()
2411   {
2412     jvmMemoryMaxTextField.setToolTipText(
2413             MessageManager.getString("label.maximum_memory_tooltip"));
2414     jvmMemoryMaxTextField.addActionListener(new ActionListener()
2415     {
2416       @Override
2417       public void actionPerformed(ActionEvent arg0)
2418       {
2419         validateMemoryMaxTextField();
2420         setExampleMemoryLabel();
2421       }
2422     });
2423
2424     jvmMemoryMaxTextField.addKeyListener(new KeyListener()
2425     {
2426       @Override
2427       public void keyReleased(KeyEvent e)
2428       {
2429         validateMemoryMaxTextField();
2430         setExampleMemoryLabel();
2431       }
2432
2433       @Override
2434       public void keyPressed(KeyEvent e)
2435       {
2436       }
2437
2438       // try and stop invalid typing
2439       @Override
2440       public void keyTyped(KeyEvent e)
2441       {
2442         char c = Character.toLowerCase(e.getKeyChar());
2443         String text = jvmMemoryMaxTextField.getText();
2444         String suffixes = "tgmkb";
2445         int pos = jvmMemoryMaxTextField.getCaretPosition();
2446         int suffixPos = StringUtils.firstCharPosIgnoreCase(text, suffixes);
2447         if (!((('0' <= c && c <= '9')
2448                 && (suffixPos == -1 || pos <= suffixPos)) // digits only allowed
2449                 // before suffix
2450                 || (suffixes.indexOf(Character.toLowerCase(c)) >= 0 // valid
2451                                                                     // suffix
2452                         && pos == text.length() // at end of text and
2453                         && suffixPos == -1) // there isn't already one
2454         ))
2455         {
2456           // don't process
2457           e.consume();
2458         }
2459       }
2460     });
2461   }
2462
2463   private boolean isMemoryMaxTextFieldValid()
2464   {
2465     return MemorySetting
2466             .isValidMemoryString(jvmMemoryMaxTextField.getText());
2467   }
2468
2469   private void validateMemoryMaxTextField()
2470   {
2471     if (isMemoryMaxTextFieldValid())
2472     {
2473       jvmMemoryMaxTextField.setBackground(Color.WHITE);
2474     }
2475     else
2476     {
2477       jvmMemoryMaxTextField.setBackground(Color.PINK);
2478     }
2479   }
2480
2481   private void setMemoryPercentDisplay()
2482   {
2483     jvmMemoryPercentDisplay
2484             .setText(jvmMemoryPercentSlider.getValue() + "%");
2485     setExampleMemoryLabel();
2486   }
2487
2488   private void setExampleMemoryLabel()
2489   {
2490     boolean selected = customiseMemorySetting.isSelected();
2491     int jvmmempc = jvmMemoryPercentSlider.getValue();
2492     String jvmmemmax = jvmMemoryMaxTextField.getText();
2493
2494     long mem;
2495     if (selected && (0 <= jvmmempc && jvmmempc <= 100)
2496             && MemorySetting.isValidMemoryString(jvmmemmax))
2497     {
2498       mem = MemorySetting.getMemorySetting(jvmmemmax,
2499               String.valueOf(jvmmempc), false, true);
2500     }
2501     else
2502     {
2503       mem = MemorySetting.getMemorySetting(null, null, false, true);
2504     }
2505     exampleMemoryLabel.setText(MemorySetting.memoryLongToString(mem));
2506     String message = MemorySetting.getAdjustmentMessage();
2507     exampleMemoryMessageTextArea.setText(
2508             MessageManager.getString("label.adjustments_for_this_computer")
2509                     + ": "
2510                     + (message == null
2511                             ? MessageManager.getString("label.none")
2512                             : message));
2513   }
2514
2515   private void memoryOptionsSetEnabled()
2516   {
2517     boolean enabled = customiseMemorySetting.isSelected();
2518     // leave exampleMemoryLabel enabled always
2519     maxMemoryLabel.setEnabled(enabled);
2520     jvmMemoryPercentLabel.setEnabled(enabled);
2521     jvmMemoryPercentSlider.setEnabled(enabled);
2522     jvmMemoryPercentDisplay.setEnabled(enabled);
2523     jvmMemoryMaxLabel.setEnabled(enabled);
2524     jvmMemoryMaxTextField.setEnabled(enabled);
2525     exampleMemoryMessageTextArea.setEnabled(enabled);
2526     setExampleMemoryLabel();
2527   }
2528
2529   /**
2530    * Initialises the Backups tabbed panel.
2531    * 
2532    * @return
2533    */
2534   private JPanel initBackupsTab()
2535   {
2536     JPanel backupsTab = new JPanel();
2537     backupsTab.setBorder(new TitledBorder(
2538             MessageManager.getString("label.backup_files")));
2539     backupsTab.setLayout(new GridBagLayout());
2540
2541     GridBagConstraints gbc = new GridBagConstraints();
2542     gbc.weightx = 0.0;
2543     gbc.weighty = 0.0;
2544     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
2545     gbc.fill = GridBagConstraints.NONE;
2546
2547     initBackupsTabPresetsPanel();
2548     initBackupsTabSuffixPanel();
2549     initBackupsTabKeepFilesPanel();
2550     initBackupsTabFilenameExamplesPanel();
2551
2552     enableBackupFiles.setFont(LABEL_FONT_BOLD);
2553     enableBackupFiles
2554             .setText(MessageManager.getString("label.enable_backupfiles"));
2555     enableBackupFiles.addActionListener(new ActionListener()
2556     {
2557       @Override
2558       public void actionPerformed(ActionEvent e)
2559       {
2560         // enable other options only when the first is checked
2561         backupsOptionsSetEnabled();
2562       }
2563     });
2564
2565     // enable checkbox 1 col
2566     gbc.gridwidth = 1;
2567     gbc.gridheight = 1;
2568     gbc.gridx = 0;
2569     gbc.gridy = 0; // row 0
2570     backupsTab.add(enableBackupFiles, gbc);
2571
2572     // summary of scheme box (over two rows)
2573     gbc.gridx = 1;
2574     gbc.weightx = 0.0;
2575     gbc.gridheight = 2;
2576     gbc.anchor = GridBagConstraints.FIRST_LINE_END;
2577     gbc.fill = GridBagConstraints.BOTH;
2578     backupsTab.add(exampleFilesPanel, gbc);
2579     gbc.gridheight = 1;
2580     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
2581     gbc.fill = GridBagConstraints.NONE;
2582
2583     // fill empty space on right
2584     gbc.gridx++;
2585     gbc.weightx = 1.0;
2586     backupsTab.add(new JPanel(), gbc);
2587
2588     // schemes box
2589     gbc.weightx = 0.0;
2590     gbc.gridx = 0;
2591     gbc.gridy++; // row 1
2592     backupsTab.add(presetsPanel, gbc);
2593
2594     // now using whole row
2595     gbc.gridwidth = 2;
2596     gbc.gridheight = 1;
2597     // keep files box
2598     gbc.gridx = 0;
2599     gbc.gridy++; // row 2
2600     backupsTab.add(keepfilesPanel, gbc);
2601
2602     // filename strategy box
2603     gbc.gridy++; // row 3
2604     backupsTab.add(suffixPanel, gbc);
2605
2606     // fill empty space
2607     gbc.gridy++; // row 4
2608     gbc.weighty = 1.0;
2609     backupsTab.add(new JPanel(), gbc);
2610
2611     backupsOptionsSetEnabled();
2612     return backupsTab;
2613   }
2614
2615   private JPanel initBackupsTabPresetsPanel()
2616   {
2617
2618     String title = MessageManager.getString("label.schemes");
2619
2620     presetsPanel.setLayout(new GridBagLayout());
2621
2622     GridBagConstraints gbc = new GridBagConstraints();
2623     gbc.weightx = 0.0;
2624     gbc.weighty = 0.0;
2625     gbc.anchor = GridBagConstraints.BASELINE_LEADING;
2626     gbc.fill = GridBagConstraints.NONE;
2627     gbc.gridwidth = 1;
2628     gbc.gridheight = 1;
2629
2630     // "Scheme: "
2631     gbc.gridx = 0;
2632     gbc.gridy = 0;
2633
2634     presetsComboLabel = new JLabel(title + ":");
2635     presetsPanel.add(presetsComboLabel, gbc);
2636
2637     List<Object> entries = Arrays.asList(
2638             (Object[]) BackupFilesPresetEntry.backupfilesPresetEntries);
2639     List<String> tooltips = Arrays.asList(
2640             BackupFilesPresetEntry.backupfilesPresetEntryDescriptions);
2641     backupfilesPresetsCombo = JvSwingUtils.buildComboWithTooltips(entries,
2642             tooltips);
2643     /*
2644     for (int i = 0; i < BackupFilesPresetEntry.backupfilesPresetEntries.length; i++)
2645     {
2646       backupfilesPresetsCombo
2647               .addItem(BackupFilesPresetEntry.backupfilesPresetEntries[i]);
2648     }
2649     */
2650
2651     backupfilesPresetsCombo.addActionListener(new ActionListener()
2652     {
2653       @Override
2654       public void actionPerformed(ActionEvent e)
2655       {
2656         int key = getComboIntStringKey(backupfilesPresetsCombo);
2657         if (!customiseCheckbox.isSelected())
2658         {
2659           backupfilesPresetsComboLastSelected = key;
2660         }
2661         if (key == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
2662         {
2663           if (customiseCheckbox.isSelected())
2664           {
2665             // got here by clicking on customiseCheckbox so don't change the
2666             // values
2667             backupfilesCustomOptionsSetEnabled();
2668           }
2669           else
2670           {
2671             backupsTabUpdatePresets();
2672             backupfilesCustomOptionsSetEnabled();
2673           }
2674         }
2675         else
2676         {
2677           customiseCheckbox.setSelected(false);
2678           backupsTabUpdatePresets();
2679           backupfilesCustomOptionsSetEnabled();
2680         }
2681       }
2682     });
2683
2684     // dropdown list of preset schemes
2685     gbc.gridx = 1;
2686     presetsPanel.add(backupfilesPresetsCombo, gbc);
2687
2688     revertButton.setText(MessageManager.getString("label.cancel_changes"));
2689     revertButton.setToolTipText(
2690             MessageManager.getString("label.cancel_changes_description"));
2691     revertButton.addActionListener(new ActionListener()
2692     {
2693       @Override
2694       public void actionPerformed(ActionEvent e)
2695       {
2696         backupsSetOptions(
2697                 BackupFilesPresetEntry.backupfilesPresetEntriesValues.get(
2698                         BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM));
2699         backupfilesCustomOptionsSetEnabled();
2700       }
2701
2702     });
2703     revertButton.setFont(LABEL_FONT);
2704
2705     customiseCheckbox.setFont(LABEL_FONT);
2706     customiseCheckbox.setText(MessageManager.getString("label.customise"));
2707     customiseCheckbox.addActionListener(new ActionListener()
2708     {
2709       @Override
2710       public void actionPerformed(ActionEvent e)
2711       {
2712         int currently = getComboIntStringKey(backupfilesPresetsCombo);
2713         if (customiseCheckbox.isSelected())
2714         {
2715           backupfilesPresetsComboLastSelected = currently;
2716           setComboIntStringKey(backupfilesPresetsCombo,
2717                   BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
2718         }
2719         else
2720         {
2721           setComboIntStringKey(backupfilesPresetsCombo,
2722                   backupfilesPresetsComboLastSelected);
2723
2724         }
2725         backupfilesCustomOptionsSetEnabled();
2726       }
2727     });
2728     customiseCheckbox.setToolTipText(
2729             MessageManager.getString("label.customise_description"));
2730
2731     // customise checkbox
2732     gbc.gridx = 0;
2733     gbc.gridy++;
2734     presetsPanel.add(customiseCheckbox, gbc);
2735
2736     // "Cancel changes" button (aligned with combo box above)
2737     gbc.gridx = 1;
2738     presetsPanel.add(revertButton, gbc);
2739
2740     return presetsPanel;
2741   }
2742
2743   private JPanel initBackupsTabFilenameExamplesPanel()
2744   {
2745     String title = MessageManager.getString("label.scheme_examples");
2746     TitledBorder tb = new TitledBorder(title);
2747     exampleFilesPanel.setBorder(tb);
2748     exampleFilesPanel.setLayout(new GridBagLayout());
2749
2750     backupfilesExampleLabel.setEditable(false);
2751     backupfilesExampleLabel
2752             .setBackground(exampleFilesPanel.getBackground());
2753
2754     updateBackupFilesExampleLabel();
2755
2756     GridBagConstraints gbc = new GridBagConstraints();
2757     gbc.weightx = 1.0;
2758     gbc.weighty = 1.0;
2759     gbc.fill = GridBagConstraints.NONE;
2760     gbc.anchor = GridBagConstraints.FIRST_LINE_START;
2761
2762     exampleFilesPanel.add(backupfilesExampleLabel, gbc);
2763     return exampleFilesPanel;
2764   }
2765
2766   private void backupsTabUpdatePresets()
2767   {
2768     IntKeyStringValueEntry entry = (IntKeyStringValueEntry) backupfilesPresetsCombo
2769             .getSelectedItem();
2770     int key = entry.k;
2771     String value = entry.v;
2772
2773     if (BackupFilesPresetEntry.backupfilesPresetEntriesValues
2774             .containsKey(key))
2775     {
2776       backupsSetOptions(
2777               BackupFilesPresetEntry.backupfilesPresetEntriesValues
2778                       .get(key));
2779     }
2780     else
2781     {
2782       Console.error(
2783               "Preset '" + value + "' [key:" + key + "] not implemented");
2784     }
2785
2786     // Custom options will now be enabled when the customiseCheckbox is checked
2787     // (performed above)
2788     // backupfilesCustomOptionsSetEnabled();
2789     updateBackupFilesExampleLabel();
2790   }
2791
2792   protected int getComboIntStringKey(
2793           JComboBox<Object> backupfilesPresetsCombo2)
2794   {
2795     IntKeyStringValueEntry e;
2796     try
2797     {
2798       e = (IntKeyStringValueEntry) backupfilesPresetsCombo2
2799               .getSelectedItem();
2800     } catch (Exception ex)
2801     {
2802       Console.error(
2803               "Problem casting Combo entry to IntKeyStringValueEntry.");
2804       e = null;
2805     }
2806     return e != null ? e.k : 0;
2807   }
2808
2809   protected void setComboIntStringKey(
2810           JComboBox<Object> backupfilesPresetsCombo2, int key)
2811   {
2812     for (int i = 0; i < backupfilesPresetsCombo2.getItemCount(); i++)
2813     {
2814       IntKeyStringValueEntry e;
2815       try
2816       {
2817         e = (IntKeyStringValueEntry) backupfilesPresetsCombo2.getItemAt(i);
2818       } catch (Exception ex)
2819       {
2820         Console.error(
2821                 "Problem casting Combo entry to IntKeyStringValueEntry. Skipping item. ");
2822         continue;
2823       }
2824       if (e.k == key)
2825       {
2826         backupfilesPresetsCombo2.setSelectedIndex(i);
2827         break;
2828       }
2829     }
2830     // backupsTabUpdatePresets();
2831   }
2832
2833   private JPanel initBackupsTabSuffixPanel()
2834   {
2835     suffixPanel.setBorder(new TitledBorder(
2836             MessageManager.getString("label.backup_filename_strategy")));
2837     suffixPanel.setLayout(new GridBagLayout());
2838
2839     suffixTemplateLabel
2840             .setText(MessageManager.getString("label.append_to_filename"));
2841     suffixTemplateLabel.setHorizontalAlignment(SwingConstants.LEFT);
2842     suffixTemplateLabel.setFont(LABEL_FONT);
2843
2844     final String tooltip = JvSwingUtils.wrapTooltip(true,
2845             MessageManager.getString("label.append_to_filename_tooltip"));
2846     suffixTemplate.setToolTipText(tooltip);
2847     suffixTemplate.addActionListener(new ActionListener()
2848     {
2849       @Override
2850       public void actionPerformed(ActionEvent e)
2851       {
2852         updateBackupFilesExampleLabel();
2853         backupfilesCustomOptionsSetEnabled();
2854         backupfilesRevertButtonSetEnabled(true);
2855       }
2856
2857     });
2858     suffixTemplate.addKeyListener(new KeyListener()
2859     {
2860       @Override
2861       public void keyReleased(KeyEvent e)
2862       {
2863         updateBackupFilesExampleLabel();
2864         backupfilesCustomOptionsSetEnabled();
2865         backupfilesRevertButtonSetEnabled(true);
2866       }
2867
2868       @Override
2869       public void keyPressed(KeyEvent e)
2870       {
2871       }
2872
2873       // disable use of ':' or '/' or '\'
2874       @Override
2875       public void keyTyped(KeyEvent e)
2876       {
2877         char c = e.getKeyChar();
2878         if (c == ':' || c == '/' || c == '\\')
2879         {
2880           // don't process ':' or '/' or '\'
2881           e.consume();
2882         }
2883       }
2884
2885     });
2886
2887     // digits spinner
2888     suffixDigitsLabel
2889             .setText(MessageManager.getString("label.index_digits"));
2890     suffixDigitsLabel.setHorizontalAlignment(SwingConstants.LEFT);
2891     suffixDigitsLabel.setFont(LABEL_FONT);
2892     ChangeListener c = new ChangeListener()
2893     {
2894       @Override
2895       public void stateChanged(ChangeEvent e)
2896       {
2897         backupfilesRevertButtonSetEnabled(true);
2898         updateBackupFilesExampleLabel();
2899       }
2900
2901     };
2902     setIntegerSpinner(suffixDigitsSpinner, BackupFilesPresetEntry.DIGITSMIN,
2903             BackupFilesPresetEntry.DIGITSMAX, 3, c);
2904
2905     suffixReverse.setLabels(MessageManager.getString("label.reverse_roll"),
2906             MessageManager.getString("label.increment_index"));
2907     suffixReverse.addActionListener(new ActionListener()
2908     {
2909       @Override
2910       public void actionPerformed(ActionEvent e)
2911       {
2912         boolean okay = true;
2913         if (warnAboutSuffixReverseChange())
2914         {
2915           // Warning popup
2916           okay = confirmSuffixReverseChange();
2917         }
2918         if (okay)
2919         {
2920           backupfilesRevertButtonSetEnabled(true);
2921           updateBackupFilesExampleLabel();
2922         }
2923         else
2924         {
2925           boolean savedSuffixReverse = BackupFilesPresetEntry
2926                   .getSavedBackupEntry().reverse;
2927           suffixReverse.setSelected(savedSuffixReverse);
2928         }
2929       }
2930     });
2931
2932     GridBagConstraints sgbc = new GridBagConstraints();
2933
2934     // first row (template text box)
2935     sgbc.anchor = GridBagConstraints.WEST;
2936     sgbc.gridx = 0;
2937     sgbc.gridy = 0;
2938     sgbc.gridwidth = 1;
2939     sgbc.gridheight = 1;
2940     sgbc.weightx = 1.0;
2941     sgbc.weighty = 0.0;
2942     sgbc.fill = GridBagConstraints.NONE;
2943     suffixPanel.add(suffixTemplateLabel, sgbc);
2944
2945     sgbc.gridx = 1;
2946     sgbc.fill = GridBagConstraints.HORIZONTAL;
2947     suffixPanel.add(suffixTemplate, sgbc);
2948
2949     // second row (number of digits spinner)
2950     sgbc.gridy = 1;
2951
2952     sgbc.gridx = 0;
2953     sgbc.fill = GridBagConstraints.NONE;
2954     suffixPanel.add(suffixDigitsLabel, sgbc);
2955
2956     sgbc.gridx = 1;
2957     sgbc.fill = GridBagConstraints.HORIZONTAL;
2958     suffixPanel.add(suffixDigitsSpinner, sgbc);
2959
2960     // third row (forward order radio selection)
2961     sgbc.gridx = 0;
2962     sgbc.gridy = 2;
2963     sgbc.gridwidth = GridBagConstraints.REMAINDER;
2964     sgbc.fill = GridBagConstraints.HORIZONTAL;
2965     suffixPanel.add(suffixReverse.getFalseButton(), sgbc);
2966
2967     // fourth row (reverse order radio selection)
2968     sgbc.gridy = 3;
2969     suffixPanel.add(suffixReverse.getTrueButton(), sgbc);
2970     return suffixPanel;
2971   }
2972
2973   private boolean confirmSuffixReverseChange()
2974   {
2975     boolean ret = false;
2976     String warningMessage = MessageManager
2977             .getString("label.warning_confirm_change_reverse");
2978     int confirm = JvOptionPane.showConfirmDialog(Desktop.desktop,
2979             warningMessage,
2980             MessageManager.getString("label.change_increment_decrement"),
2981             JvOptionPane.YES_NO_OPTION, JvOptionPane.WARNING_MESSAGE);
2982
2983     ret = (confirm == JvOptionPane.YES_OPTION);
2984     return ret;
2985   }
2986
2987   private JPanel initBackupsTabKeepFilesPanel()
2988   {
2989     keepfilesPanel.setBorder(
2990             new TitledBorder(MessageManager.getString("label.keep_files")));
2991     keepfilesPanel.setLayout(new GridBagLayout());
2992
2993     backupfilesKeepAll.setLabels(
2994             MessageManager.getString("label.keep_all_backup_files"),
2995             MessageManager.getString(
2996                     "label.keep_only_this_number_of_backup_files"));
2997     backupfilesKeepAll.addTrueActionListener(new ActionListener()
2998     {
2999       @Override
3000       public void actionPerformed(ActionEvent e)
3001       {
3002         backupfilesRevertButtonSetEnabled(true);
3003         updateBackupFilesExampleLabel();
3004       }
3005     });
3006     backupfilesKeepAll.addActionListener(new ActionListener()
3007     {
3008       @Override
3009       public void actionPerformed(ActionEvent e)
3010       {
3011         backupfilesRevertButtonSetEnabled(true);
3012         keepRollMaxOptionsEnabled();
3013         updateBackupFilesExampleLabel();
3014       }
3015     });
3016
3017     ChangeListener c = new ChangeListener()
3018     {
3019       @Override
3020       public void stateChanged(ChangeEvent e)
3021       {
3022         backupfilesRevertButtonSetEnabled(true);
3023         updateBackupFilesExampleLabel();
3024       }
3025
3026     };
3027     setIntegerSpinner(backupfilesRollMaxSpinner,
3028             BackupFilesPresetEntry.ROLLMAXMIN,
3029             BackupFilesPresetEntry.ROLLMAXMAX, 4, true, c);
3030
3031     backupfilesConfirmDelete.setLabels(
3032             MessageManager.getString("label.always_ask"),
3033             MessageManager.getString("label.auto_delete"));
3034     backupfilesConfirmDelete.addActionListener(new ActionListener()
3035     {
3036       @Override
3037       public void actionPerformed(ActionEvent e)
3038       {
3039         backupfilesRevertButtonSetEnabled(true);
3040       }
3041     });
3042     // update the enabled section
3043     keepRollMaxOptionsEnabled();
3044
3045     GridBagConstraints kgbc = new GridBagConstraints();
3046
3047     // first row (template text box)
3048     kgbc.anchor = GridBagConstraints.WEST;
3049     kgbc.gridx = 0;
3050     kgbc.gridy = 0;
3051     kgbc.gridwidth = GridBagConstraints.REMAINDER;
3052     kgbc.gridheight = 1;
3053     kgbc.weightx = 1.0;
3054     kgbc.weighty = 0.0;
3055     kgbc.fill = GridBagConstraints.HORIZONTAL;
3056     keepfilesPanel.add(backupfilesKeepAll.getTrueButton(), kgbc);
3057
3058     // second row
3059     kgbc.gridy = 1;
3060
3061     kgbc.gridx = 0;
3062     kgbc.gridwidth = GridBagConstraints.RELATIVE;
3063     keepfilesPanel.add(backupfilesKeepAll.getFalseButton(), kgbc);
3064
3065     kgbc.gridx = 1;
3066     kgbc.gridwidth = GridBagConstraints.REMAINDER;
3067     keepfilesPanel.add(backupfilesRollMaxSpinner, kgbc);
3068
3069     // third row (indented)
3070     kgbc.gridy = 2;
3071     kgbc.insets = new Insets(0, 20, 0, 0);
3072
3073     kgbc.gridx = 0;
3074     kgbc.gridwidth = GridBagConstraints.REMAINDER;
3075     kgbc.fill = GridBagConstraints.HORIZONTAL;
3076     kgbc.weightx = 1.0;
3077
3078     JPanel jp = new JPanel();
3079     jp.setLayout(new FlowLayout());
3080     oldBackupFilesLabel.setText(
3081             MessageManager.getString("label.autodelete_old_backup_files"));
3082     oldBackupFilesLabel.setFont(LABEL_FONT);
3083     oldBackupFilesLabel.setHorizontalAlignment(SwingConstants.LEFT);
3084     jp.add(oldBackupFilesLabel);
3085     jp.add(backupfilesConfirmDelete.getTrueButton());
3086     jp.add(backupfilesConfirmDelete.getFalseButton());
3087     keepfilesPanel.add(jp, kgbc);
3088
3089     return keepfilesPanel;
3090   }
3091
3092   protected void updateBackupFilesExampleLabel()
3093   {
3094     int exampleindex = 12;
3095     String base = MessageManager.getString("label.filename") + ".fa";
3096     if (base == null || base.length() == 0)
3097     {
3098       base = "file_name.fa";
3099     }
3100
3101     boolean reverse = suffixReverse.isSelected();
3102     boolean keepAll = backupfilesKeepAll.isSelected();
3103     int rollMax = 4;
3104     String suffix = suffixTemplate.getText();
3105     int digits = 3;
3106
3107     backupfilesExampleLabel.setFont(LABEL_FONT_ITALIC);
3108     if (suffix == null || suffix.length() == 0)
3109     {
3110       backupfilesExampleLabel
3111               .setText(MessageManager.getString("label.no_backup_files"));
3112       backupfilesExampleLabel.setFont(LABEL_FONT_BOLD);
3113       return;
3114     }
3115
3116     rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 4);
3117     rollMax = rollMax < 1 ? 1 : rollMax;
3118
3119     if (suffix.indexOf(BackupFiles.NUM_PLACEHOLDER) == -1)
3120     {
3121       rollMax = 1;
3122     }
3123
3124     digits = getSpinnerInt(suffixDigitsSpinner, 3);
3125     digits = digits < 1 ? 1 : digits;
3126
3127     int lowersurround = 2;
3128     int uppersurround = 0;
3129     StringBuilder exampleSB = new StringBuilder();
3130     boolean firstLine = true;
3131     int lineNumber = 0;
3132     if (reverse)
3133     {
3134
3135       int min = 1;
3136       int max = keepAll ? exampleindex : rollMax;
3137       for (int index = min; index <= max; index++)
3138       {
3139         if (index == min + lowersurround && index < max - uppersurround - 1)
3140         {
3141           exampleSB.append("\n...");
3142           lineNumber++;
3143         }
3144         else if (index > min + lowersurround && index < max - uppersurround)
3145         {
3146           // nothing
3147         }
3148         else
3149         {
3150           if (firstLine)
3151           {
3152             firstLine = false;
3153           }
3154           else
3155           {
3156             exampleSB.append("\n");
3157             lineNumber++;
3158           }
3159           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
3160                   base, suffix, digits));
3161           if (min == max)
3162           {
3163             // no extra text needed
3164           }
3165           else if (index == min)
3166           {
3167             String newest = MessageManager.getString("label.braced_newest");
3168             if (newest != null && newest.length() > 0)
3169             {
3170               exampleSB.append(" " + newest);
3171             }
3172           }
3173           else if (index == max)
3174           {
3175             String oldest = MessageManager.getString("label.braced_oldest");
3176             if (oldest != null && oldest.length() > 0)
3177             {
3178               exampleSB.append(" " + oldest);
3179             }
3180           }
3181         }
3182       }
3183     }
3184     else
3185     {
3186
3187       int min = (keepAll || exampleindex - rollMax < 0) ? 1
3188               : exampleindex - rollMax + 1;
3189       int max = exampleindex;
3190
3191       for (int index = min; index <= max; index++)
3192       {
3193
3194         if (index == min + lowersurround && index < max - uppersurround - 1)
3195         {
3196           exampleSB.append("\n...");
3197           lineNumber++;
3198         }
3199         else if (index > min + lowersurround && index < max - uppersurround)
3200         {
3201           // nothing
3202         }
3203         else
3204         {
3205           if (firstLine)
3206           {
3207             firstLine = false;
3208           }
3209           else
3210           {
3211             exampleSB.append("\n");
3212             lineNumber++;
3213           }
3214           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
3215                   base, suffix, digits));
3216           if (min == max)
3217           {
3218             // no extra text needed
3219           }
3220           else if (index == min)
3221           {
3222             String oldest = MessageManager.getString("label.braced_oldest");
3223             if (oldest != null && oldest.length() > 0)
3224             {
3225               exampleSB.append(" " + oldest);
3226             }
3227           }
3228           else if (index == max)
3229           {
3230             String newest = MessageManager.getString("label.braced_newest");
3231             if (newest != null && newest.length() > 0)
3232             {
3233               exampleSB.append(" " + newest);
3234             }
3235           }
3236         }
3237       }
3238
3239     }
3240
3241     // add some extra empty lines to pad out the example files box. ugh, please
3242     // tell
3243     // me how to do this better
3244     int remainingLines = lowersurround + uppersurround + 1 - lineNumber;
3245     if (remainingLines > 0)
3246     {
3247       for (int i = 0; i < remainingLines; i++)
3248       {
3249         exampleSB.append("\n ");
3250         lineNumber++;
3251       }
3252     }
3253
3254     backupfilesExampleLabel.setText(exampleSB.toString());
3255   }
3256
3257   protected void setIntegerSpinner(JSpinner s, int min, int max, int def,
3258           boolean useExistingVal, ChangeListener c)
3259   {
3260     int i = def;
3261     if (useExistingVal)
3262     {
3263       try
3264       {
3265         i = ((Integer) s.getValue()).intValue();
3266       } catch (Exception e)
3267       {
3268         Console.error(
3269                 "Exception casting the initial value of s.getValue()");
3270       }
3271     }
3272
3273     setIntegerSpinner(s, min, max, i, c);
3274   }
3275
3276   protected void setIntegerSpinner(JSpinner s, int min, int max, int def,
3277           ChangeListener c)
3278   {
3279     // integer spinner for number of digits
3280     if (def > max)
3281     {
3282       max = def;
3283     }
3284     if (def < min)
3285     {
3286       def = min;
3287     }
3288     SpinnerModel sModel = new SpinnerNumberModel(def, min, max, 1);
3289     s.setModel(sModel);
3290
3291     s.addChangeListener(c);
3292
3293   }
3294
3295   protected static int getSpinnerInt(JSpinner s, int def)
3296   {
3297     int i = def;
3298     try
3299     {
3300       s.commitEdit();
3301       i = (Integer) s.getValue();
3302     } catch (Exception e)
3303     {
3304       Console.error("Failed casting (Integer) JSpinner s.getValue()");
3305     }
3306     return i;
3307   }
3308
3309   private void keepRollMaxOptionsEnabled()
3310   {
3311     boolean enabled = backupfilesKeepAll.isEnabled()
3312             && !backupfilesKeepAll.isSelected();
3313     oldBackupFilesLabel.setEnabled(enabled);
3314     backupfilesRollMaxSpinner.setEnabled(enabled);
3315     backupfilesConfirmDelete.setEnabled(enabled);
3316   }
3317
3318   private void backupfilesKeepAllSetEnabled(boolean tryEnabled)
3319   {
3320     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
3321             && customiseCheckbox.isSelected() && suffixTemplate.getText()
3322                     .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
3323     keepfilesPanel.setEnabled(enabled);
3324     backupfilesKeepAll.setEnabled(enabled);
3325     oldBackupFilesLabel.setEnabled(enabled);
3326     keepRollMaxOptionsEnabled();
3327   }
3328
3329   private void backupfilesSuffixTemplateDigitsSetEnabled()
3330   {
3331     boolean enabled = suffixTemplate.isEnabled() && suffixTemplate.getText()
3332             .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
3333     suffixDigitsLabel.setEnabled(enabled);
3334     suffixDigitsSpinner.setEnabled(enabled);
3335     suffixReverse.setEnabled(enabled);
3336   }
3337
3338   private void backupfilesSuffixTemplateSetEnabled(boolean tryEnabled)
3339   {
3340     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
3341             && customiseCheckbox.isSelected();
3342     suffixPanel.setEnabled(enabled);
3343     suffixTemplateLabel.setEnabled(enabled);
3344     suffixTemplate.setEnabled(enabled);
3345     backupfilesSuffixTemplateDigitsSetEnabled();
3346   }
3347
3348   private void backupfilesRevertButtonSetEnabled(boolean tryEnabled)
3349   {
3350     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
3351             && customiseCheckbox.isSelected() && backupfilesCustomChanged();
3352     revertButton.setEnabled(enabled);
3353   }
3354
3355   private boolean backupfilesCustomChanged()
3356   {
3357     BackupFilesPresetEntry custom = BackupFilesPresetEntry.backupfilesPresetEntriesValues
3358             .get(BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
3359     BackupFilesPresetEntry current = getBackupfilesCurrentEntry();
3360     return !custom.equals(current);
3361   }
3362
3363   protected BackupFilesPresetEntry getBackupfilesCurrentEntry()
3364   {
3365     String suffix = suffixTemplate.getText();
3366     int digits = getSpinnerInt(suffixDigitsSpinner, 3);
3367     boolean reverse = suffixReverse.isSelected();
3368     boolean keepAll = backupfilesKeepAll.isSelected();
3369     int rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 3);
3370     boolean confirmDelete = backupfilesConfirmDelete.isSelected();
3371
3372     BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits,
3373             reverse, keepAll, rollMax, confirmDelete);
3374
3375     return bfpe;
3376   }
3377
3378   protected void backupfilesCustomOptionsSetEnabled()
3379   {
3380     boolean enabled = customiseCheckbox.isSelected();
3381
3382     backupfilesRevertButtonSetEnabled(enabled);
3383     backupfilesSuffixTemplateSetEnabled(enabled);
3384     backupfilesKeepAllSetEnabled(enabled);
3385   }
3386
3387   private void backupfilesSummarySetEnabled()
3388   {
3389     boolean enabled = enableBackupFiles.isSelected();
3390     backupfilesExampleLabel.setEnabled(enabled);
3391     exampleFilesPanel.setEnabled(enabled);
3392   }
3393
3394   private void backupfilesPresetsSetEnabled()
3395   {
3396     boolean enabled = enableBackupFiles.isSelected();
3397     presetsPanel.setEnabled(enabled);
3398     presetsComboLabel.setEnabled(enabled);
3399     backupfilesPresetsCombo.setEnabled(enabled);
3400     customiseCheckbox.setEnabled(enabled);
3401     revertButton.setEnabled(enabled);
3402   }
3403
3404   protected void backupsOptionsSetEnabled()
3405   {
3406     backupfilesPresetsSetEnabled();
3407     backupfilesSummarySetEnabled();
3408     backupfilesCustomOptionsSetEnabled();
3409   }
3410
3411   protected void backupsSetOptions(String suffix, int digits,
3412           boolean reverse, boolean keepAll, int rollMax,
3413           boolean confirmDelete)
3414   {
3415     suffixTemplate.setText(suffix);
3416     suffixDigitsSpinner.setValue(digits);
3417     suffixReverse.setSelected(reverse);
3418     backupfilesKeepAll.setSelected(keepAll);
3419     backupfilesRollMaxSpinner.setValue(rollMax);
3420     backupfilesConfirmDelete.setSelected(confirmDelete);
3421   }
3422
3423   protected void backupsSetOptions(BackupFilesPresetEntry p)
3424   {
3425     backupsSetOptions(p.suffix, p.digits, p.reverse, p.keepAll, p.rollMax,
3426             p.confirmDelete);
3427   }
3428
3429   protected void autoIdWidth_actionPerformed()
3430   {
3431     // TODO Auto-generated method stub
3432
3433   }
3434
3435   protected void userIdWidth_actionPerformed()
3436   {
3437     // TODO Auto-generated method stub
3438
3439   }
3440
3441   protected void maxColour_actionPerformed(JPanel panel)
3442   {
3443   }
3444
3445   protected void minColour_actionPerformed(JPanel panel)
3446   {
3447   }
3448
3449   protected void gapColour_actionPerformed(JPanel panel)
3450   {
3451   }
3452
3453   protected void hiddenColour_actionPerformed(JPanel panel)
3454   {
3455   }
3456
3457   protected void showunconserved_actionPerformed(ActionEvent e)
3458   {
3459     // TODO Auto-generated method stub
3460
3461   }
3462
3463   protected void useLegacyGaps_actionPerformed(ActionEvent e)
3464   {
3465   }
3466
3467   protected void resetOvDefaults_actionPerformed(ActionEvent e)
3468   {
3469   }
3470
3471   /**
3472    * DOCUMENT ME!
3473    * 
3474    * @param e
3475    *          DOCUMENT ME!
3476    */
3477   public void ok_actionPerformed(ActionEvent e)
3478   {
3479   }
3480
3481   /**
3482    * DOCUMENT ME!
3483    * 
3484    * @param e
3485    *          DOCUMENT ME!
3486    */
3487   public void cancel_actionPerformed(ActionEvent e)
3488   {
3489   }
3490
3491   /**
3492    * DOCUMENT ME!
3493    * 
3494    * @param e
3495    *          DOCUMENT ME!
3496    */
3497   public void annotations_actionPerformed(ActionEvent e)
3498   {
3499   }
3500
3501   /**
3502    * DOCUMENT ME!
3503    */
3504   public void startupFileTextfield_mouseClicked()
3505   {
3506   }
3507
3508   public void newLink_actionPerformed(ActionEvent e)
3509   {
3510
3511   }
3512
3513   public void editLink_actionPerformed(ActionEvent e)
3514   {
3515
3516   }
3517
3518   public void deleteLink_actionPerformed(ActionEvent e)
3519   {
3520
3521   }
3522
3523   public void linkURLList_keyTyped(KeyEvent e)
3524   {
3525
3526   }
3527
3528   public void setProxyAuthEnabled()
3529   {
3530     boolean enabled = proxyAuth.isSelected() && proxyAuth.isEnabled();
3531     proxyAuthUsernameLabel.setEnabled(enabled);
3532     proxyAuthPasswordLabel.setEnabled(enabled);
3533     passwordNotStoredLabel.setEnabled(enabled);
3534     proxyAuthUsernameTB.setEnabled(enabled);
3535     proxyAuthPasswordPB.setEnabled(enabled);
3536   }
3537
3538   public void setCustomProxyEnabled()
3539   {
3540     boolean enabled = customProxy.isSelected();
3541     portLabel.setEnabled(enabled);
3542     serverLabel.setEnabled(enabled);
3543     portLabel2.setEnabled(enabled);
3544     serverLabel2.setEnabled(enabled);
3545     httpLabel.setEnabled(enabled);
3546     httpsLabel.setEnabled(enabled);
3547     proxyServerHttpTB.setEnabled(enabled);
3548     proxyPortHttpTB.setEnabled(enabled);
3549     proxyServerHttpsTB.setEnabled(enabled);
3550     proxyPortHttpsTB.setEnabled(enabled);
3551     proxyAuth.setEnabled(enabled);
3552     setProxyAuthEnabled();
3553   }
3554
3555   public void proxyType_actionPerformed()
3556   {
3557     setCustomProxyEnabled();
3558     proxyAuthPasswordCheckHighlight(true);
3559     applyProxyButtonEnabled(true);
3560   }
3561
3562   public void proxyAuth_actionPerformed()
3563   {
3564     setProxyAuthEnabled();
3565     proxyAuthPasswordCheckHighlight(true);
3566     applyProxyButtonEnabled(true);
3567   }
3568
3569   /**
3570    * Customer renderer for JTable: supports column of radio buttons
3571    */
3572   public class RadioButtonRenderer extends JRadioButton
3573           implements TableCellRenderer
3574   {
3575     public RadioButtonRenderer()
3576     {
3577       setHorizontalAlignment(CENTER);
3578       setToolTipText(MessageManager.getString("label.urltooltip"));
3579     }
3580
3581     @Override
3582     public Component getTableCellRendererComponent(JTable table,
3583             Object value, boolean isSelected, boolean hasFocus, int row,
3584             int column)
3585     {
3586       setSelected((boolean) value);
3587
3588       // set colours to match rest of table
3589       if (isSelected)
3590       {
3591         setBackground(table.getSelectionBackground());
3592         setForeground(table.getSelectionForeground());
3593       }
3594       else
3595       {
3596         setBackground(table.getBackground());
3597         setForeground(table.getForeground());
3598       }
3599       return this;
3600     }
3601   }
3602
3603   /**
3604    * Customer cell editor for JTable: supports column of radio buttons in
3605    * conjunction with renderer
3606    */
3607   public class RadioButtonEditor extends AbstractCellEditor
3608           implements TableCellEditor
3609   {
3610     private JRadioButton button = new JRadioButton();
3611
3612     public RadioButtonEditor()
3613     {
3614       button.setHorizontalAlignment(SwingConstants.CENTER);
3615       this.button.addActionListener(new ActionListener()
3616       {
3617         @Override
3618         public void actionPerformed(ActionEvent e)
3619         {
3620           fireEditingStopped();
3621         }
3622       });
3623     }
3624
3625     @Override
3626     public Component getTableCellEditorComponent(JTable table, Object value,
3627             boolean isSelected, int row, int column)
3628     {
3629       button.setSelected((boolean) value);
3630       return button;
3631     }
3632
3633     @Override
3634     public Object getCellEditorValue()
3635     {
3636       return button.isSelected();
3637     }
3638
3639   }
3640 }