JAL-2371 remove ColourSchemeI.findColour(c), pure interface groovy
[jalview.git] / src / jalview / gui / UserDefinedColours.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.api.structures.JalviewStructureDisplayI;
24 import jalview.bin.Cache;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.io.JalviewFileChooser;
27 import jalview.io.JalviewFileView;
28 import jalview.jbgui.GUserDefinedColours;
29 import jalview.schemabinding.version2.Colour;
30 import jalview.schemabinding.version2.JalviewUserColours;
31 import jalview.schemes.ColourSchemeI;
32 import jalview.schemes.ColourSchemes;
33 import jalview.schemes.ResidueProperties;
34 import jalview.schemes.UserColourScheme;
35 import jalview.util.ColorUtils;
36 import jalview.util.Format;
37 import jalview.util.MessageManager;
38
39 import java.awt.Color;
40 import java.awt.Font;
41 import java.awt.Insets;
42 import java.awt.event.ActionEvent;
43 import java.awt.event.MouseAdapter;
44 import java.awt.event.MouseEvent;
45 import java.io.File;
46 import java.io.FileOutputStream;
47 import java.io.OutputStreamWriter;
48 import java.io.PrintWriter;
49 import java.util.ArrayList;
50 import java.util.List;
51
52 import javax.swing.JButton;
53 import javax.swing.JInternalFrame;
54 import javax.swing.event.ChangeEvent;
55 import javax.swing.event.ChangeListener;
56
57 /**
58  * This panel allows the user to assign colours to Amino Acid residue codes, and
59  * save the colour scheme.
60  * 
61  * @author Andrew Waterhouse
62  * @author Mungo Carstairs
63  */
64 public class UserDefinedColours extends GUserDefinedColours implements
65         ChangeListener
66 {
67   private static final Font VERDANA_BOLD_10 = new Font("Verdana", Font.BOLD, 10);
68
69   public static final String USER_DEFINED_COLOURS = "USER_DEFINED_COLOURS";
70
71   private static final String LAST_DIRECTORY = "LAST_DIRECTORY";
72
73   private static final int MY_FRAME_HEIGHT = 420;
74
75   private static final int MY_FRAME_WIDTH = 810;
76
77   private static final int MY_FRAME_WIDTH_CASE_SENSITIVE = 970;
78
79   AlignmentPanel ap;
80
81   SequenceGroup seqGroup;
82
83   List<JButton> selectedButtons;
84
85   ColourSchemeI oldColourScheme;
86
87   JInternalFrame frame;
88
89   JalviewStructureDisplayI structureViewer;
90
91   List<JButton> upperCaseButtons;
92
93   List<JButton> lowerCaseButtons;
94
95   /**
96    * Creates a new UserDefinedColours object.
97    * 
98    * @param ap
99    * @param sg
100    */
101   public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
102   {
103     super();
104
105     lcaseColour.setEnabled(false);
106
107     this.ap = ap;
108     seqGroup = sg;
109
110     if (seqGroup != null)
111     {
112       oldColourScheme = seqGroup.getColourScheme();
113     }
114     else
115     {
116       oldColourScheme = ap.av.getGlobalColourScheme();
117     }
118
119     if (oldColourScheme instanceof UserColourScheme)
120     {
121       schemeName.setText(oldColourScheme.getSchemeName());
122       if (((UserColourScheme) oldColourScheme).getLowerCaseColours() != null)
123       {
124         caseSensitive.setSelected(true);
125         lcaseColour.setEnabled(true);
126         resetButtonPanel(true);
127       }
128       else
129       {
130         resetButtonPanel(false);
131       }
132     }
133     else
134     {
135       resetButtonPanel(false);
136     }
137
138     showFrame();
139   }
140
141   public UserDefinedColours(JalviewStructureDisplayI viewer,
142           ColourSchemeI oldcs)
143   {
144     super();
145     this.structureViewer = viewer;
146
147     colorChooser.getSelectionModel().addChangeListener(this);
148
149     oldColourScheme = oldcs;
150
151     if (oldColourScheme instanceof UserColourScheme)
152     {
153       schemeName.setText(((UserColourScheme) oldColourScheme).getSchemeName());
154     }
155
156     resetButtonPanel(false);
157
158     showFrame();
159
160   }
161
162   void showFrame()
163   {
164     colorChooser.getSelectionModel().addChangeListener(this);
165     frame = new JInternalFrame();
166     frame.setContentPane(this);
167     Desktop.addInternalFrame(frame,
168             MessageManager.getString("label.user_defined_colours"),
169             MY_FRAME_WIDTH, MY_FRAME_HEIGHT, true);
170
171     if (seqGroup != null)
172     {
173       frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
174     }
175   }
176
177   /**
178    * Rebuilds the panel with coloured buttons for residues. If not case
179    * sensitive colours, show 3-letter amino acid code as button text. If case
180    * sensitive, just show the single letter code, in order to make space for the
181    * additional buttons.
182    * 
183    * @param isCaseSensitive
184    */
185   void resetButtonPanel(boolean isCaseSensitive)
186   {
187     buttonPanel.removeAll();
188
189     if (upperCaseButtons == null)
190     {
191       upperCaseButtons = new ArrayList<JButton>();
192     }
193
194     for (int i = 0; i < 20; i++)
195     {
196       String label = isCaseSensitive ? ResidueProperties.aa[i]
197               : ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
198                       .toString();
199       JButton button = makeButton(label, ResidueProperties.aa[i],
200               upperCaseButtons, i);
201       buttonPanel.add(button);
202     }
203
204     buttonPanel.add(makeButton("B", "B", upperCaseButtons, 20));
205     buttonPanel.add(makeButton("Z", "Z", upperCaseButtons, 21));
206     buttonPanel.add(makeButton("X", "X", upperCaseButtons, 22));
207     buttonPanel.add(makeButton("Gap", "-", upperCaseButtons, 23));
208
209     if (!isCaseSensitive)
210     {
211       gridLayout.setRows(6);
212       gridLayout.setColumns(4);
213     }
214     else
215     {
216       gridLayout.setRows(7);
217       int cols = 7;
218       gridLayout.setColumns(cols + 1);
219
220       if (lowerCaseButtons == null)
221       {
222         lowerCaseButtons = new ArrayList<JButton>();
223       }
224
225       for (int i = 0; i < 20; i++)
226       {
227         int row = i / cols + 1;
228         int index = (row * cols) + i;
229         JButton button = makeButton(ResidueProperties.aa[i].toLowerCase(),
230                 ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
231
232         buttonPanel.add(button, index);
233       }
234     }
235
236     if (isCaseSensitive)
237     {
238       buttonPanel.add(makeButton("b", "b", lowerCaseButtons, 20));
239       buttonPanel.add(makeButton("z", "z", lowerCaseButtons, 21));
240       buttonPanel.add(makeButton("x", "x", lowerCaseButtons, 22));
241     }
242
243     // JAL-1360 widen the frame dynamically to accommodate case-sensitive AA
244     // codes
245     if (this.frame != null)
246     {
247       int newWidth = isCaseSensitive ? MY_FRAME_WIDTH_CASE_SENSITIVE
248               : MY_FRAME_WIDTH;
249       this.frame.setSize(newWidth, this.frame.getHeight());
250     }
251
252     buttonPanel.validate();
253     validate();
254   }
255
256   /**
257    * DOCUMENT ME!
258    * 
259    * @param evt
260    *          DOCUMENT ME!
261    */
262   @Override
263   public void stateChanged(ChangeEvent evt)
264   {
265     if (selectedButtons != null)
266     {
267       JButton button = null;
268       final Color newColour = colorChooser.getColor();
269       for (int i = 0; i < selectedButtons.size(); i++)
270       {
271         button = selectedButtons.get(i);
272         button.setBackground(newColour);
273         button.setForeground(ColorUtils.brighterThan(newColour));
274       }
275       if (button == lcaseColour)
276       {
277         for (int i = 0; i < lowerCaseButtons.size(); i++)
278         {
279           button = lowerCaseButtons.get(i);
280           button.setBackground(newColour);
281           button.setForeground(ColorUtils.brighterThan(button
282                   .getBackground()));
283         }
284       }
285     }
286   }
287
288   /**
289    * Performs actions when a residue button is clicked. This manages the button
290    * selection set (highlighted by brighter foreground text).
291    * <p>
292    * On select button(s) with Ctrl/click or Shift/click: set button foreground
293    * text to brighter than background.
294    * <p>
295    * On unselect button(s) with Ctrl/click on selected, or click to release
296    * current selection: reset foreground text to darker than background.
297    * <p>
298    * Simple click: clear selection (resetting foreground to darker); set clicked
299    * button foreground to brighter
300    * <p>
301    * Finally, synchronize the colour chooser to the colour of the first button
302    * in the selected set.
303    * 
304    * @param e
305    */
306   public void colourButtonPressed(MouseEvent e)
307   {
308     if (selectedButtons == null)
309     {
310       selectedButtons = new ArrayList<JButton>();
311     }
312
313     JButton pressed = (JButton) e.getSource();
314
315     if (e.isShiftDown())
316     {
317       JButton start, end = (JButton) e.getSource();
318       if (selectedButtons.size() > 0)
319       {
320         start = selectedButtons.get(selectedButtons.size() - 1);
321       }
322       else
323       {
324         start = (JButton) e.getSource();
325       }
326
327       int startIndex = 0, endIndex = 0;
328       for (int b = 0; b < buttonPanel.getComponentCount(); b++)
329       {
330         if (buttonPanel.getComponent(b) == start)
331         {
332           startIndex = b;
333         }
334         if (buttonPanel.getComponent(b) == end)
335         {
336           endIndex = b;
337         }
338       }
339
340       if (startIndex > endIndex)
341       {
342         int temp = startIndex;
343         startIndex = endIndex;
344         endIndex = temp;
345       }
346
347       for (int b = startIndex; b <= endIndex; b++)
348       {
349         JButton button = (JButton) buttonPanel.getComponent(b);
350         if (!selectedButtons.contains(button))
351         {
352           button.setForeground(ColorUtils.brighterThan(button
353                   .getBackground()));
354           selectedButtons.add(button);
355         }
356       }
357     }
358     else if (!e.isControlDown())
359     {
360       for (int b = 0; b < selectedButtons.size(); b++)
361       {
362         JButton button = selectedButtons.get(b);
363         button.setForeground(ColorUtils.darkerThan(button.getBackground()));
364       }
365       selectedButtons.clear();
366       pressed.setForeground(ColorUtils.brighterThan(pressed.getBackground()));
367       selectedButtons.add(pressed);
368
369     }
370     else if (e.isControlDown())
371     {
372       if (selectedButtons.contains(pressed))
373       {
374         pressed.setForeground(ColorUtils.darkerThan(pressed.getBackground()));
375         selectedButtons.remove(pressed);
376       }
377       else
378       {
379         pressed.setForeground(ColorUtils.brighterThan(pressed
380                 .getBackground()));
381         selectedButtons.add(pressed);
382       }
383     }
384
385     if (selectedButtons.size() > 0)
386     {
387       colorChooser.setColor((selectedButtons.get(0)).getBackground());
388     }
389   }
390
391   /**
392    * A helper method to update or make a colour button, whose background colour
393    * is the associated colour, and text colour a darker shade of the same. If
394    * the button is already in the list, then its text and margins are updated,
395    * if not then it is created and added. This method supports toggling between
396    * case-sensitive and case-insensitive button panels. The case-sensitive
397    * version has abbreviated button text in order to fit in more buttons.
398    * 
399    * @param label
400    * @param residue
401    * @param the
402    *          list of buttons
403    * @param buttonIndex
404    *          the button's position in the list
405    */
406   JButton makeButton(String label, String residue,
407           List<JButton> buttons, int buttonIndex)
408   {
409     final JButton button;
410     Color col;
411
412     if (buttonIndex < buttons.size())
413     {
414       button = buttons.get(buttonIndex);
415       col = button.getBackground();
416     }
417     else
418     {
419       button = new JButton();
420       button.addMouseListener(new MouseAdapter()
421       {
422         @Override
423         public void mouseClicked(MouseEvent e)
424         {
425           colourButtonPressed(e);
426         }
427       });
428
429       buttons.add(button);
430
431       /*
432        * make initial button colour that of the current colour scheme,
433        * if it is a simple per-residue colouring, else white
434        */
435       col = Color.white;
436       if (oldColourScheme != null && oldColourScheme.isSimple())
437       {
438         col = oldColourScheme.findColour(residue.charAt(0), 0, null, null,
439                 0f);
440       }
441     }
442
443     if (caseSensitive.isSelected())
444     {
445       button.setMargin(new Insets(2, 2, 2, 2));
446     }
447     else
448     {
449       button.setMargin(new Insets(2, 14, 2, 14));
450     }
451
452     button.setOpaque(true); // required for the next line to have effect
453     button.setBackground(col);
454     button.setText(label);
455     button.setForeground(ColorUtils.darkerThan(col));
456     button.setFont(VERDANA_BOLD_10);
457
458     return button;
459   }
460
461   /**
462    * On 'OK', check that at least one colour has been assigned to a residue (and
463    * if not issue a warning), and apply the chosen colour scheme and close the
464    * panel.
465    */
466   @Override
467   protected void okButton_actionPerformed()
468   {
469     if (isNoSelectionMade())
470     {
471       JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
472               .getString("label.no_colour_selection_in_scheme"),
473               MessageManager.getString("label.no_colour_selection_warn"),
474               JvOptionPane.WARNING_MESSAGE);
475     }
476     else
477     {
478       applyButton_actionPerformed();
479
480       try
481       {
482         frame.setClosed(true);
483       } catch (Exception ex)
484       {
485       }
486     }
487   }
488
489   /**
490    * Returns true if the user has not made any colour selection (including if
491    * 'case-sensitive' selected and no lower-case colour chosen).
492    * 
493    * @return
494    */
495   protected boolean isNoSelectionMade()
496   {
497     final boolean noUpperCaseSelected = upperCaseButtons == null
498             || upperCaseButtons.isEmpty();
499     final boolean noLowerCaseSelected = caseSensitive.isSelected()
500             && (lowerCaseButtons == null || lowerCaseButtons.isEmpty());
501     final boolean noSelectionMade = noUpperCaseSelected
502             || noLowerCaseSelected;
503     return noSelectionMade;
504   }
505
506   /**
507    * Applies the current colour scheme to the alignment, sequence group or
508    * structure view.
509    */
510   @Override
511   protected void applyButton_actionPerformed()
512   {
513     if (isNoSelectionMade())
514     {
515       JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
516               .getString("label.no_colour_selection_in_scheme"),
517               MessageManager.getString("label.no_colour_selection_warn"),
518               JvOptionPane.WARNING_MESSAGE);
519
520     }
521     UserColourScheme ucs = getSchemeFromButtons();
522
523     if (seqGroup != null)
524     {
525       seqGroup.setColourScheme(ucs);
526       ap.paintAlignment(true);
527     }
528     else if (ap != null)
529     {
530       ap.alignFrame.changeColour(ucs);
531     }
532     else if (structureViewer != null)
533     {
534       structureViewer.setJalviewColourScheme(ucs);
535     }
536   }
537
538   UserColourScheme getSchemeFromButtons()
539   {
540
541     Color[] newColours = new Color[24];
542
543     int length = upperCaseButtons.size();
544     if (length < 24)
545     {
546       int i = 0;
547       for (JButton btn : upperCaseButtons)
548       {
549         newColours[i] = btn.getBackground();
550         i++;
551       }
552     }
553     else
554     {
555       for (int i = 0; i < 24; i++)
556       {
557         JButton button = upperCaseButtons.get(i);
558         newColours[i] = button.getBackground();
559       }
560     }
561
562     UserColourScheme ucs = new UserColourScheme(newColours);
563     ucs.setName(schemeName.getText());
564
565     if (caseSensitive.isSelected())
566     {
567       newColours = new Color[23];
568       length = lowerCaseButtons.size();
569       if (length < 23)
570       {
571         int i = 0;
572         for (JButton btn : lowerCaseButtons)
573         {
574           newColours[i] = btn.getBackground();
575           i++;
576         }
577       }
578       else
579       {
580         for (int i = 0; i < 23; i++)
581         {
582           JButton button = lowerCaseButtons.get(i);
583           newColours[i] = button.getBackground();
584         }
585       }
586       ucs.setLowerCaseColours(newColours);
587     }
588
589     // if (ap != null)
590     // {
591     // ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
592     // }
593
594     return ucs;
595   }
596
597   /**
598    * DOCUMENT ME!
599    * 
600    * @param e
601    *          DOCUMENT ME!
602    */
603   @Override
604   protected void loadbutton_actionPerformed(ActionEvent e)
605   {
606     upperCaseButtons = new ArrayList<JButton>();
607     lowerCaseButtons = new ArrayList<JButton>();
608
609     JalviewFileChooser chooser = new JalviewFileChooser(
610             Cache.getProperty(LAST_DIRECTORY), "jc", "Jalview User Colours");
611     chooser.setFileView(new JalviewFileView());
612     chooser.setDialogTitle(MessageManager
613             .getString("label.load_colour_scheme"));
614     chooser.setToolTipText(MessageManager.getString("action.load"));
615
616     int value = chooser.showOpenDialog(this);
617
618     if (value != JalviewFileChooser.APPROVE_OPTION)
619     {
620       return;
621     }
622     File choice = chooser.getSelectedFile();
623     Cache.setProperty(LAST_DIRECTORY, choice.getParent());
624
625     UserColourScheme ucs = ColourSchemes.loadColourScheme(choice.getAbsolutePath());
626     Color[] colors = ucs.getColours();
627     schemeName.setText(ucs.getSchemeName());
628
629     if (ucs.getLowerCaseColours() != null)
630     {
631       caseSensitive.setSelected(true);
632       lcaseColour.setEnabled(true);
633       resetButtonPanel(true);
634       for (int i = 0; i < lowerCaseButtons.size(); i++)
635       {
636         JButton button = lowerCaseButtons.get(i);
637         button.setBackground(ucs.getLowerCaseColours()[i]);
638       }
639     }
640     else
641     {
642       caseSensitive.setSelected(false);
643       lcaseColour.setEnabled(false);
644       resetButtonPanel(false);
645     }
646
647     for (int i = 0; i < upperCaseButtons.size(); i++)
648     {
649       JButton button = upperCaseButtons.get(i);
650       button.setBackground(colors[i]);
651     }
652
653     addNewColourScheme(choice.getPath());
654   }
655
656   /**
657    * Loads the user-defined colour scheme from the first file listed in property
658    * "USER_DEFINED_COLOURS". If this fails, returns an all-white colour scheme.
659    * 
660    * @return
661    */
662   public static UserColourScheme loadDefaultColours()
663   {
664     UserColourScheme ret = null;
665
666     String colours = Cache.getProperty(USER_DEFINED_COLOURS);
667     if (colours != null)
668     {
669       if (colours.indexOf("|") > -1)
670       {
671         colours = colours.substring(0, colours.indexOf("|"));
672       }
673       ret = ColourSchemes.loadColourScheme(colours);
674     }
675
676     if (ret == null)
677     {
678       ret = new UserColourScheme("white");
679     }
680
681     return ret;
682   }
683
684   /**
685    * DOCUMENT ME!
686    * 
687    * @param e
688    *          DOCUMENT ME!
689    */
690   @Override
691   protected void savebutton_actionPerformed(ActionEvent e)
692   {
693     String name = schemeName.getText().trim();
694     if (name.length() < 1)
695     {
696       JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
697               .getString("label.user_colour_scheme_must_have_name"),
698               MessageManager.getString("label.no_name_colour_scheme"),
699               JvOptionPane.WARNING_MESSAGE);
700       return;
701     }
702
703     if (ColourSchemes.getInstance().nameExists(name))
704     {
705       int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
706               MessageManager.formatMessage(
707                       "label.colour_scheme_exists_overwrite", new Object[] {
708                           name, name }),
709               MessageManager.getString("label.duplicate_scheme_name"),
710               JvOptionPane.YES_NO_OPTION);
711       if (reply != JvOptionPane.YES_OPTION)
712       {
713         return;
714       }
715       ColourSchemes.getInstance().removeColourScheme(name);
716     }
717     JalviewFileChooser chooser = new JalviewFileChooser(
718             Cache.getProperty(LAST_DIRECTORY), "jc",
719             "Jalview User Colours");
720
721     JalviewFileView fileView = new JalviewFileView();
722     chooser.setFileView(fileView);
723     chooser.setDialogTitle(MessageManager
724             .getString("label.save_colour_scheme"));
725     chooser.setToolTipText(MessageManager.getString("action.save"));
726
727     int value = chooser.showSaveDialog(this);
728
729     if (value == JalviewFileChooser.APPROVE_OPTION)
730     {
731       File file = chooser.getSelectedFile();
732       addNewColourScheme(file.getPath());
733       saveToFile(file);
734     }
735   }
736
737   /**
738    * Adds the current colour scheme to the Jalview properties file so it is
739    * loaded on next startup, and updates the Colour menu in the parent
740    * AlignFrame (if there is one). Note this action does not including applying
741    * the colour scheme.
742    * 
743    * @param filePath
744    */
745   protected void addNewColourScheme(String filePath)
746   {
747     /*
748      * update the delimited list of user defined colour files in
749      * Jalview property USER_DEFINED_COLOURS
750      */
751     String defaultColours = Cache
752             .getDefault(USER_DEFINED_COLOURS, filePath);
753     if (defaultColours.indexOf(filePath) == -1)
754     {
755       if (defaultColours.length() > 0)
756       {
757         defaultColours = defaultColours.concat("|");
758       }
759       defaultColours = defaultColours.concat(filePath);
760     }
761     Cache.setProperty(USER_DEFINED_COLOURS, defaultColours);
762
763     /*
764      * construct and register the colour scheme
765      */
766     UserColourScheme ucs = getSchemeFromButtons();
767     ColourSchemes.getInstance().registerColourScheme(ucs);
768
769     /*
770      * update the Colour menu items
771      */
772     if (ap != null)
773     {
774       ap.alignFrame.buildColourMenu();
775     }
776   }
777
778   /**
779    * Saves the colour scheme to file in XML format
780    * 
781    * @param path
782    */
783   protected void saveToFile(File toFile)
784   {
785     /*
786      * build a Java model of colour scheme as XML, and 
787      * marshal to file
788      */
789     JalviewUserColours ucs = new JalviewUserColours();
790     ucs.setSchemeName(schemeName.getText());
791     try
792     {
793       PrintWriter out = new PrintWriter(new OutputStreamWriter(
794               new FileOutputStream(toFile), "UTF-8"));
795
796       for (int i = 0; i < buttonPanel.getComponentCount(); i++)
797       {
798         JButton button = (JButton) buttonPanel.getComponent(i);
799         Colour col = new Colour();
800         col.setName(button.getText());
801         col.setRGB(Format.getHexString(button.getBackground()));
802         ucs.addColour(col);
803       }
804       ucs.marshal(out);
805       out.close();
806     } catch (Exception ex)
807     {
808       ex.printStackTrace();
809     }
810   }
811
812   /**
813    * On cancel, restores the colour scheme before the dialogue was opened
814    * 
815    * @param e
816    */
817   @Override
818   protected void cancelButton_actionPerformed(ActionEvent e)
819   {
820     if (ap != null)
821     {
822       if (seqGroup != null)
823       {
824         seqGroup.setColourScheme(oldColourScheme);
825       }
826       else
827       {
828         ap.alignFrame.changeColour(oldColourScheme);
829       }
830       ap.paintAlignment(true);
831     }
832
833     if (structureViewer != null)
834     {
835       structureViewer.setJalviewColourScheme(oldColourScheme);
836     }
837
838     try
839     {
840       frame.setClosed(true);
841     } catch (Exception ex)
842     {
843     }
844   }
845
846   @Override
847   public void caseSensitive_actionPerformed(ActionEvent e)
848   {
849     resetButtonPanel(caseSensitive.isSelected());
850     lcaseColour.setEnabled(caseSensitive.isSelected());
851   }
852
853   @Override
854   public void lcaseColour_actionPerformed(ActionEvent e)
855   {
856     if (selectedButtons == null)
857     {
858       selectedButtons = new ArrayList<JButton>();
859     }
860     else
861     {
862       selectedButtons.clear();
863     }
864     selectedButtons.add(lcaseColour);
865   }
866 }