package com.salas.bb.networking.manager;
import com.salas.bb.utils.uif.UifUtilities;
import com.salas.bb.utils.uif.treetable.AbstractTreeTableModel;
import com.salas.bb.utils.uif.treetable.TreeTableModel;
import com.salas.bb.utils.i18n.Strings;
import javax.swing.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* Model for displaying activity if groups of tasks.
*
* This model has a trick which allows users of it to get the <code>NetTask</code> object itself
* instead of it's fields broken into columns. In order to do that you need to ask a value for
* a column with index -1.
*/
public class NetTasksModel extends AbstractTreeTableModel
{
/** Index of Task Name column. */
public static final int COL_TASK_NAME = 0;
/** Index of column with progress indicator. */
public static final int COL_PROGRESS = 1;
/** Index of column with commands. */
public static final int COL_COMMANDS = 2;
private final static String[] COLUMN_NAME =
{ Strings.message("activity.taskstable.name"), Strings.message("activity.taskstable.progress"), "_" };
private final static Class[] COLUMN_CLASS =
{ TreeTableModel.class, Double.class, Integer.class };
private ModelChangeListener rootListener;
/**
* Creates model.
*/
public NetTasksModel(NetTaskGroup aRoot)
{
super(aRoot);
rootListener = new ModelChangeListener();
aRoot.addPropertyChangeListener(rootListener);
aRoot.addListener(rootListener);
}
/**
* Returns the number of availible columns.
*
* @return number of columns.
*/
public int getColumnCount()
{
return COLUMN_NAME.length;
}
/**
* Returns the name for column number <code>column</code>.
*
* @param column column index.
* @return name of column.
*/
public String getColumnName(int column)
{
return COLUMN_NAME[column];
}
/**
* Returns the type for column number <code>column</code>.
*
* @return class.
*/
public Class getColumnClass(int column)
{
return COLUMN_CLASS[column];
}
/**
* Returns the value to be displayed for node <code>node</code>,
* at column number <code>column</code>.
*
* @param node node to get value of.
* @param column column index.
* @return value.
*/
public Object getValueAt(Object node, int column)
{
NetTask task = (NetTask)node;
Object value;
switch (column)
{
case COL_TASK_NAME:
value = task.getTitle();
break;
case COL_PROGRESS:
float progress = task.getProgress();
value = new Double(progress);
break;
case COL_COMMANDS:
value = new Integer(task.getStatus());
break;
case -1:
// Small cheat to provide a fast path for gitting node from tree-table.
value = task;
break;
default:
value = null;
}
return value;
}
/**
* Returns the child of <code>parent</code> at index <code>index</code>
* in the parent's
* child array. <code>parent</code> must be a node previously obtained
* from this data source. This should not return <code>null</code>
* if <code>index</code>
* is a valid index for <code>parent</code> (that is <code>index >= 0 &&
* index < getChildCount(parent</code>)).
*
* @param parent a node in the tree, obtained from this data source
* @return the child of <code>parent</code> at index <code>index</code>
*/
public Object getChild(Object parent, int index)
{
return (parent instanceof NetTaskGroup)
? ((NetTaskGroup)parent).getTask(index)
: null;
}
/**
* Returns the number of children of <code>parent</code>.
* Returns 0 if the node
* is a leaf or if it has no children. <code>parent</code> must be a node
* previously obtained from this data source.
*
* @param parent a node in the tree, obtained from this data source
* @return the number of children of the node <code>parent</code>
*/
public int getChildCount(Object parent)
{
return (parent instanceof NetTaskGroup)
? ((NetTaskGroup)parent).getTaskCount()
: 0;
}
/**
* Returns TRUE if nonde is leaf.
*
* @param node node to check.
* @return TRUE if node is leaf.
*/
public boolean isLeaf(Object node)
{
return !(node instanceof NetTaskGroup);
}
/**
* Returns coordinates package for the task. If the task isn't put into tree or it's a
* top level node (root) then the result will be undefined (NULL).
*
* @param group group the task belongs to.
* @param task task to get coordinates for.
*
* @return coordinates or NULL.
*/
private Coordinates getTaskCoordinates(NetTaskGroup group, NetTask task)
{
Coordinates coords = null;
if (group != null)
{
List pathL = new ArrayList();
NetTaskGroup parent = group;
while (parent != null)
{
pathL.add(0, parent);
parent = parent.getParent();
}
coords = new Coordinates();
coords.path = pathL.toArray();
coords.index = group.indexOf(task);
}
return coords;
}
/**
* Coordinates of single task.
*/
private static class Coordinates
{
private Object[] path;
private int index;
}
// ---------------------------------------------------------------------------------------------
/**
* Adapter between changes in model and tree-table.
*/
private class ModelChangeListener implements PropertyChangeListener, INetTaskGroupListener
{
/**
* Called when some task property changes.
*
* @param evt property change event.
*/
public void propertyChange(final PropertyChangeEvent evt)
{
if (UifUtilities.isEDT())
{
propertyChangeEDT(evt);
} else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
propertyChangeEDT(evt);
}
});
}
}
/**
* Called when some task property changes.
*
* @param evt property change event.
*/
private void propertyChangeEDT(PropertyChangeEvent evt)
{
NetTask task = (NetTask)evt.getSource();
Coordinates coords = getTaskCoordinates(task.getParent(), task);
// If coordinates aren't set then it's root
if (coords != null)
{
int[] indicies = new int[] { coords.index };
Object[] children = new Object[] { task };
fireTreeNodesChanged(this, coords.path, indicies, children);
}
}
/**
* Fired when new task is added to the group.
*
* @param group group to which the task was added.
* @param task added task.
*/
public void taskAdded(final NetTaskGroup group, final NetTask task)
{
if (UifUtilities.isEDT())
{
taskAddedEDT(group, task);
} else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
taskAddedEDT(group, task);
}
});
}
}
/**
* Fired when new task is added to the group.
*
* @param group group to which the task was added.
* @param task added task.
*/
private void taskAddedEDT(NetTaskGroup group, NetTask task)
{
Coordinates coords = getTaskCoordinates(group, task);
if (coords != null && coords.index != -1)
{
int[] indicies = new int[] { coords.index };
Object[] children = new Object[] { task };
fireTreeNodesInserted(this, coords.path, indicies, children);
}
}
/**
* Fired when task is removed from the group.
*
* @param group group the task was removed from.
* @param task removed task.
* @param index index of removed task.
*/
public void taskRemoved(final NetTaskGroup group, final NetTask task, final int index)
{
if (UifUtilities.isEDT())
{
taskRemovedEDT(group, task, index);
} else
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
taskRemovedEDT(group, task, index);
}
});
}
}
/**
* Fired when task is removed from the group.
*
* @param group group the task was removed from.
* @param task removed task.
* @param index index of removed task.
*/
private void taskRemovedEDT(NetTaskGroup group, NetTask task, int index)
{
Coordinates coords = getTaskCoordinates(group, task);
if (coords != null)
{
int[] indicies = new int[] { index };
Object[] children = new Object[] { task };
fireTreeNodesRemoved(this, coords.path, indicies, children);
}
}
}
}