/*******************************************************************************
* 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.trackList;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import edu.yu.einstein.genplay.core.manager.application.ConfigurationManager;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.core.manager.project.ProjectWindow;
import edu.yu.einstein.genplay.gui.event.genomeWindowEvent.GenomeWindowListener;
import edu.yu.einstein.genplay.gui.track.Track;
import edu.yu.einstein.genplay.gui.track.layer.Layer;
/**
* Model that manages a list of tracks
* @author Julien Lajugie
*/
public class TrackListModel implements Serializable {
private static final long serialVersionUID = 6131854814047955278L; // generated serial id
/**
* Creates a track list containing only empty tracks with the default
* project settings (number and height of tracks)
* @return a list of tracks
*/
private static Track[] createDefaultTrackList() {
int trackCount = ConfigurationManager.getInstance().getTrackCount();
Track[] tracks = new Track[trackCount];
for (int i = 0; i < trackCount; i++) {
tracks[i] = new Track(i + 1);
}
return tracks;
}
private final List<ListDataListener> dataListeners; // list of listeners that is notified each time a change to the data model occurs
private Track[] tracks; // array of tracks displayed in the table
/**
* Creates an instance of {@link TrackListModel}
*/
public TrackListModel() {
this(createDefaultTrackList());
}
/**
* Creates an instance of {@link TrackListModel}
* @param tracks tracks of the model
*/
public TrackListModel(Track[] tracks) {
dataListeners = new ArrayList<ListDataListener>();
setTracks(tracks);
}
/**
* Adds a listener to the list that's notified each time a change to the data model occurs.
* @param dataListener
*/
public void addListDataListener(ListDataListener dataListener) {
if (!dataListeners.contains(dataListener)) {
dataListeners.add(dataListener);
}
}
/**
* Deletes the track at the specified row
* @param row
*/
public void deleteTrack(int row) {
// removes references to avoid memory leaks
for (int i = row + 1; i < tracks.length; i++) {
tracks[i - 1] = tracks[i];
}
tracks[tracks.length - 1] = new Track(tracks.length);
updateTracksRegisteredToProjectWindow();
// we notify the listeners that the data changed
ListDataEvent event = new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, row, row);
notifyListeners(event);
}
/**
* Deletes the specified track if the track is present in the list
* @param track
*/
public void deleteTrack(Track track) {
int trackIndex = indexOf(track);
if (trackIndex != -1) {
deleteTrack(trackIndex);
}
}
/**
* @return the list of all the layers displayed in the {@link TrackListPanel}
*/
public List<Layer<?>> getAllLayers() {
List<Layer<?>> allLayers = new ArrayList<Layer<?>>();
for (Track currentTrack: tracks) {
allLayers.addAll(currentTrack.getLayers());
}
return allLayers;
}
/**
* @param row
* @return the {@link Track} at the specified row
*/
public Track getTrack(int row) {
return tracks[row];
}
/**
* @return the number of track
*/
public int getTrackCount() {
return tracks.length;
}
/**
* @return the tracks displayed in the JTable
*/
public Track[] getTracks() {
return tracks;
}
/**
* @param track a Track
* @return the index of the specified track in the data list if found. -1 if the specified track is not found
*/
public int indexOf(Track track) {
for (int i = 0; i < tracks.length; i++) {
if (track == tracks[i]) {
return i;
}
}
return -1;
}
/**
* Insert a row right before the specified row
* @param row
* @param track track to insert
*/
public void insertTrack(int row, Track track) {
for (int i = tracks.length - 2; i >= row; i--) {
tracks[i + 1] = tracks[i];
}
tracks[row] = track;
updateTracksRegisteredToProjectWindow();
// we notify the listeners that the data changed
ListDataEvent event = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, row, row);
notifyListeners(event);
}
/**
* Notifies all the {@link ListDataListener} that the data changed
* @param event
*/
private void notifyListeners(ListDataEvent event) {
switch (event.getType()) {
case ListDataEvent.CONTENTS_CHANGED:
for (ListDataListener listener: dataListeners) {
listener.contentsChanged(event);
}
case ListDataEvent.INTERVAL_ADDED:
for (ListDataListener listener: dataListeners) {
listener.intervalAdded(event);
}
case ListDataEvent.INTERVAL_REMOVED:
for (ListDataListener listener: dataListeners) {
listener.intervalRemoved(event);
}
}
}
/**
* Removes a listener from the list that's notified each time a change to the data model occurs.
* @param dataListener
*/
public void removeListDataListener(ListDataListener dataListener) {
dataListeners.remove(dataListener);
}
/**
* Sets the {@link Track} at the specified row
* @param track a track
* @param row row where the track needs to be set
*/
public void setTrack(Track track, int row) {
tracks[row] = track;
updateTracksRegisteredToProjectWindow();
// we notify the listeners that the data changed
ListDataEvent event = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, row, row);
notifyListeners(event);
}
/**
* @param tracks the tracks to display in the JTable
*/
public void setTracks(Track[] tracks) {
this.tracks = tracks;
updateTracksRegisteredToProjectWindow();
// we notify the listeners that the data changed
ListDataEvent event = new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, tracks.length - 1);
notifyListeners(event);
}
/**
* This method update the list of tracks registered as {@link GenomeWindowListener} in the
* {@link ProjectWindow}. This method should be used every time the list of track is modified.
* All the tracks not present in this model are removed from the list of listeners.
* All the tracks of this model that are not registered are added to the list of listeners.
*/
public void updateTracksRegisteredToProjectWindow() {
ProjectWindow projectWindow = ProjectManager.getInstance().getProjectWindow();
// removes all the track listener from the list of listeners of the project window
for (GenomeWindowListener currentGWL: projectWindow.getGenomeWindowListeners()) {
if (currentGWL instanceof Track) {
projectWindow.removeGenomeWindowListener(currentGWL);
}
}
// registers the tracks
for (Track currentTrack: tracks) {
projectWindow.addGenomeWindowListener(currentTrack);
}
}
}