Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.gui

File UserDefinedColours.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

112
265
21
1
917
601
86
0.32
12.62
21
4.1

Classes

Class Line # Actions
UserDefinedColours 66 265 86
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

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