+ * On select button(s) with Ctrl/click or Shift/click: set button foreground + * text to brighter than background. + *
+ * On unselect button(s) with Ctrl/click on selected, or click to release + * current selection: reset foreground text to darker than background. + *
+ * Simple click: clear selection (resetting foreground to darker); set clicked + * button foreground to brighter + *
+ * Finally, synchronize the colour chooser to the colour of the first button
+ * in the selected set.
+ *
+ * @param e
+ */
+ public void colourButtonPressed(MouseEvent e)
+ {
+ JButton pressed = (JButton) e.getSource();
+
+ if (e.isShiftDown())
+ {
+ JButton start, end = (JButton) e.getSource();
+ if (selectedButtons.size() > 0)
+ {
+ start = selectedButtons.get(selectedButtons.size() - 1);
+ }
+ else
+ {
+ start = (JButton) e.getSource();
+ }
+
+ int startIndex = 0, endIndex = 0;
+ for (int b = 0; b < buttonPanel.getComponentCount(); b++)
+ {
+ if (buttonPanel.getComponent(b) == start)
+ {
+ startIndex = b;
+ }
+ if (buttonPanel.getComponent(b) == end)
+ {
+ endIndex = b;
+ }
+ }
+
+ if (startIndex > endIndex)
+ {
+ int temp = startIndex;
+ startIndex = endIndex;
+ endIndex = temp;
+ }
+
+ for (int b = startIndex; b <= endIndex; b++)
+ {
+ JButton button = (JButton) buttonPanel.getComponent(b);
+ if (!selectedButtons.contains(button))
+ {
+ button.setForeground(
+ ColorUtils.brighterThan(button.getBackground()));
+ selectedButtons.add(button);
+ }
+ }
+ }
+ else if (!e.isControlDown())
+ {
+ for (int b = 0; b < selectedButtons.size(); b++)
+ {
+ JButton button = selectedButtons.get(b);
+ button.setForeground(ColorUtils.darkerThan(button.getBackground()));
+ }
+ selectedButtons.clear();
+ pressed.setForeground(
+ ColorUtils.brighterThan(pressed.getBackground()));
+ selectedButtons.add(pressed);
+
+ }
+ else if (e.isControlDown())
+ {
+ if (selectedButtons.contains(pressed))
+ {
+ pressed.setForeground(
+ ColorUtils.darkerThan(pressed.getBackground()));
+ selectedButtons.remove(pressed);
+ }
+ else
+ {
+ pressed.setForeground(
+ ColorUtils.brighterThan(pressed.getBackground()));
+ selectedButtons.add(pressed);
+ }
+ }
+
+ if (selectedButtons.size() > 0)
+ {
+ colorChooser.setColor((selectedButtons.get(0)).getBackground());
+ }
+ }
+
+ /**
+ * A helper method to update or make a colour button, whose background colour
+ * is the associated colour, and text colour a darker shade of the same. If
+ * the button is already in the list, then its text and margins are updated,
+ * if not then it is created and added. This method supports toggling between
+ * case-sensitive and case-insensitive button panels. The case-sensitive
+ * version has abbreviated button text in order to fit in more buttons.
+ *
+ * @param label
+ * @param residue
+ * @param the
+ * list of buttons
+ * @param buttonIndex
+ * the button's position in the list
+ */
+ JButton makeButton(String label, String residue, List
+ *
+ */
+ @Override
+ protected void loadbutton_actionPerformed()
+ {
+ upperCaseButtons = new ArrayList<>();
+ lowerCaseButtons = new ArrayList<>();
+ JalviewFileChooser chooser = new JalviewFileChooser("jc",
+ "Jalview User Colours");
+ chooser.setFileView(new JalviewFileView());
+ chooser.setDialogTitle(
+ MessageManager.getString("label.load_colour_scheme"));
+ chooser.setToolTipText(MessageManager.getString("action.load"));
+ chooser.setResponseHandler(0, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ File choice = chooser.getSelectedFile();
+ Cache.setProperty(LAST_DIRECTORY, choice.getParent());
+
+ UserColourScheme ucs = ColourSchemeLoader
+ .loadColourScheme(choice.getAbsolutePath());
+ Color[] colors = ucs.getColours();
+ schemeName.setText(ucs.getSchemeName());
+
+ if (ucs.getLowerCaseColours() != null)
+ {
+ caseSensitive.setSelected(true);
+ lcaseColour.setEnabled(true);
+ resetButtonPanel(true);
+ for (int i = 0; i < lowerCaseButtons.size(); i++)
+ {
+ JButton button = lowerCaseButtons.get(i);
+ button.setBackground(ucs.getLowerCaseColours()[i]);
+ }
+ }
+ else
+ {
+ caseSensitive.setSelected(false);
+ lcaseColour.setEnabled(false);
+ resetButtonPanel(false);
+ }
+
+ for (int i = 0; i < upperCaseButtons.size(); i++)
+ {
+ JButton button = upperCaseButtons.get(i);
+ button.setBackground(colors[i]);
+ }
+
+ addNewColourScheme(choice.getPath());
+ }
+ });
+
+ chooser.showOpenDialog(this);
+ }
+
+ /**
+ * Loads the user-defined colour scheme from the first file listed in property
+ * "USER_DEFINED_COLOURS". If this fails, returns an all-white colour scheme.
+ *
+ * @return
+ */
+ public static UserColourScheme loadDefaultColours()
+ {
+ UserColourScheme ret = null;
+
+ String colours = Cache.getProperty(USER_DEFINED_COLOURS);
+ if (colours != null)
+ {
+ if (colours.indexOf("|") > -1)
+ {
+ colours = colours.substring(0, colours.indexOf("|"));
+ }
+ ret = ColourSchemeLoader.loadColourScheme(colours);
+ }
+
+ if (ret == null)
+ {
+ ret = new UserColourScheme("white");
+ }
+
+ return ret;
+ }
+
+ /**
+ * Action on pressing the Save button.
+ *
+ *
+ * If the scheme is saved to file, the 'changed' flag field is reset to false.
+ */
+ @Override
+ protected void savebutton_actionPerformed()
+ {
+ String name = schemeName.getText().trim();
+ if (name.length() < 1)
+ {
+ JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+ MessageManager
+ .getString("label.user_colour_scheme_must_have_name"),
+ MessageManager.getString("label.no_name_colour_scheme"),
+ JvOptionPane.WARNING_MESSAGE);
+ }
+
+ if (ColourSchemes.getInstance().nameExists(name))
+ {
+ // BH 2018 SwingJS bypasses this question with YES_OPTION
+ int reply = /** @j2sNative 0 && */ JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
+ MessageManager.formatMessage(
+ "label.colour_scheme_exists_overwrite", new Object[]
+ { name, name }),
+ MessageManager.getString("label.duplicate_scheme_name"),
+ JvOptionPane.YES_NO_OPTION);
+ if (reply != JvOptionPane.YES_OPTION)
+ {
+ }
+ }
+
+ JalviewFileChooser chooser = new JalviewFileChooser("jc",
+ "Jalview User Colours");
+
+ JalviewFileView fileView = new JalviewFileView();
+ chooser.setFileView(fileView);
+ chooser.setDialogTitle(
+ MessageManager.getString("label.save_colour_scheme"));
+ chooser.setToolTipText(MessageManager.getString("action.save"));
+ int option = chooser.showSaveDialog(this);
+ if (option == JalviewFileChooser.APPROVE_OPTION)
+ {
+ File file = chooser.getSelectedFile();
+ UserColourScheme updatedScheme = addNewColourScheme(file.getPath());
+ saveToFile(file);
+ changedButNotSaved = false;
+
+ /*
+ * changes saved - apply to alignment if we are changing
+ * the currently selected colour scheme; also make the updated
+ * colours the 'backout' scheme on Cancel
+ */
+ if (oldColourScheme != null
+ && name.equals(oldColourScheme.getSchemeName()))
+ {
+ oldColourScheme = updatedScheme;
+ applyButton_actionPerformed();
+ }
+ }
+ }
+
+ /**
+ * Adds the current colour scheme to the Jalview properties file so it is
+ * loaded on next startup, and updates the Colour menu in the parent
+ * AlignFrame (if there is one). Note this action does not including applying
+ * the colour scheme.
+ *
+ * @param filePath
+ * @return
+ */
+ protected UserColourScheme addNewColourScheme(String filePath)
+ {
+ /*
+ * update the delimited list of user defined colour files in
+ * Jalview property USER_DEFINED_COLOURS
+ */
+ String defaultColours = Cache.getDefault(USER_DEFINED_COLOURS,
+ filePath);
+ if (defaultColours.indexOf(filePath) == -1)
+ {
+ if (defaultColours.length() > 0)
+ {
+ defaultColours = defaultColours.concat("|");
+ }
+ defaultColours = defaultColours.concat(filePath);
+ }
+ Cache.setProperty(USER_DEFINED_COLOURS, defaultColours);
+
+ /*
+ * construct and register the colour scheme
+ */
+ UserColourScheme ucs = getSchemeFromButtons();
+ ColourSchemes.getInstance().registerColourScheme(ucs);
+
+ /*
+ * update the Colour menu items
+ */
+ if (ap != null)
+ {
+ ap.alignFrame.buildColourMenu();
+ }
+
+ return ucs;
+ }
+
+ /**
+ * Saves the colour scheme to file in XML format
+ *
+ * @param path
+ */
+ protected void saveToFile(File toFile)
+ {
+ /*
+ * build a Java model of colour scheme as XML, and
+ * marshal to file
+ */
+ JalviewUserColours ucs = new JalviewUserColours();
+ String name = schemeName.getText();
+ ucs.setSchemeName(name);
+ try
+ {
+ PrintWriter out = new PrintWriter(new OutputStreamWriter(
+ new FileOutputStream(toFile), "UTF-8"));
+
+ for (int i = 0; i < buttonPanel.getComponentCount(); i++)
+ {
+ JButton button = (JButton) buttonPanel.getComponent(i);
+ Colour col = new Colour();
+ col.setName(button.getText());
+ col.setRGB(Format.getHexString(button.getBackground()));
+ ucs.getColour().add(col);
+ }
+ JAXBContext jaxbContext = JAXBContext
+ .newInstance(JalviewUserColours.class);
+ Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+ jaxbMarshaller.marshal(
+ new ObjectFactory().createJalviewUserColours(ucs), out);
+ // ucs.marshal(out);
+ out.close();
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * On cancel, restores the colour scheme that was selected before the dialogue
+ * was opened
+ */
+ @Override
+ protected void cancelButton_actionPerformed()
+ {
+ ap.alignFrame.changeColour(oldColourScheme);
+ ap.paintAlignment(true, true);
+
+ try
+ {
+ frame.setClosed(true);
+ } catch (Exception ex)
+ {
+ }
+ }
+
+ /**
+ * Action on selecting or deselecting the Case Sensitive option. When
+ * selected, separate buttons are shown for lower case residues, and the panel
+ * is resized to accommodate them. Also, the checkbox for 'apply colour to all
+ * lower case' is enabled.
+ */
+ @Override
+ public void caseSensitive_actionPerformed()
+ {
+ boolean selected = caseSensitive.isSelected();
+ resetButtonPanel(selected);
+ lcaseColour.setEnabled(selected);
+ }
+}