/*
* Copyright (c) 2010 The Jackson Laboratory
*
* This 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 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
* along with this software. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jax.maanova.project.gui;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.jax.maanova.fit.FitMaanovaResult;
import org.jax.maanova.madata.MicroarrayExperiment;
import org.jax.maanova.project.MaanovaDataModel;
import org.jax.maanova.project.MaanovaDataModelListener;
import org.jax.maanova.project.MaanovaProject;
import org.jax.maanova.project.MaanovaProjectManager;
import org.jax.maanova.test.MaanovaTestResult;
import org.jax.util.gui.SwingTreeUtilities;
import org.jax.util.project.Project;
import org.jax.util.project.gui.ProjectTree;
/**
* A {@link JTree} that shows the interactive contents of a J/maanova
* project
* @author <A HREF="mailto:keith.sheppard@jax.org">Keith Sheppard</A>
*/
public class MaanovaProjectTree extends ProjectTree
{
/**
* every {@link java.io.Serializable} is supposed to have one of these
*/
private static final long serialVersionUID = 1354914290025074652L;
private MaanovaDataModelListener dataModelListener = new MaanovaDataModelListener()
{
/**
* {@inheritDoc}
*/
public void microarrayExperimentAdded(
MaanovaDataModel source,
MicroarrayExperiment microarrayExperiment)
{
this.changeOccured();
}
/**
* {@inheritDoc}
*/
public void microarrayExperimentRemoved(
MaanovaDataModel source,
MicroarrayExperiment microarrayExperiment)
{
this.changeOccured();
}
private void changeOccured()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
MaanovaProjectTree.this.refreshMicroarrayExperimentNodes();
}
});
}
};
/**
* Constructor
*/
public MaanovaProjectTree()
{
this.getSelectionModel().setSelectionMode(
TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
this.addTreeSelectionListener(new TreeSelectionListener()
{
public void valueChanged(TreeSelectionEvent treeSelectionEvent)
{
MaanovaProjectTree.this.treeSelectionChanged(treeSelectionEvent);
}
});
}
/**
* {@inheritDoc}
*/
@Override
protected void refreshProjectTree()
{
MaanovaProject activeProject =
this.getProjectManager().getActiveProject();
final boolean activeProjectIsRoot;
{
final Object rootObject = this.getModel().getRoot();
if(rootObject instanceof ProjectTreeNode)
{
final ProjectTreeNode root = (ProjectTreeNode)rootObject;
activeProjectIsRoot =
root.getProject() == activeProject;
}
else
{
activeProjectIsRoot = false;
}
}
if(!activeProjectIsRoot)
{
this.getModel().setRoot(new ProjectTreeNode(activeProject));
}
this.refreshMicroarrayExperimentNodes();
}
/**
* {@inheritDoc}
*/
@Override
public MaanovaProject getActiveProject()
{
return (MaanovaProject)super.getActiveProject();
}
/**
* {@inheritDoc}
*/
@Override
public void setActiveProject(Project activeProject)
{
if(activeProject == null)
{
throw new NullPointerException("Project cannot be null");
}
MaanovaProject maanovaActiveProject = (MaanovaProject)activeProject;
{
MaanovaProject oldActiveProject = this.getActiveProject();
if(oldActiveProject != null)
{
oldActiveProject.getDataModel().removeMaanovaDataModelListener(
this.dataModelListener);
}
}
maanovaActiveProject.getDataModel().addMaanovaDataModelListener(
this.dataModelListener);
super.setActiveProject(activeProject);
}
/**
* refresh all of the microarray experiment nodes
*/
private void refreshMicroarrayExperimentNodes()
{
ProjectTreeNode projectNode = (ProjectTreeNode)this.getModel().getRoot();
MaanovaProject project = projectNode.getProject();
MaanovaDataModel dataModel = project.getDataModel();
boolean experimentCountMayHaveChanged = false;
// remove tree nodes not in the MAANOVA data model
for(int microarrayNodeIndex = projectNode.getChildCount() - 1;
microarrayNodeIndex >= 0;
microarrayNodeIndex--)
{
MicroarrayExperimentTreeNode currMicroarrayNode =
(MicroarrayExperimentTreeNode)projectNode.getChildAt(microarrayNodeIndex);
boolean microarrayInDataModel = dataModel.getMicroarrayExperimentMap().containsKey(
currMicroarrayNode.getMicroarrayExperiment().getAccessorExpressionString());
if(!microarrayInDataModel)
{
this.getModel().removeNodeFromParent(
(MutableTreeNode)projectNode.getChildAt(microarrayNodeIndex));
experimentCountMayHaveChanged = true;
}
}
// add nodes that are missing (refresh existing)
for(MicroarrayExperiment currMicroarray: dataModel.getMicroarrayExperimentMap().values())
{
int indexOfMicroarray = SwingTreeUtilities.indexOfChildWithUserObject(
projectNode,
currMicroarray);
MicroarrayExperimentTreeNode currMicroarrayExperimentNode;
if(indexOfMicroarray == -1)
{
// append the microarray to the end of the project node
currMicroarrayExperimentNode = new MicroarrayExperimentTreeNode(currMicroarray);
this.getModel().insertNodeInto(
currMicroarrayExperimentNode,
projectNode,
projectNode.getChildCount());
this.getModel().insertNodeInto(
currMicroarrayExperimentNode.getFitMaanovasTreeNode(),
currMicroarrayExperimentNode,
currMicroarrayExperimentNode.getChildCount());
this.getModel().insertNodeInto(
currMicroarrayExperimentNode.getMaanovaTestsTreeNode(),
currMicroarrayExperimentNode,
currMicroarrayExperimentNode.getChildCount());
this.getModel().insertNodeInto(
currMicroarrayExperimentNode.getGeneListsTreeNode(),
currMicroarrayExperimentNode,
currMicroarrayExperimentNode.getChildCount());
this.expandPath(new TreePath(
currMicroarrayExperimentNode.getPath()));
experimentCountMayHaveChanged = true;
}
else
{
currMicroarrayExperimentNode =
(MicroarrayExperimentTreeNode)projectNode.getChildAt(indexOfMicroarray);
}
this.refreshFitResultsNode(
currMicroarrayExperimentNode.getFitMaanovasTreeNode());
this.refreshTestResultsNode(
currMicroarrayExperimentNode.getMaanovaTestsTreeNode());
this.refreshGeneListsNode(
currMicroarrayExperimentNode.getGeneListsTreeNode());
}
// if the experiment count changes it can cause the project node's
// label to change, so we need to notify
if(experimentCountMayHaveChanged)
{
this.getModel().nodeChanged(projectNode);
}
}
/**
* Refresh the given gene list node
* @param geneListsTreeNode the node to refresh
*/
private void refreshGeneListsNode(GeneListsTreeNode geneListsTreeNode)
{
final MicroarrayExperiment microarrayExperiment =
geneListsTreeNode.getMicroarrayExperiment();
final int childNodeCount = geneListsTreeNode.getChildCount();
final DefaultTreeModel treeModel = this.getModel();
// prune old gene lists and the gene lists to add in the same loop
final List<String> geneListNamesToAdd = microarrayExperiment.getGeneListNames();
for(int i = childNodeCount - 1; i >= 0; i--)
{
GeneListTreeNode geneListNode =
(GeneListTreeNode)geneListsTreeNode.getChildAt(i);
if(!geneListNamesToAdd.remove(geneListNode.getGeneListId()))
{
treeModel.removeNodeFromParent(geneListNode);
}
}
// append the new nodes
for(String geneListName: geneListNamesToAdd)
{
GeneListTreeNode geneListNode = new GeneListTreeNode(
microarrayExperiment,
geneListName);
treeModel.insertNodeInto(
geneListNode,
geneListsTreeNode,
geneListsTreeNode.getChildCount());
}
// update the label (the count may have changed)
treeModel.nodeChanged(geneListsTreeNode);
}
/**
* Refresh the given test node
* @param maanovaTestsTreeNode
* the node to refresh
*/
private void refreshTestResultsNode(
MaanovaTestsTreeNode maanovaTestsTreeNode)
{
final MicroarrayExperiment microarrayExperiment =
maanovaTestsTreeNode.getMicroarrayExperiment();
final int childNodeCount = maanovaTestsTreeNode.getChildCount();
final Set<MaanovaTestResult> testResultsToAdd = new HashSet<MaanovaTestResult>(
microarrayExperiment.getMaanovaTestResults());
final DefaultTreeModel treeModel = this.getModel();
// clean the test results to add and old tree nodes in a single loop
for(int i = childNodeCount - 1; i >= 0; i--)
{
MaanovaTestTreeNode maanovaTestTreeNode =
(MaanovaTestTreeNode)maanovaTestsTreeNode.getChildAt(i);
if(!testResultsToAdd.remove(maanovaTestTreeNode.getMaanovaTestResult()))
{
// remove nodes that no longer belong
treeModel.removeNodeFromParent(maanovaTestTreeNode);
}
}
// append the new nodes
for(MaanovaTestResult testToAdd: testResultsToAdd)
{
treeModel.insertNodeInto(
new MaanovaTestTreeNode(testToAdd),
maanovaTestsTreeNode,
maanovaTestsTreeNode.getChildCount());
}
// update the label (the count may have changed)
treeModel.nodeChanged(maanovaTestsTreeNode);
}
/**
* Refresh the fit results node
* @param fitMaanovasTreeNode
* the node to refresh
*/
private void refreshFitResultsNode(FitMaanovasTreeNode fitMaanovasTreeNode)
{
final MicroarrayExperiment microarrayExperiment =
fitMaanovasTreeNode.getMicroarrayExperiment();
final int childNodeCount = fitMaanovasTreeNode.getChildCount();
final Set<FitMaanovaResult> fitResultsToAdd = new HashSet<FitMaanovaResult>(
microarrayExperiment.getFitMaanovaResults());
final DefaultTreeModel treeModel = this.getModel();
// clean the fit results to add and old tree nodes in a single loop
for(int i = childNodeCount - 1; i >= 0; i--)
{
FitMaanovaTreeNode fitMaanovaTreeNode =
(FitMaanovaTreeNode)fitMaanovasTreeNode.getChildAt(i);
if(!fitResultsToAdd.remove(fitMaanovaTreeNode.getFitMaanovaResult()))
{
// remove nodes that no longer belong
treeModel.removeNodeFromParent(fitMaanovaTreeNode);
}
}
// append the new nodes
for(FitMaanovaResult fitToAdd: fitResultsToAdd)
{
treeModel.insertNodeInto(
new FitMaanovaTreeNode(fitToAdd),
fitMaanovasTreeNode,
fitMaanovasTreeNode.getChildCount());
}
// update the label (the count may have changed)
treeModel.nodeChanged(fitMaanovasTreeNode);
}
/**
* {@inheritDoc}
*/
@Override
public DefaultTreeModel getModel()
{
return (DefaultTreeModel)super.getModel();
}
/**
* {@inheritDoc}
*/
@Override
public MaanovaProjectManager getProjectManager()
{
return (MaanovaProjectManager)super.getProjectManager();
}
/**
* Respond to a tree selection event
* @param treeSelectionEvent
* the event we're responding to
*/
private void treeSelectionChanged(TreeSelectionEvent treeSelectionEvent)
{
// TODO implement me
}
}