c9c1531512d1f616fe79b8d7d2dde49b48b2cd2b
[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.jbgui.GUserDefinedColours;
27 import jalview.schemes.ColourSchemeI;
28 import jalview.schemes.ResidueProperties;
29 import jalview.schemes.UserColourScheme;
30 import jalview.util.ColorUtils;
31 import jalview.util.MessageManager;
32
33 import java.awt.Color;
34 import java.awt.Font;
35 import java.awt.event.ActionEvent;
36 import java.awt.event.MouseEvent;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileOutputStream;
40 import java.io.InputStreamReader;
41 import java.io.OutputStreamWriter;
42 import java.io.PrintWriter;
43 import java.util.ArrayList;
44 import java.util.Hashtable;
45 import java.util.StringTokenizer;
46
47 import javax.swing.JButton;
48 import javax.swing.JInternalFrame;
49 import javax.swing.JOptionPane;
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       JOptionPane.showMessageDialog(Desktop.desktop, MessageManager
460               .getString("label.no_colour_selection_in_scheme"),
461               MessageManager.getString("label.no_colour_selection_warn"),
462               JOptionPane.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       JOptionPane.showMessageDialog(Desktop.desktop, MessageManager
506               .getString("label.no_colour_selection_in_scheme"),
507               MessageManager.getString("label.no_colour_selection_warn"),
508               JOptionPane.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(
600             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
601             new String[] { "jc" }, new String[] { "Jalview User Colours" },
602             "Jalview User Colours");
603     chooser.setFileView(new jalview.io.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       JOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
813               .getString("label.user_colour_scheme_must_have_name"),
814               MessageManager.getString("label.no_name_colour_scheme"),
815               JOptionPane.WARNING_MESSAGE);
816       return;
817     }
818
819     if (userColourSchemes != null
820             && userColourSchemes.containsKey(schemeName.getText()))
821     {
822       int reply = JOptionPane.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               JOptionPane.YES_NO_OPTION);
828       if (reply != JOptionPane.YES_OPTION)
829       {
830         return;
831       }
832
833       userColourSchemes.remove(schemeName.getText());
834     }
835     JalviewFileChooser chooser = new JalviewFileChooser(
836             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
837             new String[] { "jc" }, new String[] { "Jalview User Colours" },
838             "Jalview User Colours");
839
840     chooser.setFileView(new jalview.io.JalviewFileView());
841     chooser.setDialogTitle(MessageManager
842             .getString("label.save_colour_scheme"));
843     chooser.setToolTipText(MessageManager.getString("action.save"));
844
845     int value = chooser.showSaveDialog(this);
846
847     if (value == JalviewFileChooser.APPROVE_OPTION)
848     {
849       String choice = chooser.getSelectedFile().getPath();
850       String defaultColours = jalview.bin.Cache.getDefault(
851               "USER_DEFINED_COLOURS", choice);
852       if (defaultColours.indexOf(choice) == -1)
853       {
854         if (defaultColours.length() > 0)
855         {
856           defaultColours = defaultColours.concat("|");
857         }
858         defaultColours = defaultColours.concat(choice);
859       }
860
861       userColourSchemes.put(schemeName.getText(), getSchemeFromButtons());
862
863       ap.alignFrame.updateUserColourMenu();
864
865       jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS", defaultColours);
866
867       jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
868
869       ucs.setSchemeName(schemeName.getText());
870       try
871       {
872         PrintWriter out = new PrintWriter(new OutputStreamWriter(
873                 new FileOutputStream(choice), "UTF-8"));
874
875         for (int i = 0; i < buttonPanel.getComponentCount(); i++)
876         {
877           JButton button = (JButton) buttonPanel.getComponent(i);
878           jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
879           col.setName(button.getText());
880           col.setRGB(jalview.util.Format.getHexString(button
881                   .getBackground()));
882           ucs.addColour(col);
883         }
884
885         ucs.marshal(out);
886         out.close();
887       } catch (Exception ex)
888       {
889         ex.printStackTrace();
890       }
891     }
892   }
893
894   /**
895    * DOCUMENT ME!
896    * 
897    * @param e
898    *          DOCUMENT ME!
899    */
900   @Override
901   protected void cancelButton_actionPerformed(ActionEvent e)
902   {
903     if (ap != null)
904     {
905       if (seqGroup != null)
906       {
907         seqGroup.cs = oldColourScheme;
908       }
909       else if (ap != null)
910       {
911         ap.av.setGlobalColourScheme(oldColourScheme);
912       }
913       ap.paintAlignment(true);
914     }
915
916     if (jmol != null)
917     {
918       jmol.setJalviewColourScheme(oldColourScheme);
919     }
920
921     try
922     {
923       frame.setClosed(true);
924     } catch (Exception ex)
925     {
926     }
927   }
928
929   static Hashtable userColourSchemes;
930
931   public static Hashtable getUserColourSchemes()
932   {
933     return userColourSchemes;
934   }
935
936   public static void initUserColourSchemes(String files)
937   {
938     userColourSchemes = new Hashtable();
939
940     if (files == null || files.length() == 0)
941     {
942       return;
943     }
944
945     // In case colours can't be loaded, we'll remove them
946     // from the default list here.
947     StringBuffer coloursFound = new StringBuffer();
948     StringTokenizer st = new StringTokenizer(files, "|");
949     while (st.hasMoreElements())
950     {
951       String file = st.nextToken();
952       try
953       {
954         UserColourScheme ucs = loadColours(file);
955         if (ucs != null)
956         {
957           if (coloursFound.length() > 0)
958           {
959             coloursFound.append("|");
960           }
961           coloursFound.append(file);
962           userColourSchemes.put(ucs.getName(), ucs);
963         }
964       } catch (Exception ex)
965       {
966         System.out.println("Error loading User ColourFile\n" + ex);
967       }
968     }
969     if (!files.equals(coloursFound.toString()))
970     {
971       if (coloursFound.toString().length() > 1)
972       {
973         jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS",
974                 coloursFound.toString());
975       }
976       else
977       {
978         jalview.bin.Cache.applicationProperties
979                 .remove("USER_DEFINED_COLOURS");
980       }
981     }
982   }
983
984   public static void removeColourFromDefaults(String target)
985   {
986     // The only way to find colours by name is to load them in
987     // In case colours can't be loaded, we'll remove them
988     // from the default list here.
989
990     userColourSchemes = new Hashtable();
991
992     StringBuffer coloursFound = new StringBuffer();
993     StringTokenizer st = new StringTokenizer(
994             jalview.bin.Cache.getProperty("USER_DEFINED_COLOURS"), "|");
995
996     while (st.hasMoreElements())
997     {
998       String file = st.nextToken();
999       try
1000       {
1001         UserColourScheme ucs = loadColours(file);
1002         if (ucs != null && !ucs.getName().equals(target))
1003         {
1004           if (coloursFound.length() > 0)
1005           {
1006             coloursFound.append("|");
1007           }
1008           coloursFound.append(file);
1009           userColourSchemes.put(ucs.getName(), ucs);
1010         }
1011       } catch (Exception ex)
1012       {
1013         System.out.println("Error loading User ColourFile\n" + ex);
1014       }
1015     }
1016
1017     if (coloursFound.toString().length() > 1)
1018     {
1019       jalview.bin.Cache.setProperty("USER_DEFINED_COLOURS",
1020               coloursFound.toString());
1021     }
1022     else
1023     {
1024       jalview.bin.Cache.applicationProperties
1025               .remove("USER_DEFINED_COLOURS");
1026     }
1027
1028   }
1029
1030   @Override
1031   public void caseSensitive_actionPerformed(ActionEvent e)
1032   {
1033     resetButtonPanel(caseSensitive.isSelected());
1034     lcaseColour.setEnabled(caseSensitive.isSelected());
1035   }
1036
1037   @Override
1038   public void lcaseColour_actionPerformed(ActionEvent e)
1039   {
1040     if (selectedButtons == null)
1041     {
1042       selectedButtons = new ArrayList<JButton>();
1043     }
1044     else
1045     {
1046       selectedButtons.clear();
1047     }
1048     selectedButtons.add(lcaseColour);
1049   }
1050 }