/*
* Created on Mar 2, 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.model;
import java.awt.Color;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.io.Serializable;
import java.util.List;
import java.util.Vector;
import javax.swing.Icon;
import uk.org.toot.audio.core.AudioBuffer.MetaInfo;
import com.frinika.project.ProjectContainer;
public abstract class Lane implements Selectable, EditHistoryRecordable,
EditHistoryRecorder<Part>, Serializable {
private static final long serialVersionUID = -2220043314267459844L;
// static int colorCount = 0;
transient boolean selected = false;
transient MetaInfo channelLabel = null;
//int colorID;
Color color;
protected List<Part> parts;
/* this is the list of lanes contained within this lane. */
protected List<Lane> children;
/* this is for display */
transient private int displayY;
transient private int displayH;
protected int height;
/* flags for GUI */
boolean open = true;
boolean hidden = false;
/* display lane index (how many lanes from the top is it displayed) */
transient int visibleID;
transient int uniqueID; // is this used ??? PJL
private String name;
ProjectContainer project;
/*
* to save the position in the children list. Only for use by the add/remove
* methods
*/
transient private int indexInList = -1;
int soloMuteFlags = 0;
/* Constructor for serializable interface */
protected Lane() {
}
protected Lane(String name, ProjectContainer project) {
height = 1; // Layout.getLaneItemHeight();
this.project = project;
parts = new Vector<Part>();
children = new Vector<Lane>();
setName(name);
// colorID = colorCount++;
}
public List<Part> getParts() {
return parts;
}
/**
*
* Remove all parts
*
*/
public void removeAll() {
Vector<Part> partsCopy=new Vector<Part>(parts);
for (Part part:partsCopy) {
remove(part);
}
}
/**
* remove a part.
* You must use this if you want the GUI to be maintained
* Call project.getEditHistoryContainer().notfiyObserers().
*
*/
public void remove(Part part) {
part.commitEventsRemove();
synchronized(this) {
parts.remove(part);
}
if (part.isSelected())
part.lane.project.getPartSelection().removeSelected(part);
project.getEditHistoryContainer().push(this,
EditHistoryRecordableAction.EDIT_HISTORY_TYPE_REMOVE, part);
}
public void add(Part part) {
// System.out.println("Lane.add " + part);
synchronized(this) {
parts.add(part);
}
part.lane = this;
part.commitEventsAdd();
project.getEditHistoryContainer().push(this,
EditHistoryRecordableAction.EDIT_HISTORY_TYPE_ADD, part);
}
public boolean isSelected() {
return selected;
}
public int getHeight() {
return height;
}
// public int getColorID() {
// return colorID;
// }
public ProjectContainer getProject() {
return project;
}
public void setSelected(boolean b) {
selected = b;
}
public String getName() {
return name;
}
@Override
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
*
* @param lane
* to add to children.
*/
public void addChildLane(Lane lane) {
if (lane.indexInList == -1)
children.add(lane);
else
children.add(lane.indexInList, lane);
if (lane instanceof MidiLane) {
((MidiLane) lane).attachFTW();
}
}
public void addChildLane(int indexInList, Lane lane) {
children.add(indexInList, lane);
if (lane instanceof MidiLane) {
((MidiLane) lane).attachFTW();
}
}
/**
* Lane to add
*
* @param lane
* to remove
*/
public void removeChildLane(Lane lane) {
int pos = children.indexOf(lane);
lane.indexInList = pos;
children.remove(lane);
if (lane instanceof MidiLane)
((MidiLane) lane).detachFTW();
}
/**
* Return a flat view of the decendent lanes.
*
* @return a List of all the lanes including this and all decendents
*/
public List<Lane> getFamilyLanes() {
Vector<Lane> lanes = new Vector<Lane>();
lanes.add(this);
if (children != null)
for (Lane child : children) {
lanes.addAll(child.getFamilyLanes());
}
return lanes;
}
/**
* If a lane is hidden it will not be displayed in the lane panel. Note that
* it's children might still be displayed (see isOpen())
*
* @return
*/
public boolean isHidden() {
return hidden;
}
/**
* If a lane is open it's children might be displayed in the lane panel. if
* it is not open then none of it's decendents will be in the lane panel.
*
* @return
*/
public boolean isOpen() {
return open;
}
/**
*
* @return list of the Lanes children (contents of this folder)
*/
public List<Lane> getChildren() {
return children;
}
/**
* Used by the partview for mapping onto the screen.
*
* @return distance from the top of the display.
*/
public int getDisplayY() {
return displayY;
}
public int getDisplayH() {
return displayH;
}
void setDisplayPos(int y, int h, int id) {
displayY = y;
displayH = h;
visibleID = id;
}
/**
* For the partview GUI.
*
* @return lane position in the visible lane list
*/
public int getDisplayID() {
return visibleID;
}
/**
*
* Hide the lane in the part view. You will need to get the partview to
* rebuild for this to take effect.
*/
public void setHidden(boolean b) {
hidden = b;
}
/**
*
* Open the lane in the part view. You will need to get the partview to
* rebuild for this to take effect.
*/
public void setOpen(boolean b) {
open = b;
}
public void setName(String name) {
this.name = name;
channelLabel = new MetaInfo(name);
}
/**
* Actions to be done when this lane is loaded
*/
public void onLoad() {
// System.out.println(" loading " + getParts().size());
if (getParts() == null)
return;
for (Part part : getParts()) {
try {
part.onLoad();
} catch (Exception e) {
e.printStackTrace();
}
}
for (Lane lane : getChildren())
lane.onLoad();
}
/**
* Remove the lane from the project.
* Override to do any subclass specific stuff.
* (used by undo)
*/
public void removeFromModel() {
project.remove(this);
detachComponents();
System.out.println(" REMOVE LANE ");
}
private void detachComponents() {
// for (Part part : getParts()) {
// part.detach();
// }
for (Lane lane : getChildren())
lane.detachComponents();
}
/**
* Add the lane from the project.
* Override to do any subclass specific stuff.
* (used by redo)
*/
public void addToModel() {
project.add(this);
attachComponents();
System.out.println(" Add LANE ");
}
/**
* For undo/redo
*
*/
private void attachComponents() {
// for (Part part : getParts()) {
// part.attach();
// }
for (Lane lane : getChildren())
lane.attachComponents();
}
public long leftTickForMove() {
return 0;
}
public long rightTickForMove() {
// TODO Auto-generated method stub
return 0;
}
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream in)
throws ClassNotFoundException, IOException {
in.defaultReadObject();
// System. out.println(colorID);
// need to do this to make sure we get new colours creating lanes later
// colorCount = Math.max(colorCount, colorID + 1);
height = 1;
setName(name); // just to set the channelInfo
}
public void setHeight(int i) {
height = i;
}
public void displayStructure(String prefix, PrintStream out) {
out.println(prefix + " " + toString());
prefix += "*";
if (children != null)
for (Lane lane : children) {
lane.displayStructure(prefix, out);
}
if (parts != null)
for (Part part : parts) {
part.displayStructure(prefix, out);
}
}
abstract public Part createPart();
/**
*
* @return icon for the gui (e.g. lane header)
*/
public abstract Icon getIcon();
}