/*
* Group.java
* JCollider
*
* Copyright (c) 2004-2010 Hanns Holger Rutz. All rights reserved.
*
* This software 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, june 1991 of the License, or (at your option) any later version.
*
* This software 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 (gpl.txt) along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de , or visit http://www.sciss.de/jcollider
*
*
* JCollider is closely modelled after SuperCollider Language,
* often exhibiting a direct translation from Smalltalk to Java.
* SCLang is a software originally developed by James McCartney,
* which has become an Open Source project.
* See http://www.audiosynth.com/ for details.
*
*
* Changelog:
* 04-Aug-05 created
* 02-Oct-05 removed all setGroup statements. to have the group
* set correctly, use a NodeWatcher instead
*/
package de.sciss.jcollider;
import java.io.IOException;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import javax.swing.tree.TreeNode;
import de.sciss.net.OSCMessage;
/**
* Mimics SCLang's Group class,
* that is, it's a client side
* representation of a group in the synthesis graph
*
* @warning this is a quick direct translation from SClang
* which is largely untested. before all methods have been
* thoroughly verified, excepted some of them to be wrong
* or behave different than expected. what certainly works
* is instantiation, new- and free-messages
*
* @author Hanns Holger Rutz
* @version 0.32, 25-Feb-08
*/
public class Group
extends Node
{
private Node headNode = null;
private Node tailNode = null;
// immediately sends
public Group( Group target )
throws IOException
{
this( target, kAddToHead );
}
// immediately sends
public Group( Node target, int addAction )
throws IOException
{
super( target.getServer() );
getServer().sendMsg( newMsg( target, addAction ));
}
// does not send
private Group( Server server, int nodeID )
{
super( server, nodeID );
}
public Node getHeadNode()
{
return headNode;
}
public Node getTailNode()
{
return tailNode;
}
protected void setHeadNode( Node headNode )
{
this.headNode = headNode;
}
protected void setTailNode( Node tailNode )
{
this.tailNode = tailNode;
}
public OSCMessage newMsg()
{
return newMsg( null );
}
public OSCMessage newMsg( Group target )
{
return newMsg( target, kAddToHead );
}
/**
* Note: this sets the group!
*
* @throws ClassCastException if target is not a group and addAction
* is either kAddToHead or kAddToTail
*/
public OSCMessage newMsg( Node target, int addAction )
{
if( target == null ) target = getServer().getDefaultGroup();
// removed 02-oct-05
// this.setGroup( addAction == kAddToHead || addAction == kAddToTail ?
// (Group) target : target.getGroup() );
return( new OSCMessage( "/g_new", new Object[] {
new Integer( this.getNodeID() ), new Integer( addAction ), new Integer( target.getNodeID() )}));
}
public static Group basicNew( Server server )
{
return Group.basicNew( server, server.nextNodeID() );
}
public static Group basicNew( Server server, int nodeID )
{
return new Group( server, nodeID );
}
public static Group after( Node aNode )
throws IOException
{
return new Group( aNode, kAddAfter );
}
public static Group before( Node aNode )
throws IOException
{
return new Group( aNode, kAddBefore );
}
public static Group head( Group aGroup )
throws IOException
{
return new Group( aGroup, kAddToHead );
}
public static Group tail( Group aGroup )
throws IOException
{
return new Group( aGroup, kAddToTail );
}
public static Group replace( Node nodeToReplace )
throws IOException
{
return new Group( nodeToReplace, kAddReplace );
}
// for bundling
public OSCMessage addToHeadMsg( Group aGroup )
{
return newMsg( aGroup, kAddToHead );
}
public OSCMessage addToTailMsg( Group aGroup )
{
return newMsg( aGroup, kAddToTail );
}
public OSCMessage addAfterMsg( Node aNode )
{
return newMsg( aNode, kAddAfter );
}
public OSCMessage addBeforeMsg( Node aNode )
{
return newMsg( aNode, kAddBefore );
}
public OSCMessage addReplaceMsg( Node aNode )
{
return newMsg( aNode, kAddReplace );
}
// move Nodes to this group
public void moveNodeToHead( Node aNode )
throws IOException
{
// NO
// setGroup is called by moveNodeToHeadMsg()
// aNode.setGroup( this );
getServer().sendMsg( moveNodeToHeadMsg( aNode ));
}
public void moveNodeToTail( Node aNode )
throws IOException
{
// NO
// setGroup is called by moveNodeToTailMsg()
// aNode.setGroup( this );
getServer().sendMsg( moveNodeToTailMsg( aNode ));
}
public OSCMessage moveNodeToHeadMsg( Node aNode )
{
// removed 02-oct-05
// aNode.setGroup( this );
return( new OSCMessage( "/g_head", new Object[] {
new Integer( this.getNodeID() ), new Integer( aNode.getNodeID() )}));
}
public OSCMessage moveNodeToTailMsg( Node aNode )
{
// removed 02-oct-05
// aNode.setGroup( this );
return( new OSCMessage( "/g_tail", new Object[] {
new Integer( this.getNodeID() ), new Integer( aNode.getNodeID() )}));
}
// free my children, but this node is still playing
public void freeAll()
throws IOException
{
getServer().sendMsg( freeAllMsg() );
}
public OSCMessage freeAllMsg()
{
return new OSCMessage( "/g_freeAll", new Object[] { new Integer( this.getNodeID() )});
}
public void deepFree()
throws IOException
{
getServer().sendMsg( deepFreeMsg() );
}
public OSCMessage deepFreeMsg()
{
return new OSCMessage( "/g_deepFree", new Object[] { new Integer( this.getNodeID() )});
}
public String toString()
{
if( getName() == null ) {
return( "Group(" + getNodeID() + ")" );
} else {
return( "Group::" + getName() + "(" + getNodeID() + ")" );
}
}
// -------------- TreeNode interface --------------
public TreeNode getChildAt( int childIndex )
{
final Enumeration children = children();
for( int idx = 0; idx < childIndex; idx++ ) {
children.nextElement();
}
return (TreeNode) children.nextElement();
}
public int getChildCount()
{
int idx = 0;
for( Enumeration children = children(); children.hasMoreElements(); children.nextElement() ) idx++;
return idx;
}
public int getIndex( TreeNode node )
{
final Enumeration children = children();
for( int idx = 0; children.hasMoreElements(); idx++ ) {
if( children.nextElement().equals( node )) {
return idx;
}
}
return -1;
}
public boolean getAllowsChildren()
{
return true;
}
public boolean isLeaf()
{
return false;
}
public Enumeration children()
{
return new ChildEnumeration( this );
}
// -------------- internal classes --------------
private static class ChildEnumeration
implements Enumeration
{
private Node nextElement;
protected ChildEnumeration( Group g )
{
nextElement = g.getHeadNode();
}
public boolean hasMoreElements()
{
return( nextElement != null );
}
public Object nextElement()
{
final Node result = nextElement;
if( nextElement == null ) {
throw new NoSuchElementException();
} else {
nextElement = nextElement.getSuccNode();
return result;
}
}
}
}