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