/*
* Created on Mar 14, 2006
*
* Copyright (c) 2006 P.J.Leonard
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika 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 2 of the License, or
* (at your option) any later version.
* Frinika 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 Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.sequencer.gui.selection;
import java.util.Collection;
import java.util.Vector;
import com.frinika.project.ProjectContainer;
import com.frinika.sequencer.model.Selectable;
public abstract class SelectionContainer<T extends Selectable> implements SelectionFocusable {
/**
* The selectionStartTick is the timebase of the selection. It's neccesary
* when copying events in order to place them correctly in time when pasting
* them to another location.
*
* The selectionStartTick is used by the tracker - since you may want to select a number of rows - but the first event in the selection might
* not be on the first row. Let's say the first row was a beat row - and you want to paste into another beat row. Then you would want your pasted
* data to appear as the selection. Another issue is when the selected data is not 100% quantized. Using the selectionStartTick reference solves
* that issue as well.
*
* Set to -1 if not used
*/
private long selectionStartTick = -1;
private int selectionLeftColumn; // Also used by the tracker
protected T focus = null;
Vector<T> selectedList = new Vector<T>();
Vector<SelectionListener<T>> selectionListeners = new Vector<SelectionListener<T>>();
ProjectContainer project;
boolean dirty=false;
public SelectionContainer(ProjectContainer project){
this.project=project;
}
/**
* Add one T to the selection
*
* @param item
*/
public void addSelected(T item) {
selectedList.add(item);
item.setSelected(true);
// Notify selection listeners
Vector<T> list = new Vector<T>();
list.add(item);
setFocus(item);
// notifyListeners();
/*for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.addedToSelection(this, list);
*/
project.setSelectionFocus(this);
dirty=true;
}
/**
* Add multiple items to the selection
*
* @param Lanes
*/
public void addSelected(Collection<? extends T> list) {
selectedList.addAll(list);
for (T item : list)
item.setSelected(true);
if (list.size() != 0 ) focus=list.iterator().next();
// Notify selection listeners
// notifyListeners();
/* for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.addedToSelection(this, list);
*/
project.setSelectionFocus(this);
dirty=true;
}
public void setSelected(T item) {
Vector<T> list = new Vector<T>();
list.add(item);
setSelected(list);
}
/**
* Clear then add multiple items to the selection
*
* @param Lanes
*/
public void setSelected(Collection<? extends T> list) {
for (T t : selectedList) {
t.setSelected(false);
}
selectedList.removeAllElements();
selectionStartTick = -1;
focus=null;
for (T item : list)
item.setSelected(true);
selectedList.addAll(list);
if (list.size() !=0 ) setFocus(focus=list.iterator().next());
// notifyListeners();
project.setSelectionFocus(this);
dirty=true;
}
@SuppressWarnings("unchecked")
public void setSelectedX(Collection<Selectable> list) {
for (T t : selectedList) {
t.setSelected(false);
}
selectedList.removeAllElements();
selectionStartTick = -1;
focus=null;
for (Selectable item : list)
item.setSelected(true);
selectedList.addAll((Collection<T>)list);
if (list.size() !=0 ) setFocus(focus=(T)list.iterator().next());
// notifyListeners();
project.setSelectionFocus(this);
dirty=true;
}
/**
* Remove one T to the selection
*
* @param item
*/
public void removeSelected(T item) {
if (item== focus) focus=null;
selectedList.remove(item);
item.setSelected(false);
// Notify selection listeners
Vector<T> list = new Vector<T>();
list.add(item);
// notifyListeners();
/* for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.removedFromSelection(this, list);
*/
dirty=true;
}
/**
* Add multiple Lanes to the selection
*
* @param Lanes
*/
public void removeSelected(Collection<? extends T> list) {
if (list.contains(focus)) focus=null;
selectedList.removeAll(list);
for (T item : list) {
//if (item instanceof Selectable)
item.setSelected(false);
}
// Notify selection listeners
// notifyListeners();
/* for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.removedFromSelection(this, list);
*/
dirty=true;
}
/**
* Clear the selection
*/
public void clearSelection() {
focus=null;
selectionStartTick = -1;
for (T t : selectedList) {
t.setSelected(false);
}
selectedList.clear();
// notifyListeners();
// Notify selection listeners
/* for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.selectionCleared(this);*/
dirty=true;
}
/**
* @return Returns the selectionStartTick.
*/
public long getSelectionStartTick() {
return selectionStartTick;
}
/**
* The selectionStartTick is the timebase of the selection. It's neccesary
* when copying events in order to place them correctly in time when pasting
* them to another location.
*
* An editor should always set a selectionStartTick when starting on a new
* selection. It's a good idea to base the starttick on the current snap (or
* quantize) resolution.
*
* @param selectionStartTick
*/
public void setSelectionStartTick(long selectionStartTick) {
this.selectionStartTick = selectionStartTick;
dirty=true;
}
/**
* Returns the selected Lanes. Note that you should NOT add or remove events
* directly from this returned collection. Use the provided methods from
* this container.
*
* @return
*/
public Collection<T> getSelected() {
return selectedList;
}
public Collection<Selectable> getObjects() {
return (Collection<Selectable>) selectedList;
}
/**
* Add a LaneSelectionListener to this container
*
* @param listener
*/
public void addSelectionListener(SelectionListener<T> listener) {
selectionListeners.add(listener);
}
/**
* Remove a LaneSelectionListener from this container
*
* @param listener
*/
public void removeSelectionListener(SelectionListener<T> listener) {
selectionListeners.remove(listener);
}
/**
* I need a focus so I will get it from here for now. This might move (PJL).
*
*
* @return
*/
public T getFocus() {
return focus;
/*
* if (selectedList.size() == 0 ) return null; else return
* selectedList.elementAt(0);
*/
}
/**
* Override this null implementation to get focus to follow containers
*
*/
protected abstract void setMetaFocus();
public void setFocus(T focus) {
if (focus == this.focus && project.getSelectionFocus() == this) return;
this.focus=focus;
setMetaFocus();
// notifyListeners();
project.setSelectionFocus(this);
dirty=true;
}
public void notifyListeners() {
if (!dirty) return;
for (SelectionListener<T> selectionListener : selectionListeners)
selectionListener.selectionChanged(this);
dirty=false;
}
public void setSelectionLeftColumn(int selectionLeftColumn) {
this.selectionLeftColumn = selectionLeftColumn;
dirty=true;
}
public int getSelectionLeftColumn() {
return selectionLeftColumn;
}
public void setDirty() {
dirty=true;
}
}