/******************************************************************************* * GenPlay, Einstein Genome Analyzer * Copyright (C) 2009, 2014 Albert Einstein College of Medicine * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu> * Nicolas Fourel <nicolas.fourel@einstein.yu.edu> * Eric Bouhassira <eric.bouhassira@einstein.yu.edu> * * Website: <http://genplay.einstein.yu.edu> ******************************************************************************/ package edu.yu.einstein.genplay.gui.dialog.trackChooser; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import edu.yu.einstein.genplay.gui.track.Track; import edu.yu.einstein.genplay.gui.track.TrackComparator; import edu.yu.einstein.genplay.util.Images; import edu.yu.einstein.genplay.util.Utils; import edu.yu.einstein.genplay.util.colors.Colors; /** * A dialog box used to choose tracks * @author Julien Lajugie * @version 0.1 */ public class MultiTrackChooser extends JDialog { private static final long serialVersionUID = -4678243279540123148L; // generated ID private static final Dimension WINDOW_SIZE = new Dimension(680, 400); // size of the dialog box private static final int LIST_WIDTH = 200; // preferred width of the 2 JList private static JLabel jlaAvailableTracks; // label for the list of available tracks private static JLabel jlaSelectedTracks; // label for the list of selected tracks private static JList jliAvailableTracks; // list of available tracks private static DefaultListModel dlmAvailableTracks; // model of the list of available tracks private static JList jliSelectedTracks; // list of selected tracks private static DefaultListModel dlmSelectedTracks; // model of the list of selected tracks private static JButton jbLeft; // left button private static JButton jbRight; // right button private static JButton jbUp; // up button private static JButton jbDown; // down button private static JButton jbOk; // OK button private static JButton jbCancel; // cancel button private static boolean validated; // true if OK has been pressed /** * Displays a dialog box allowing the user to select tracks * @param parent the parent {@link Component} from which the dialog is displayed * @param availableTracks array of {@link Track} * @return an array containing the track selected. Null if cancel was pressed */ public static Track[] getSelectedTracks(Component parent, Track[] availableTracks) { // the list model for selected tracks must be empty dlmSelectedTracks = new DefaultListModel(); // show the dialog and return selected tracks return getTracks(parent, availableTracks); } /** * Displays a dialog box allowing the user to select tracks. * This method allows user to define a list of track that are already selected * @param parent the parent {@link Component} from which the dialog is displayed * @param availableTracks array of {@link Track} to select * @param selectedTracks array of {@link Track} already selected * @return an array containing the track selected. Null if cancel was pressed */ public static Track[] getSelectedTracks(Component parent, Track[] availableTracks, Track[] selectedTracks) { // the list model for selected tracks is set to empty dlmSelectedTracks = new DefaultListModel(); // we will try to add tracks in the list model for selected tracks if (selectedTracks != null) { for (Track currentTrack: selectedTracks) { dlmSelectedTracks.addElement(currentTrack); } } // show the dialog and return selected tracks return getTracks(parent, availableTracks); } /** * Displays a dialog box allowing the user to select tracks. * @param parent the parent {@link Component} from which the dialog is displayed * @param availableTracks array of {@link Track} to select * @return an array containing the track selected. Null if cancel was pressed */ private static Track[] getTracks (Component parent, Track[] availableTracks) { MultiTrackChooser mtc = new MultiTrackChooser(parent, availableTracks); mtc.setVisible(true); if(validated) { Track[] result = new Track[dlmSelectedTracks.getSize()]; for (int i = 0; i < dlmSelectedTracks.getSize(); i++) { result[i] = (Track) dlmSelectedTracks.getElementAt(i); } return result; } else { return null; } } /** * Private constructor. Used internally to create a {@link MultiTrackChooser} dialog. * @param parent The parent {@link Component} from which the dialog is displayed. * @param availableTracks array of {@link Track} */ private MultiTrackChooser(Component parent, Track[] availableTracks) { initComponents(availableTracks); addComponents(); pack(); setIconImages(Images.getApplicationImages()); setModalityType(ModalityType.APPLICATION_MODAL); validated = false; setTitle("Select Tracks"); getRootPane().setDefaultButton(jbOk); setLocationRelativeTo(parent); setSize(WINDOW_SIZE); } /** * Adds the subcomponents */ private void addComponents() { setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.PAGE_END; c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.insets = new Insets(10, 10, 0, 0); add(jlaAvailableTracks, c); c = new GridBagConstraints(); c.anchor = GridBagConstraints.PAGE_END; c.gridx = 2; c.gridy = 0; c.weightx = 1; c.weighty = 0; c.insets = new Insets(10, 0, 0, 0); add(jlaSelectedTracks, c); c = new GridBagConstraints(); c.gridx = 0; c.gridy = 1; c.gridheight = 2; c.weightx = 1; c.weighty = 1; c.insets = new Insets(0, 10, 0, 0); c.fill = GridBagConstraints.BOTH; JScrollPane scrollAvailableTracks = new JScrollPane(jliAvailableTracks); scrollAvailableTracks.getVerticalScrollBar().setUnitIncrement(Utils.SCROLL_INCREMENT_UNIT); scrollAvailableTracks.setPreferredSize(new Dimension(LIST_WIDTH, getPreferredSize().height)); add(scrollAvailableTracks, c); c = new GridBagConstraints(); c.gridx = 1; c.gridy = 1; c.weightx = 0; c.weighty = 1; c.anchor = GridBagConstraints.PAGE_END; c.insets = new Insets(0, 10, 0, 10); add(jbRight, c); c = new GridBagConstraints(); c.gridx = 1; c.gridy = 2; c.weightx = 0; c.weighty = 1; c.anchor = GridBagConstraints.PAGE_START; c.insets = new Insets(0, 10, 0, 10); add(jbLeft, c); c = new GridBagConstraints(); c.gridx = 2; c.gridy = 1; c.gridheight = 2; c.weightx = 1; c.weighty = 1; c.fill = GridBagConstraints.BOTH; JScrollPane scrollSelectedTracks = new JScrollPane(jliSelectedTracks); scrollSelectedTracks.getVerticalScrollBar().setUnitIncrement(Utils.SCROLL_INCREMENT_UNIT); scrollSelectedTracks.setPreferredSize(new Dimension(LIST_WIDTH, getPreferredSize().height)); add(scrollSelectedTracks, c); c = new GridBagConstraints(); c.gridx = 3; c.gridy = 1; c.weightx = 0; c.weighty = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_END; c.insets = new Insets(0, 10, 0, 10); add(jbUp, c); c = new GridBagConstraints(); c.gridx = 3; c.gridy = 2; c.weightx = 0; c.weighty = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.PAGE_START; c.insets = new Insets(0, 10, 0, 10); add(jbDown, c); c = new GridBagConstraints(); c.gridx = 2; c.gridy = 3; c.weightx = 0; c.weighty = 0; c.anchor = GridBagConstraints.LINE_END; c.insets = new Insets(10, 0, 10, 0); add(jbOk, c); c = new GridBagConstraints(); c.gridx = 3; c.gridy = 3; c.weightx = 0; c.weighty = 0; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(10, 0, 10, 10); add(jbCancel, c); } /** * Initializes the subcomponents of the dialog box * @param availableTracks array of {@link Track} */ private void initComponents(Track[] availableTracks) { dlmAvailableTracks = new DefaultListModel(); for (Track currentTrack: availableTracks) { dlmAvailableTracks.addElement(currentTrack); } jlaAvailableTracks = new JLabel("Available Tracks"); jlaSelectedTracks = new JLabel("Selected Tracks"); jliAvailableTracks = new JList(dlmAvailableTracks); jliAvailableTracks.setBorder(BorderFactory.createLineBorder(Colors.BLACK)); jliAvailableTracks.setBackground(Colors.WHITE); jliAvailableTracks.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent arg0) { if (jliAvailableTracks.isSelectionEmpty()) { jbRight.setEnabled(false); } else { jbRight.setEnabled(true); } } }); jliAvailableTracks.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { // if jbRight gain the focus we need to keep the selection in order to // know which tracks need to be transfered if (e.getOppositeComponent() != jbRight) { jliAvailableTracks.clearSelection(); } } }); jliAvailableTracks.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if ((e.getClickCount() % 2) == 0) { selectTracks(); } } }); jliSelectedTracks = new JList(dlmSelectedTracks); //jliSelectedTracks.setPreferredSize(new Dimension(LIST_WIDTH, getPreferredSize().height)); jliSelectedTracks.setBorder(BorderFactory.createLineBorder(Color.black)); jliSelectedTracks.setBackground(Color.white); jliSelectedTracks.addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent arg0) { if (jliSelectedTracks.isSelectionEmpty()) { jbLeft.setEnabled(false); jbUp.setEnabled(false); jbDown.setEnabled(false); } else { jbLeft.setEnabled(true); jbUp.setEnabled(true); jbDown.setEnabled(true); if (jliSelectedTracks.getSelectedIndices().length > 1) { jbUp.setEnabled(false); jbDown.setEnabled(false); } else { if (jliSelectedTracks.getSelectedIndex() == 0) { jbUp.setEnabled(false); } if (jliSelectedTracks.getSelectedIndex() == (dlmSelectedTracks.getSize() - 1)) { jbDown.setEnabled(false); } } } } }); jliSelectedTracks.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { // if jbLeft, jbUp or jbDown gain the focus we need to keep the selection in order to // know which tracks need to be transfered if ((e.getOppositeComponent() != jbLeft) && (e.getOppositeComponent() != jbUp) && (e.getOppositeComponent() != jbDown)) { jliSelectedTracks.clearSelection(); } } }); jliSelectedTracks.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if ((e.getClickCount() % 2) == 0) { unSelectTracks(); } } }); jbLeft = new JButton("<"); jbLeft.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { unSelectTracks(); } }); jbLeft.setEnabled(false); jbRight = new JButton(">"); jbRight.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { selectTracks(); } }); jbRight.setEnabled(false); jbUp = new JButton("Up"); jbUp.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { selectedTrackUp(); } }); jbUp.setEnabled(false); jbDown = new JButton("Down"); jbDown.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { selectedTrackDown(); } }); jbDown.setEnabled(false); jbOk = new JButton("OK"); jbOk.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { jbOkClicked(); } }); jbCancel = new JButton("Cancel"); jbCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jbCancelClicked(); } }); } /** * Closes the dialog. No action are performed. */ private void jbCancelClicked() { dispose(); } /** * Closes the dialog. Sets validated to true so the main function can return the two selected curves. */ private void jbOkClicked() { validated = true; dispose(); } /** * Moves the selected {@link Track} down in the list of selected tracks */ protected void selectedTrackDown() { int selectedIndex = jliSelectedTracks.getSelectedIndex(); Object tempTrack = dlmSelectedTracks.getElementAt(selectedIndex); dlmSelectedTracks.setElementAt(dlmSelectedTracks.getElementAt(selectedIndex + 1), selectedIndex); dlmSelectedTracks.setElementAt(tempTrack, selectedIndex + 1); jliSelectedTracks.setSelectedIndex(selectedIndex + 1); } /** * Moves the selected {@link Track} up in the list of selected tracks */ protected void selectedTrackUp() { int selectedIndex = jliSelectedTracks.getSelectedIndex(); Object tempTrack = dlmSelectedTracks.getElementAt(selectedIndex); dlmSelectedTracks.setElementAt(dlmSelectedTracks.getElementAt(selectedIndex - 1), selectedIndex); dlmSelectedTracks.setElementAt(tempTrack, selectedIndex - 1); jliSelectedTracks.setSelectedIndex(selectedIndex - 1); } /** * Moves the selected tracks from the list of available tracks to the list of selected tracks */ protected void selectTracks() { if (!jliAvailableTracks.isSelectionEmpty()) { Track[] selectedTracks = new Track[jliAvailableTracks.getSelectedValues().length]; for (int i = 0; i < selectedTracks.length; i++) { selectedTracks[i] = (Track) jliAvailableTracks.getSelectedValues()[i]; } for (Track currentTrack: selectedTracks) { dlmSelectedTracks.addElement(currentTrack); dlmAvailableTracks.removeElement(currentTrack); } } } /** * Moves the selected tracks from the list of selected tracks to the list of available tracks */ protected void unSelectTracks() { if (!jliSelectedTracks.isSelectionEmpty()) { // Get the selected tracks from the selected list of track Track[] selectedTracks = new Track[jliSelectedTracks.getSelectedValues().length]; for (int i = 0; i < selectedTracks.length; i++) { selectedTracks[i] = (Track) jliSelectedTracks.getSelectedValues()[i]; } // Get the current available tracks List<Track> tracks = new ArrayList<Track>(); for (Object object: dlmAvailableTracks.toArray()) { tracks.add((Track) object); } // For all selected tracks for (Track currentTrack: selectedTracks) { tracks.add(currentTrack); // we add them to the current available list of track dlmSelectedTracks.removeElement(currentTrack); // we delete them from the selected tracks } // We sort the new list and update the model of the available list of track Collections.sort(tracks, new TrackComparator()); dlmAvailableTracks.removeAllElements(); for (Track currentTrack: tracks) { dlmAvailableTracks.addElement(currentTrack); } } } }