JAL-2344 handle null format, simplify JalviewFileChooser constructor
[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.schemes.ColourSchemeI;
30 import jalview.schemes.ResidueProperties;
31 import jalview.schemes.UserColourScheme;
32 import jalview.util.ColorUtils;
33 import jalview.util.MessageManager;
34
35 import java.awt.Color;
36 import java.awt.Font;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.MouseEvent;
39 import java.io.File;
40 import java.io.FileInputStream;
41 import java.io.FileOutputStream;
42 import java.io.InputStreamReader;
43 import java.io.OutputStreamWriter;
44 import java.io.PrintWriter;
45 import java.util.ArrayList;
46 import java.util.Hashtable;
47 import java.util.StringTokenizer;
48
49 import javax.swing.JButton;
50 import javax.swing.JInternalFrame;
51 import javax.swing.event.ChangeEvent;
52 import javax.swing.event.ChangeListener;
53
54 /**
55  * This panel allows the user to assign colours to Amino Acid residue codes, and
56  * save the colour scheme.
57  * 
58  * @author Andrew Waterhouse
59  * @author Mungo Carstairs
60  */
61 public class UserDefinedColours extends GUserDefinedColours implements
62         ChangeListener
63 {
64   private static final int MY_FRAME_HEIGHT = 420;
65
66   private static final int MY_FRAME_WIDTH = 810;
67
68   private static final int MY_FRAME_WIDTH_CASE_SENSITIVE = 970;
69
70   AlignmentPanel ap;
71
72   SequenceGroup seqGroup;
73
74   ArrayList<JButton> selectedButtons;
75
76   ColourSchemeI oldColourScheme;
77
78   JInternalFrame frame;
79
80   JalviewStructureDisplayI jmol;
81
82   ArrayList<JButton> upperCaseButtons;
83
84   ArrayList<JButton> lowerCaseButtons;
85
86   /**
87    * Creates a new UserDefinedColours object.
88    * 
89    * @param ap
90    *          DOCUMENT ME!
91    * @param sg
92    *          DOCUMENT ME!
93    */
94   public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
95   {
96     super();
97
98     lcaseColour.setEnabled(false);
99
100     this.ap = ap;
101     seqGroup = sg;
102
103     if (seqGroup != null)
104     {
105       oldColourScheme = seqGroup.cs;
106     }
107     else
108     {
109       oldColourScheme = ap.av.getGlobalColourScheme();
110     }
111
112     if (oldColourScheme instanceof UserColourScheme)
113     {
114       schemeName.setText(((UserColourScheme) oldColourScheme).getName());
115       if (((UserColourScheme) oldColourScheme).getLowerCaseColours() != null)
116       {
117         caseSensitive.setSelected(true);
118         lcaseColour.setEnabled(true);
119         resetButtonPanel(true);
120       }
121       else
122       {
123         resetButtonPanel(false);
124       }
125     }
126     else
127     {
128       resetButtonPanel(false);
129     }
130
131     showFrame();
132   }
133
134   public UserDefinedColours(JalviewStructureDisplayI jmol,
135           ColourSchemeI oldcs)
136   {
137     super();
138     this.jmol = jmol;
139
140     colorChooser.getSelectionModel().addChangeListener(this);
141
142     oldColourScheme = oldcs;
143
144     if (oldColourScheme instanceof UserColourScheme)
145     {
146       schemeName.setText(((UserColourScheme) oldColourScheme).getName());
147     }
148
149     resetButtonPanel(false);
150
151     showFrame();
152
153   }
154
155   void showFrame()
156   {
157     colorChooser.getSelectionModel().addChangeListener(this);
158     frame = new JInternalFrame();
159     frame.setContentPane(this);
160     Desktop.addInternalFrame(frame,
161             MessageManager.getString("label.user_defined_colours"),
162             MY_FRAME_WIDTH, MY_FRAME_HEIGHT, true);
163
164     if (seqGroup != null)
165     {
166       frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
167     }
168   }
169
170   void resetButtonPanel(boolean caseSensitive)
171   {
172     buttonPanel.removeAll();
173
174     if (upperCaseButtons == null)
175     {
176       upperCaseButtons = new ArrayList<JButton>();
177     }
178
179     JButton button;
180     String label;
181     for (int i = 0; i < 20; i++)
182     {
183       if (caseSensitive)
184       {
185         label = ResidueProperties.aa[i];
186       }
187       else
188       {
189         label = ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
190                 .toString();
191       }
192
193       button = makeButton(label, ResidueProperties.aa[i], upperCaseButtons,
194               i);
195
196       buttonPanel.add(button);
197     }
198
199     buttonPanel.add(makeButton("B", "B", upperCaseButtons, 20));
200     buttonPanel.add(makeButton("Z", "Z", upperCaseButtons, 21));
201     buttonPanel.add(makeButton("X", "X", upperCaseButtons, 22));
202     buttonPanel.add(makeButton("Gap", "-", upperCaseButtons, 23));
203
204     if (!caseSensitive)
205     {
206       gridLayout.setRows(6);
207       gridLayout.setColumns(4);
208     }
209     else
210     {
211       gridLayout.setRows(7);
212       int cols = 7;
213       gridLayout.setColumns(cols + 1);
214
215       if (lowerCaseButtons == null)
216       {
217         lowerCaseButtons = new ArrayList<JButton>();
218       }
219
220       for (int i = 0; i < 20; i++)
221       {
222         int row = i / cols + 1;
223         int index = (row * cols) + i;
224         button = makeButton(ResidueProperties.aa[i].toLowerCase(),
225                 ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
226
227         buttonPanel.add(button, index);
228       }
229     }
230
231     if (caseSensitive)
232     {
233       buttonPanel.add(makeButton("b", "b", lowerCaseButtons, 20));
234       buttonPanel.add(makeButton("z", "z", lowerCaseButtons, 21));
235       buttonPanel.add(makeButton("x", "x", lowerCaseButtons, 22));
236     }
237
238     // JAL-1360 widen the frame dynamically to accommodate case-sensitive AA
239     // codes
240     if (this.frame != null)
241     {
242       int newWidth = caseSensitive ? MY_FRAME_WIDTH_CASE_SENSITIVE
243               : MY_FRAME_WIDTH;
244       this.frame.setSize(newWidth, this.frame.getHeight());
245     }
246
247     buttonPanel.validate();
248     validate();
249   }
250
251   /**
252    * DOCUMENT ME!
253    * 
254    * @param evt
255    *          DOCUMENT ME!
256    */
257   @Override
258   public void stateChanged(ChangeEvent evt)
259   {
260     if (selectedButtons != null)
261     {
262       JButton button = null;
263       final Color newColour = colorChooser.getColor();
264       for (int i = 0; i < selectedButtons.size(); i++)
265       {
266         button = selectedButtons.get(i);
267         button.setBackground(newColour);
268         button.setForeground(ColorUtils.brighterThan(newColour));
269       }
270       if (button == lcaseColour)
271       {
272         for (int i = 0; i < lowerCaseButtons.size(); i++)
273         {
274           button = lowerCaseButtons.get(i);
275           button.setBackground(newColour);
276           button.setForeground(ColorUtils.brighterThan(button
277                   .getBackground()));
278         }
279       }
280     }
281   }
282
283   /**
284    * Performs actions when a residue button is clicked. This manages the button
285    * selection set (highlighted by brighter foreground text).
286    * <p>
287    * On select button(s) with Ctrl/click or Shift/click: set button foreground
288    * text to brighter than background.
289    * <p>
290    * On unselect button(s) with Ctrl/click on selected, or click to release
291    * current selection: reset foreground text to darker than background.
292    * <p>
293    * Simple click: clear selection (resetting foreground to darker); set clicked
294    * button foreground to brighter
295    * <p>
296    * Finally, synchronize the colour chooser to the colour of the first button
297    * in the selected set.
298    * 
299    * @param e
300    */
301   public void colourButtonPressed(MouseEvent e)
302   {
303     if (selectedButtons == null)
304     {
305       selectedButtons = new ArrayList<JButton>();
306     }
307
308     JButton pressed = (JButton) e.getSource();
309
310     if (e.isShiftDown())
311     {
312       JButton start, end = (JButton) e.getSource();
313       if (selectedButtons.size() > 0)
314       {
315         start = selectedButtons.get(selectedButtons.size() - 1);
316       }
317       else
318       {
319         start = (JButton) e.getSource();
320       }
321
322       int startIndex = 0, endIndex = 0;
323       for (int b = 0; b < buttonPanel.getComponentCount(); b++)
324       {
325         if (buttonPanel.getComponent(b) == start)
326         {
327           startIndex = b;
328         }
329         if (buttonPanel.getComponent(b) == end)
330         {
331           endIndex = b;
332         }
333       }
334
335       if (startIndex > endIndex)
336       {
337         int temp = startIndex;
338         startIndex = endIndex;
339         endIndex = temp;
340       }
341
342       for (int b = startIndex; b <= endIndex; b++)
343       {
344         JButton button = (JButton) buttonPanel.getComponent(b);
345         if (!selectedButtons.contains(button))
346         {
347           button.setForeground(ColorUtils.brighterThan(button
348                   .getBackground()));
349           selectedButtons.add(button);
350         }
351       }
352     }
353     else if (!e.isControlDown())
354     {
355       for (int b = 0; b < selectedButtons.size(); b++)
356       {
357         JButton button = selectedButtons.get(b);
358         button.setForeground(ColorUtils.darkerThan(button.getBackground()));
359       }
360       selectedButtons.clear();
361       pressed.setForeground(ColorUtils.brighterThan(pressed.getBackground()));
362       selectedButtons.add(pressed);
363
364     }
365     else if (e.isControlDown())
366     {
367       if (selectedButtons.contains(pressed))
368       {
369         pressed.setForeground(ColorUtils.darkerThan(pressed.getBackground()));
370         selectedButtons.remove(pressed);
371       }
372       else
373       {
374         pressed.setForeground(ColorUtils.brighterThan(pressed
375                 .getBackground()));
376         selectedButtons.add(pressed);
377       }
378     }
379
380     if (selectedButtons.size() > 0)
381     {
382       colorChooser.setColor((selectedButtons.get(0)).getBackground());
383     }
384   }
385
386   /**
387    * DOCUMENT ME!
388    * 
389    * @param label
390    *          DOCUMENT ME!
391    * @param aa
392    *          DOCUMENT ME!
393    */
394   JButton makeButton(String label, String aa,
395           ArrayList<JButton> caseSensitiveButtons, int buttonIndex)
396   {
397     final JButton button;
398     Color col;
399
400     if (buttonIndex < caseSensitiveButtons.size())
401     {
402       button = caseSensitiveButtons.get(buttonIndex);
403       col = button.getBackground();
404     }
405     else
406     {
407       button = new JButton();
408       button.addMouseListener(new java.awt.event.MouseAdapter()
409       {
410         @Override
411         public void mouseClicked(MouseEvent e)
412         {
413           colourButtonPressed(e);
414         }
415       });
416
417       caseSensitiveButtons.add(button);
418
419       col = Color.white;
420       if (oldColourScheme != null)
421       {
422         try
423         {
424           col = oldColourScheme.findColour(aa.charAt(0), -1, null);
425         } catch (Exception ex)
426         {
427         }
428       }
429     }
430
431     if (caseSensitive.isSelected())
432     {
433       button.setMargin(new java.awt.Insets(2, 2, 2, 2));
434     }
435     else
436     {
437       button.setMargin(new java.awt.Insets(2, 14, 2, 14));
438     }
439
440     button.setOpaque(true); // required for the next line to have effect
441     button.setBackground(col);
442     button.setText(label);
443     button.setForeground(ColorUtils.darkerThan(col));
444     button.setFont(new java.awt.Font("Verdana", Font.BOLD, 10));
445
446     return button;
447   }
448
449   /**
450    * DOCUMENT ME!
451    * 
452    * @param e
453    *          DOCUMENT ME!
454    */
455   @Override
456   protected void okButton_actionPerformed(ActionEvent e)
457   {
458     if (isNoSelectionMade())
459     {
460       JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
461               .getString("label.no_colour_selection_in_scheme"),
462               MessageManager.getString("label.no_colour_selection_warn"),
463               JvOptionPane.WARNING_MESSAGE);
464     }
465     else
466     {
467       applyButton_actionPerformed(null);
468
469       try
470       {
471         frame.setClosed(true);
472       } catch (Exception ex)
473       {
474       }
475     }
476   }
477
478   /**
479    * Returns true if the user has not made any colour selection (including if
480    * 'case-sensitive' selected and no lower-case colour chosen).
481    * 
482    * @return
483    */
484   protected boolean isNoSelectionMade()
485   {
486     final boolean noUpperCaseSelected = upperCaseButtons == null
487             || upperCaseButtons.isEmpty();
488     final boolean noLowerCaseSelected = caseSensitive.isSelected()
489             && (lowerCaseButtons == null || lowerCaseButtons.isEmpty());
490     final boolean noSelectionMade = noUpperCaseSelected
491             || noLowerCaseSelected;
492     return noSelectionMade;
493   }
494
495   /**
496    * DOCUMENT ME!
497    * 
498    * @param e
499    *          DOCUMENT ME!
500    */
501   @Override
502   protected void applyButton_actionPerformed(ActionEvent e)
503   {
504     if (isNoSelectionMade())
505     {
506       JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
507               .getString("label.no_colour_selection_in_scheme"),
508               MessageManager.getString("label.no_colour_selection_warn"),
509               JvOptionPane.WARNING_MESSAGE);
510
511     }
512     UserColourScheme ucs = getSchemeFromButtons();
513     ucs.setName(schemeName.getText());
514
515     if (seqGroup != null)
516     {
517       seqGroup.cs = ucs;
518       ap.paintAlignment(true);
519     }
520     else if (ap != null)
521     {
522       ap.alignFrame.changeColour(ucs);
523     }
524     else if (jmol != null)
525     {
526       jmol.setJalviewColourScheme(ucs);
527     }
528   }
529
530   UserColourScheme getSchemeFromButtons()
531   {
532
533     Color[] newColours = new Color[24];
534
535     int length = upperCaseButtons.size();
536     if (length < 24)
537     {
538       int i = 0;
539       for (JButton btn : upperCaseButtons)
540       {
541         newColours[i] = btn.getBackground();
542         i++;
543       }
544     }
545     else
546     {
547       for (int i = 0; i < 24; i++)
548       {
549         JButton button = upperCaseButtons.get(i);
550         newColours[i] = button.getBackground();
551       }
552     }
553
554     UserColourScheme ucs = new UserColourScheme(newColours);
555
556     if (caseSensitive.isSelected())
557     {
558       newColours = new Color[23];
559       length = lowerCaseButtons.size();
560       if (length < 23)
561       {
562         int i = 0;
563         for (JButton btn : lowerCaseButtons)
564         {
565           newColours[i] = btn.getBackground();
566           i++;
567         }
568       }
569       else
570       {
571         for (int i = 0; i < 23; i++)
572         {
573           JButton button = lowerCaseButtons.get(i);
574           newColours[i] = button.getBackground();
575         }
576       }
577       ucs.setLowerCaseColours(newColours);
578     }
579
580     if (ap != null)
581     {
582       ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
583     }
584
585     return ucs;
586   }
587
588   /**
589    * DOCUMENT ME!
590    * 
591    * @param e
592    *          DOCUMENT ME!
593    */
594   @Override
595   protected void loadbutton_actionPerformed(ActionEvent e)
596   {
597     upperCaseButtons = new ArrayList<JButton>();
598     lowerCaseButtons = new ArrayList<JButton>();
599
600     JalviewFileChooser chooser = new JalviewFileChooser(
601             Cache.getProperty("LAST_DIRECTORY"), "jc",
602             "Jalview User Colours");
603     chooser.setFileView(new JalviewFileView());
604     chooser.setDialogTitle(MessageManager
605             .getString("label.load_colour_scheme"));
606     chooser.setToolTipText(MessageManager.getString("action.load"));
607
608     int value = chooser.showOpenDialog(this);
609
610     if (value == JalviewFileChooser.APPROVE_OPTION)
611     {
612       File choice = chooser.getSelectedFile();
613       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
614       String defaultColours = jalview.bin.Cache.getDefault(
615               "USER_DEFINED_COLOURS", choice.getPath());
616       if (defaultColours.indexOf(choice.getPath()) == -1)
617       {
618         defaultColours = defaultColours.concat("|")
619                 .concat(choice.getPath());
620       }
621
622       jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS", defaultColours);
623
624       UserColourScheme ucs = loadColours(choice.getAbsolutePath());
625       Color[] colors = ucs.getColours();
626       schemeName.setText(ucs.getName());
627
628       if (ucs.getLowerCaseColours() != null)
629       {
630         caseSensitive.setSelected(true);
631         lcaseColour.setEnabled(true);
632         resetButtonPanel(true);
633         for (int i = 0; i < lowerCaseButtons.size(); i++)
634         {
635           JButton button = lowerCaseButtons.get(i);
636           button.setBackground(ucs.getLowerCaseColours()[i]);
637         }
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     }
654   }
655
656   /**
657    * DOCUMENT ME!
658    * 
659    * @return DOCUMENT ME!
660    */
661   public static UserColourScheme loadDefaultColours()
662   {
663     UserColourScheme ret = null;
664
665     String colours = jalview.bin.Cache.getProperty("USER_DEFINED_COLOURS");
666     if (colours != null)
667     {
668       if (colours.indexOf("|") > -1)
669       {
670         colours = colours.substring(0, colours.indexOf("|"));
671       }
672
673       ret = loadColours(colours);
674     }
675
676     if (ret == null)
677     {
678       Color[] newColours = new Color[24];
679       for (int i = 0; i < 24; i++)
680       {
681         newColours[i] = Color.white;
682       }
683       ret = new UserColourScheme(newColours);
684     }
685
686     return ret;
687   }
688
689   /**
690    * DOCUMENT ME!
691    * 
692    * @param file
693    *          DOCUMENT ME!
694    * 
695    * @return DOCUMENT ME!
696    */
697   static UserColourScheme loadColours(String file)
698   {
699     UserColourScheme ucs = null;
700     Color[] newColours = null;
701     try
702     {
703       InputStreamReader in = new InputStreamReader(
704               new FileInputStream(file), "UTF-8");
705
706       jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
707
708       org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
709               jucs);
710       jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
711               .unmarshal(in);
712
713       newColours = new Color[24];
714
715       Color[] lowerCase = null;
716       boolean caseSensitive = false;
717
718       String name;
719       int index;
720       for (int i = 0; i < jucs.getColourCount(); i++)
721       {
722         name = jucs.getColour(i).getName();
723         if (ResidueProperties.aa3Hash.containsKey(name))
724         {
725           index = ResidueProperties.aa3Hash.get(name).intValue();
726         }
727         else
728         {
729           index = ResidueProperties.aaIndex[name.charAt(0)];
730         }
731         if (index == -1)
732         {
733           continue;
734         }
735
736         if (name.toLowerCase().equals(name))
737         {
738           if (lowerCase == null)
739           {
740             lowerCase = new Color[23];
741           }
742           caseSensitive = true;
743           lowerCase[index] = new Color(Integer.parseInt(jucs.getColour(i)
744                   .getRGB(), 16));
745         }
746         else
747         {
748           newColours[index] = new Color(Integer.parseInt(jucs.getColour(i)
749                   .getRGB(), 16));
750         }
751       }
752
753       if (newColours != null)
754       {
755         ucs = new UserColourScheme(newColours);
756         ucs.setName(jucs.getSchemeName());
757         if (caseSensitive)
758         {
759           ucs.setLowerCaseColours(lowerCase);
760         }
761       }
762
763     } catch (Exception ex)
764     {
765       // Could be Archive Jalview format
766       try
767       {
768         InputStreamReader in = new InputStreamReader(new FileInputStream(
769                 file), "UTF-8");
770
771         jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
772
773         jucs = jucs.unmarshal(in);
774
775         newColours = new Color[jucs.getColourCount()];
776
777         for (int i = 0; i < 24; i++)
778         {
779           newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
780                   .getRGB(), 16));
781         }
782         if (newColours != null)
783         {
784           ucs = new UserColourScheme(newColours);
785           ucs.setName(jucs.getSchemeName());
786         }
787       } catch (Exception ex2)
788       {
789         ex2.printStackTrace();
790       }
791
792       if (newColours == null)
793       {
794         System.out.println("Error loading User ColourFile\n" + ex);
795       }
796     }
797
798     return ucs;
799   }
800
801   /**
802    * DOCUMENT ME!
803    * 
804    * @param e
805    *          DOCUMENT ME!
806    */
807   @Override
808   protected void savebutton_actionPerformed(ActionEvent e)
809   {
810     if (schemeName.getText().trim().length() < 1)
811     {
812       JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
813               .getString("label.user_colour_scheme_must_have_name"),
814               MessageManager.getString("label.no_name_colour_scheme"),
815               JvOptionPane.WARNING_MESSAGE);
816       return;
817     }
818
819     if (userColourSchemes != null
820             && userColourSchemes.containsKey(schemeName.getText()))
821     {
822       int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
823               MessageManager.formatMessage(
824                       "label.colour_scheme_exists_overwrite", new Object[] {
825                           schemeName.getText(), schemeName.getText() }),
826               MessageManager.getString("label.duplicate_scheme_name"),
827               JvOptionPane.YES_NO_OPTION);
828       if (reply != JvOptionPane.YES_OPTION)
829       {
830         return;
831       }
832
833       userColourSchemes.remove(schemeName.getText());
834     }
835     JalviewFileChooser chooser = new JalviewFileChooser(
836             Cache.getProperty("LAST_DIRECTORY"), "jc",
837             "Jalview User Colours");
838
839     chooser.setFileView(new JalviewFileView());
840     chooser.setDialogTitle(MessageManager
841             .getString("label.save_colour_scheme"));
842     chooser.setToolTipText(MessageManager.getString("action.save"));
843
844     int value = chooser.showSaveDialog(this);
845
846     if (value == JalviewFileChooser.APPROVE_OPTION)
847     {
848       String choice = chooser.getSelectedFile().getPath();
849       String defaultColours = jalview.bin.Cache.getDefault(
850               "USER_DEFINED_COLOURS", choice);
851       if (defaultColours.indexOf(choice) == -1)
852       {
853         if (defaultColours.length() > 0)
854         {
855           defaultColours = defaultColours.concat("|");
856         }
857         defaultColours = defaultColours.concat(choice);
858       }
859
860       userColourSchemes.put(schemeName.getText(), getSchemeFromButtons());
861
862       ap.alignFrame.updateUserColourMenu();
863
864       jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS", defaultColours);
865
866       jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
867
868       ucs.setSchemeName(schemeName.getText());
869       try
870       {
871         PrintWriter out = new PrintWriter(new OutputStreamWriter(
872                 new FileOutputStream(choice), "UTF-8"));
873
874         for (int i = 0; i < buttonPanel.getComponentCount(); i++)
875         {
876           JButton button = (JButton) buttonPanel.getComponent(i);
877           jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
878           col.setName(button.getText());
879           col.setRGB(jalview.util.Format.getHexString(button
880                   .getBackground()));
881           ucs.addColour(col);
882         }
883
884         ucs.marshal(out);
885         out.close();
886       } catch (Exception ex)
887       {
888         ex.printStackTrace();
889       }
890     }
891   }
892
893   /**
894    * DOCUMENT ME!
895    * 
896    * @param e
897    *          DOCUMENT ME!
898    */
899   @Override
900   protected void cancelButton_actionPerformed(ActionEvent e)
901   {
902     if (ap != null)
903     {
904       if (seqGroup != null)
905       {
906         seqGroup.cs = oldColourScheme;
907       }
908       else if (ap != null)
909       {
910         ap.av.setGlobalColourScheme(oldColourScheme);
911       }
912       ap.paintAlignment(true);
913     }
914
915     if (jmol != null)
916     {
917       jmol.setJalviewColourScheme(oldColourScheme);
918     }
919
920     try
921     {
922       frame.setClosed(true);
923     } catch (Exception ex)
924     {
925     }
926   }
927
928   static Hashtable userColourSchemes;
929
930   public static Hashtable getUserColourSchemes()
931   {
932     return userColourSchemes;
933   }
934
935   public static void initUserColourSchemes(String files)
936   {
937     userColourSchemes = new Hashtable();
938
939     if (files == null || files.length() == 0)
940     {
941       return;
942     }
943
944     // In case colours can't be loaded, we'll remove them
945     // from the default list here.
946     StringBuffer coloursFound = new StringBuffer();
947     StringTokenizer st = new StringTokenizer(files, "|");
948     while (st.hasMoreElements())
949     {
950       String file = st.nextToken();
951       try
952       {
953         UserColourScheme ucs = loadColours(file);
954         if (ucs != null)
955         {
956           if (coloursFound.length() > 0)
957           {
958             coloursFound.append("|");
959           }
960           coloursFound.append(file);
961           userColourSchemes.put(ucs.getName(), ucs);
962         }
963       } catch (Exception ex)
964       {
965         System.out.println("Error loading User ColourFile\n" + ex);
966       }
967     }
968     if (!files.equals(coloursFound.toString()))
969     {
970       if (coloursFound.toString().length() > 1)
971       {
972         jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS",
973                 coloursFound.toString());
974       }
975       else
976       {
977         jalview.bin.Cache.applicationProperties
978                 .remove("USER_DEFINED_COLOURS");
979       }
980     }
981   }
982
983   public static void removeColourFromDefaults(String target)
984   {
985     // The only way to find colours by name is to load them in
986     // In case colours can't be loaded, we'll remove them
987     // from the default list here.
988
989     userColourSchemes = new Hashtable();
990
991     StringBuffer coloursFound = new StringBuffer();
992     StringTokenizer st = new StringTokenizer(
993             jalview.bin.Cache.getProperty("USER_DEFINED_COLOURS"), "|");
994
995     while (st.hasMoreElements())
996     {
997       String file = st.nextToken();
998       try
999       {
1000         UserColourScheme ucs = loadColours(file);
1001         if (ucs != null && !ucs.getName().equals(target))
1002         {
1003           if (coloursFound.length() > 0)
1004           {
1005             coloursFound.append("|");
1006           }
1007           coloursFound.append(file);
1008           userColourSchemes.put(ucs.getName(), ucs);
1009         }
1010       } catch (Exception ex)
1011       {
1012         System.out.println("Error loading User ColourFile\n" + ex);
1013       }
1014     }
1015
1016     if (coloursFound.toString().length() > 1)
1017     {
1018       jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS",
1019               coloursFound.toString());
1020     }
1021     else
1022     {
1023       jalview.bin.Cache.applicationProperties
1024               .remove("USER_DEFINED_COLOURS");
1025     }
1026
1027   }
1028
1029   @Override
1030   public void caseSensitive_actionPerformed(ActionEvent e)
1031   {
1032     resetButtonPanel(caseSensitive.isSelected());
1033     lcaseColour.setEnabled(caseSensitive.isSelected());
1034   }
1035
1036   @Override
1037   public void lcaseColour_actionPerformed(ActionEvent e)
1038   {
1039     if (selectedButtons == null)
1040     {
1041       selectedButtons = new ArrayList<JButton>();
1042     }
1043     else
1044     {
1045       selectedButtons.clear();
1046     }
1047     selectedButtons.add(lcaseColour);
1048   }
1049 }