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