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