2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
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.Format;
34 import jalview.util.MessageManager;
36 import java.awt.Color;
38 import java.awt.event.ActionEvent;
39 import java.awt.event.MouseEvent;
41 import java.io.FileInputStream;
42 import java.io.FileOutputStream;
43 import java.io.InputStreamReader;
44 import java.io.OutputStreamWriter;
45 import java.io.PrintWriter;
46 import java.util.ArrayList;
47 import java.util.Hashtable;
48 import java.util.StringTokenizer;
50 import javax.swing.JButton;
51 import javax.swing.JInternalFrame;
52 import javax.swing.JOptionPane;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
57 * This panel allows the user to assign colours to Amino Acid residue codes, and
58 * save the colour scheme.
60 * @author Andrew Waterhouse
61 * @author Mungo Carstairs
63 public class UserDefinedColours extends GUserDefinedColours implements
66 private static final int MY_FRAME_HEIGHT = 420;
68 private static final int MY_FRAME_WIDTH = 810;
70 private static final int MY_FRAME_WIDTH_CASE_SENSITIVE = 970;
74 SequenceGroup seqGroup;
76 ArrayList<JButton> selectedButtons;
78 ColourSchemeI oldColourScheme;
82 JalviewStructureDisplayI jmol;
84 ArrayList<JButton> upperCaseButtons;
86 ArrayList<JButton> lowerCaseButtons;
89 * Creates a new UserDefinedColours object.
96 public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
100 lcaseColour.setEnabled(false);
105 if (seqGroup != null)
107 oldColourScheme = seqGroup.cs;
111 oldColourScheme = ap.av.getGlobalColourScheme();
114 if (oldColourScheme instanceof UserColourScheme)
116 schemeName.setText(((UserColourScheme) oldColourScheme).getName());
117 if (((UserColourScheme) oldColourScheme).getLowerCaseColours() != null)
119 caseSensitive.setSelected(true);
120 lcaseColour.setEnabled(true);
121 resetButtonPanel(true);
125 resetButtonPanel(false);
130 resetButtonPanel(false);
136 public UserDefinedColours(JalviewStructureDisplayI jmol,
142 colorChooser.getSelectionModel().addChangeListener(this);
144 oldColourScheme = oldcs;
146 if (oldColourScheme instanceof UserColourScheme)
148 schemeName.setText(((UserColourScheme) oldColourScheme).getName());
151 resetButtonPanel(false);
159 colorChooser.getSelectionModel().addChangeListener(this);
160 frame = new JInternalFrame();
161 frame.setContentPane(this);
162 Desktop.addInternalFrame(frame,
163 MessageManager.getString("label.user_defined_colours"),
164 MY_FRAME_WIDTH, MY_FRAME_HEIGHT, true);
166 if (seqGroup != null)
168 frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
172 void resetButtonPanel(boolean caseSensitive)
174 buttonPanel.removeAll();
176 if (upperCaseButtons == null)
178 upperCaseButtons = new ArrayList<JButton>();
183 for (int i = 0; i < 20; i++)
187 label = ResidueProperties.aa[i];
191 label = ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
195 button = makeButton(label, ResidueProperties.aa[i], upperCaseButtons,
198 buttonPanel.add(button);
201 buttonPanel.add(makeButton("B", "B", upperCaseButtons, 20));
202 buttonPanel.add(makeButton("Z", "Z", upperCaseButtons, 21));
203 buttonPanel.add(makeButton("X", "X", upperCaseButtons, 22));
204 buttonPanel.add(makeButton("Gap", "-", upperCaseButtons, 23));
208 gridLayout.setRows(6);
209 gridLayout.setColumns(4);
213 gridLayout.setRows(7);
215 gridLayout.setColumns(cols + 1);
217 if (lowerCaseButtons == null)
219 lowerCaseButtons = new ArrayList<JButton>();
222 for (int i = 0; i < 20; i++)
224 int row = i / cols + 1;
225 int index = (row * cols) + i;
226 button = makeButton(ResidueProperties.aa[i].toLowerCase(),
227 ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
229 buttonPanel.add(button, index);
235 buttonPanel.add(makeButton("b", "b", lowerCaseButtons, 20));
236 buttonPanel.add(makeButton("z", "z", lowerCaseButtons, 21));
237 buttonPanel.add(makeButton("x", "x", lowerCaseButtons, 22));
240 // JAL-1360 widen the frame dynamically to accommodate case-sensitive AA
242 if (this.frame != null)
244 int newWidth = caseSensitive ? MY_FRAME_WIDTH_CASE_SENSITIVE
246 this.frame.setSize(newWidth, this.frame.getHeight());
249 buttonPanel.validate();
260 public void stateChanged(ChangeEvent evt)
262 if (selectedButtons != null)
264 JButton button = null;
265 final Color newColour = colorChooser.getColor();
266 for (int i = 0; i < selectedButtons.size(); i++)
268 button = selectedButtons.get(i);
269 button.setBackground(newColour);
270 button.setForeground(ColorUtils.brighterThan(newColour));
272 if (button == lcaseColour)
274 for (int i = 0; i < lowerCaseButtons.size(); i++)
276 button = lowerCaseButtons.get(i);
277 button.setBackground(newColour);
278 button.setForeground(ColorUtils.brighterThan(button
286 * Performs actions when a residue button is clicked. This manages the button
287 * selection set (highlighted by brighter foreground text).
289 * On select button(s) with Ctrl/click or Shift/click: set button foreground
290 * text to brighter than background.
292 * On unselect button(s) with Ctrl/click on selected, or click to release
293 * current selection: reset foreground text to darker than background.
295 * Simple click: clear selection (resetting foreground to darker); set clicked
296 * button foreground to brighter
298 * Finally, synchronize the colour chooser to the colour of the first button
299 * in the selected set.
303 public void colourButtonPressed(MouseEvent e)
305 if (selectedButtons == null)
307 selectedButtons = new ArrayList<JButton>();
310 JButton pressed = (JButton) e.getSource();
314 JButton start, end = (JButton) e.getSource();
315 if (selectedButtons.size() > 0)
317 start = selectedButtons.get(selectedButtons.size() - 1);
321 start = (JButton) e.getSource();
324 int startIndex = 0, endIndex = 0;
325 for (int b = 0; b < buttonPanel.getComponentCount(); b++)
327 if (buttonPanel.getComponent(b) == start)
331 if (buttonPanel.getComponent(b) == end)
337 if (startIndex > endIndex)
339 int temp = startIndex;
340 startIndex = endIndex;
344 for (int b = startIndex; b <= endIndex; b++)
346 JButton button = (JButton) buttonPanel.getComponent(b);
347 if (!selectedButtons.contains(button))
349 button.setForeground(ColorUtils.brighterThan(button
351 selectedButtons.add(button);
355 else if (!e.isControlDown())
357 for (int b = 0; b < selectedButtons.size(); b++)
359 JButton button = selectedButtons.get(b);
360 button.setForeground(ColorUtils.darkerThan(button.getBackground()));
362 selectedButtons.clear();
363 pressed.setForeground(ColorUtils.brighterThan(pressed.getBackground()));
364 selectedButtons.add(pressed);
367 else if (e.isControlDown())
369 if (selectedButtons.contains(pressed))
371 pressed.setForeground(ColorUtils.darkerThan(pressed.getBackground()));
372 selectedButtons.remove(pressed);
376 pressed.setForeground(ColorUtils.brighterThan(pressed
378 selectedButtons.add(pressed);
382 if (selectedButtons.size() > 0)
384 colorChooser.setColor((selectedButtons.get(0)).getBackground());
396 JButton makeButton(String label, String aa,
397 ArrayList<JButton> caseSensitiveButtons, int buttonIndex)
399 final JButton button;
402 if (buttonIndex < caseSensitiveButtons.size())
404 button = caseSensitiveButtons.get(buttonIndex);
405 col = button.getBackground();
409 button = new JButton();
410 button.addMouseListener(new java.awt.event.MouseAdapter()
413 public void mouseClicked(MouseEvent e)
415 colourButtonPressed(e);
419 caseSensitiveButtons.add(button);
422 if (oldColourScheme != null)
426 col = oldColourScheme.findColour(aa.charAt(0), -1, null);
427 } catch (Exception ex)
433 if (caseSensitive.isSelected())
435 button.setMargin(new java.awt.Insets(2, 2, 2, 2));
439 button.setMargin(new java.awt.Insets(2, 14, 2, 14));
442 button.setOpaque(true); // required for the next line to have effect
443 button.setBackground(col);
444 button.setText(label);
445 button.setForeground(ColorUtils.darkerThan(col));
446 button.setFont(new java.awt.Font("Verdana", Font.BOLD, 10));
458 protected void okButton_actionPerformed(ActionEvent e)
460 if (isNoSelectionMade())
462 JOptionPane.showMessageDialog(Desktop.desktop, MessageManager
463 .getString("label.no_colour_selection_in_scheme"),
464 MessageManager.getString("label.no_colour_selection_warn"),
465 JOptionPane.WARNING_MESSAGE);
469 applyButton_actionPerformed(null);
473 frame.setClosed(true);
474 } catch (Exception ex)
481 * Returns true if the user has not made any colour selection (including if
482 * 'case-sensitive' selected and no lower-case colour chosen).
486 protected boolean isNoSelectionMade()
488 final boolean noUpperCaseSelected = upperCaseButtons == null
489 || upperCaseButtons.isEmpty();
490 final boolean noLowerCaseSelected = caseSensitive.isSelected()
491 && (lowerCaseButtons == null || lowerCaseButtons.isEmpty());
492 final boolean noSelectionMade = noUpperCaseSelected || noLowerCaseSelected;
493 return noSelectionMade;
503 protected void applyButton_actionPerformed(ActionEvent e)
505 if (isNoSelectionMade())
507 JOptionPane.showMessageDialog(Desktop.desktop,
508 MessageManager.getString("label.no_colour_selection_in_scheme"),MessageManager.getString("label.no_colour_selection_warn"),
509 JOptionPane.WARNING_MESSAGE);
512 UserColourScheme ucs = getSchemeFromButtons();
513 ucs.setName(schemeName.getText());
515 if (seqGroup != null)
518 ap.paintAlignment(true);
522 ap.alignFrame.changeColour(ucs);
524 else if (jmol != null)
526 jmol.setJalviewColourScheme(ucs);
530 UserColourScheme getSchemeFromButtons()
533 Color[] newColours = new Color[24];
535 int length = upperCaseButtons.size();
538 for (JButton btn:upperCaseButtons){
539 newColours[i] = btn.getBackground();
543 for (int i = 0; i < 24; i++){
544 JButton button = upperCaseButtons.get(i);
545 newColours[i] = button.getBackground();
549 UserColourScheme ucs = new UserColourScheme(newColours);
551 if (caseSensitive.isSelected())
553 newColours = new Color[23];
554 length = lowerCaseButtons.size();
557 for (JButton btn:lowerCaseButtons){
558 newColours[i] = btn.getBackground();
562 for (int i = 0; i < 23; i++){
563 JButton button = lowerCaseButtons.get(i);
564 newColours[i] = button.getBackground();
567 ucs.setLowerCaseColours(newColours);
572 ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
585 protected void loadbutton_actionPerformed(ActionEvent e)
587 upperCaseButtons = new ArrayList<JButton>();
588 lowerCaseButtons = new ArrayList<JButton>();
590 JalviewFileChooser chooser = new JalviewFileChooser(
591 Cache.getProperty("LAST_DIRECTORY"), new String[]
592 { "jc" }, new String[]
593 { "Jalview User Colours" }, "Jalview User Colours");
594 chooser.setFileView(new JalviewFileView());
595 chooser.setDialogTitle(MessageManager
596 .getString("label.load_colour_scheme"));
597 chooser.setToolTipText(MessageManager.getString("action.load"));
599 int value = chooser.showOpenDialog(this);
601 if (value == JalviewFileChooser.APPROVE_OPTION)
603 File choice = chooser.getSelectedFile();
604 Cache.setProperty("LAST_DIRECTORY", choice.getParent());
605 String defaultColours = Cache.getDefault(
606 "USER_DEFINED_COLOURS", choice.getPath());
607 if (defaultColours.indexOf(choice.getPath()) == -1)
609 defaultColours = defaultColours.concat("|")
610 .concat(choice.getPath());
613 Cache.setProperty("USER_DEFINED_COLOURS", defaultColours);
615 UserColourScheme ucs = loadColours(choice.getAbsolutePath());
616 Color[] colors = ucs.getColours();
617 schemeName.setText(ucs.getName());
619 if (ucs.getLowerCaseColours() != null)
621 caseSensitive.setSelected(true);
622 lcaseColour.setEnabled(true);
623 resetButtonPanel(true);
624 for (int i = 0; i < lowerCaseButtons.size(); i++)
626 JButton button = lowerCaseButtons.get(i);
627 button.setBackground(ucs.getLowerCaseColours()[i]);
633 caseSensitive.setSelected(false);
634 lcaseColour.setEnabled(false);
635 resetButtonPanel(false);
638 for (int i = 0; i < upperCaseButtons.size(); i++)
640 JButton button = upperCaseButtons.get(i);
641 button.setBackground(colors[i]);
650 * @return DOCUMENT ME!
652 public static UserColourScheme loadDefaultColours()
654 UserColourScheme ret = null;
656 String colours = Cache.getProperty("USER_DEFINED_COLOURS");
659 if (colours.indexOf("|") > -1)
661 colours = colours.substring(0, colours.indexOf("|"));
664 ret = loadColours(colours);
669 Color[] newColours = new Color[24];
670 for (int i = 0; i < 24; i++)
672 newColours[i] = Color.white;
674 ret = new UserColourScheme(newColours);
686 * @return DOCUMENT ME!
688 static UserColourScheme loadColours(String file)
690 UserColourScheme ucs = null;
691 Color[] newColours = null;
694 InputStreamReader in = new InputStreamReader(
695 new FileInputStream(file), "UTF-8");
697 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
699 org.exolab.castor.xml.Unmarshaller unmar = new org.exolab.castor.xml.Unmarshaller(
701 jucs = (jalview.schemabinding.version2.JalviewUserColours) unmar
704 newColours = new Color[24];
706 Color[] lowerCase = null;
707 boolean caseSensitive = false;
711 for (int i = 0; i < jucs.getColourCount(); i++)
713 name = jucs.getColour(i).getName();
714 if (ResidueProperties.aa3Hash.containsKey(name))
716 index = ResidueProperties.aa3Hash.get(name)
721 index = ResidueProperties.aaIndex[name.charAt(0)];
728 if (name.toLowerCase().equals(name))
730 if (lowerCase == null)
732 lowerCase = new Color[23];
734 caseSensitive = true;
735 lowerCase[index] = new Color(Integer.parseInt(jucs.getColour(i)
740 newColours[index] = new Color(Integer.parseInt(jucs.getColour(i)
745 if (newColours != null)
747 ucs = new UserColourScheme(newColours);
748 ucs.setName(jucs.getSchemeName());
751 ucs.setLowerCaseColours(lowerCase);
755 } catch (Exception ex)
757 // Could be Archive Jalview format
760 InputStreamReader in = new InputStreamReader(new FileInputStream(
763 jalview.binding.JalviewUserColours jucs = new jalview.binding.JalviewUserColours();
765 jucs = jucs.unmarshal(in);
767 newColours = new Color[jucs.getColourCount()];
769 for (int i = 0; i < 24; i++)
771 newColours[i] = new Color(Integer.parseInt(jucs.getColour(i)
774 if (newColours != null)
776 ucs = new UserColourScheme(newColours);
777 ucs.setName(jucs.getSchemeName());
779 } catch (Exception ex2)
781 ex2.printStackTrace();
784 if (newColours == null)
786 System.out.println("Error loading User ColourFile\n" + ex);
800 protected void savebutton_actionPerformed(ActionEvent e)
802 if (schemeName.getText().trim().length() < 1)
804 JOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
805 .getString("label.user_colour_scheme_must_have_name"),
806 MessageManager.getString("label.no_name_colour_scheme"),
807 JOptionPane.WARNING_MESSAGE);
811 if (userColourSchemes != null
812 && userColourSchemes.containsKey(schemeName.getText()))
814 int reply = JOptionPane.showInternalConfirmDialog(Desktop.desktop,
815 MessageManager.formatMessage(
816 "label.colour_scheme_exists_overwrite", new Object[]
817 { schemeName.getText(), schemeName.getText() }),
818 MessageManager.getString("label.duplicate_scheme_name"),
819 JOptionPane.YES_NO_OPTION);
820 if (reply != JOptionPane.YES_OPTION)
825 userColourSchemes.remove(schemeName.getText());
827 JalviewFileChooser chooser = new JalviewFileChooser(
828 Cache.getProperty("LAST_DIRECTORY"), new String[]
829 { "jc" }, new String[]
830 { "Jalview User Colours" }, "Jalview User Colours");
832 chooser.setFileView(new JalviewFileView());
833 chooser.setDialogTitle(MessageManager.getString("label.save_colour_scheme"));
834 chooser.setToolTipText(MessageManager.getString("action.save"));
836 int value = chooser.showSaveDialog(this);
838 if (value == JalviewFileChooser.APPROVE_OPTION)
840 String choice = chooser.getSelectedFile().getPath();
841 String defaultColours = Cache.getDefault(
842 "USER_DEFINED_COLOURS", choice);
843 if (defaultColours.indexOf(choice) == -1)
845 if (defaultColours.length() > 0)
847 defaultColours = defaultColours.concat("|");
849 defaultColours = defaultColours.concat(choice);
852 userColourSchemes.put(schemeName.getText(), getSchemeFromButtons());
854 ap.alignFrame.updateUserColourMenu();
856 Cache.setProperty("USER_DEFINED_COLOURS", defaultColours);
858 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
860 ucs.setSchemeName(schemeName.getText());
863 PrintWriter out = new PrintWriter(new OutputStreamWriter(
864 new FileOutputStream(choice), "UTF-8"));
866 for (int i = 0; i < buttonPanel.getComponentCount(); i++)
868 JButton button = (JButton) buttonPanel.getComponent(i);
869 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
870 col.setName(button.getText());
871 col.setRGB(Format.getHexString(button.getBackground()));
877 } catch (Exception ex)
879 ex.printStackTrace();
891 protected void cancelButton_actionPerformed(ActionEvent e)
895 if (seqGroup != null)
897 seqGroup.cs = oldColourScheme;
901 ap.av.setGlobalColourScheme(oldColourScheme);
903 ap.paintAlignment(true);
908 jmol.setJalviewColourScheme(oldColourScheme);
913 frame.setClosed(true);
914 } catch (Exception ex)
919 static Hashtable userColourSchemes;
921 public static Hashtable getUserColourSchemes()
923 return userColourSchemes;
926 public static void initUserColourSchemes(String files)
928 userColourSchemes = new Hashtable();
930 if (files == null || files.length() == 0)
935 // In case colours can't be loaded, we'll remove them
936 // from the default list here.
937 StringBuffer coloursFound = new StringBuffer();
938 StringTokenizer st = new StringTokenizer(files, "|");
939 while (st.hasMoreElements())
941 String file = st.nextToken();
944 UserColourScheme ucs = loadColours(file);
947 if (coloursFound.length() > 0)
949 coloursFound.append("|");
951 coloursFound.append(file);
952 userColourSchemes.put(ucs.getName(), ucs);
954 } catch (Exception ex)
956 System.out.println("Error loading User ColourFile\n" + ex);
959 if (!files.equals(coloursFound.toString()))
961 if (coloursFound.toString().length() > 1)
963 Cache.setProperty("USER_DEFINED_COLOURS",
964 coloursFound.toString());
968 Cache.applicationProperties
969 .remove("USER_DEFINED_COLOURS");
974 public static void removeColourFromDefaults(String target)
976 // The only way to find colours by name is to load them in
977 // In case colours can't be loaded, we'll remove them
978 // from the default list here.
980 userColourSchemes = new Hashtable();
982 StringBuffer coloursFound = new StringBuffer();
983 StringTokenizer st = new StringTokenizer(
984 Cache.getProperty("USER_DEFINED_COLOURS"), "|");
986 while (st.hasMoreElements())
988 String file = st.nextToken();
991 UserColourScheme ucs = loadColours(file);
992 if (ucs != null && !ucs.getName().equals(target))
994 if (coloursFound.length() > 0)
996 coloursFound.append("|");
998 coloursFound.append(file);
999 userColourSchemes.put(ucs.getName(), ucs);
1001 } catch (Exception ex)
1003 System.out.println("Error loading User ColourFile\n" + ex);
1007 if (coloursFound.toString().length() > 1)
1009 Cache.setProperty("USER_DEFINED_COLOURS",
1010 coloursFound.toString());
1014 Cache.applicationProperties
1015 .remove("USER_DEFINED_COLOURS");
1021 public void caseSensitive_actionPerformed(ActionEvent e)
1023 resetButtonPanel(caseSensitive.isSelected());
1024 lcaseColour.setEnabled(caseSensitive.isSelected());
1028 public void lcaseColour_actionPerformed(ActionEvent e)
1030 if (selectedButtons == null)
1032 selectedButtons = new ArrayList<JButton>();
1036 selectedButtons.clear();
1038 selectedButtons.add(lcaseColour);