/*
* JacORB - a free Java ORB
*
* Copyright (C) 1999-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
package org.jacorb.ir.gui.typesystem;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
/**
* @author Joerg von Frantzius
*/
public class ModelBuilder
implements Runnable, TreeExpansionListener, TreeModelListener
{
private Hashtable threadArguments = new Hashtable();
// (using the Hashtable and the thread name as a key, several
// buildTreeModelAsync() threads are possible)
protected Hashtable expandedModParts = new Hashtable();
// key: DefaultMutableTreeNode
// contains the TreeNodes on whose ModelParticipant expand()
// has already been called and fully processed
protected Hashtable treeViewsToUpdate = new Hashtable();
// key: DefaultMutableTreeNode; value: JTree
protected Hashtable treeNodesAndTableModels = new Hashtable();
// key: TreeNode; value: Vector[TableModel]
// which TableModels belong to a TreeNode
private Hashtable treeModelsListenedTo = new Hashtable();
// key: TreeModel
// on which TreeModels are we registered as a Listener
// (multiple addTreeModelListener() on the same TreeModel
// would result in duplicate Events!)
private static ModelBuilder singleton = new ModelBuilder();
// we need a ModelBuilder instance to be able to start a Thread
// (we would need a class of its own if the methods were static;
// unfortunately VisualAge doesn't support inner classes yet)
/**
* @return javax.swing.tree.TreeModel
*/
public DefaultTreeModel buildTreeModel(ModelParticipant rootModPart)
{
DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootModPart);
DefaultTreeModel treeModel = new DefaultTreeModel(root);
treeModel.setAsksAllowsChildren(true);
rootModPart.buildTree(treeModel,null);
return treeModel;
}
/**
* @return javax.swing.tree.TreeModel
*/
public DefaultTreeModel buildTreeModelAsync(ModelParticipant rootModPart)
{
DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootModPart);
DefaultTreeModel treeModel = new DefaultTreeModel(root);
treeModel.setAsksAllowsChildren(true);
Thread thread = new Thread(this);
threadArguments.put(thread.getName(),treeModel);
// run() entnimmt das Model der Hashtable
thread.start(); // asynchronen Aufbau des TreeModels starten
return treeModel;
}
/**
* Creates a TreeModel that only contains root. In order to expand Nodes,
* the TreeExpansionListener returned by getTreeExpansionListener(treeModel)
* needs to be registered with JTree.
* @return javax.swing.tree.DefaultTreeModel
*/
public DefaultTreeModel createTreeModelRoot(ModelParticipant rootModPart) {
DefaultMutableTreeNode root = new DefaultMutableTreeNode(rootModPart);
DefaultTreeModel treeModel = new DefaultTreeModel(root);
rootModPart.addToParent(treeModel,null);
treeModel.setAsksAllowsChildren(true);
return treeModel;
}
/**
* Dummy only for synchronization purposes
* @param modPart org.jacorb.ir.gui.typesystem.ModelParticipant
*/
private synchronized void expandModPart(ModelParticipant modPart,
DefaultTreeModel treeModel)
{
modPart.expand(treeModel);
return;
}
public static ModelBuilder getSingleton()
{
return singleton;
}
/**
* @return TableModel
*/
public synchronized DefaultTableModel getTableModel(DefaultTreeModel treeModel,
DefaultMutableTreeNode treeNode)
{
DefaultTableModel tableModel = new DefaultTableModel();
java.lang.Object[] colIdentifiers = {"Item","Type","Name"};
tableModel.setColumnIdentifiers(colIdentifiers);
// tableModel.setSortColumn("Name"); // doesn't exist anymore in Swing 0.7
if (treeNode!=null &&
(treeNode.getUserObject() instanceof AbstractContainer))
{
if (!treeModelsListenedTo.containsKey(treeModel)) {
treeModel.addTreeModelListener(this);
treeModelsListenedTo.put(treeModel,treeModel);
}
if (treeNodesAndTableModels.containsKey(treeNode)) {
Vector tableModels = (Vector)treeNodesAndTableModels.get(treeNode);
tableModels.addElement(tableModel);
}
else {
Vector tableModels = new Vector();
tableModels.addElement(tableModel);
treeNodesAndTableModels.put(treeNode,tableModels);
}
if (!expandedModParts.containsKey(treeNode)) {
// need to load subtree first
startExpandNode(treeModel,treeNode);
// we are synchronized, expandModPart() also,
// which is called by the Thread
// => we get all Events that are generated
// when treeModel changes
}
else
{
// alles klar, Unterbaum ist schon da
for (int i=0; i<treeModel.getChildCount(treeNode); i++) {
insertTableRow(tableModel,(DefaultMutableTreeNode)treeNode.getChildAt(i),i);
}
} // if (!expandedModParts.containsKey(treeNode))
} // if (treeNode!=null...)
return tableModel;
}
/**
* @return javax.swing.event.TreeExpansionListener
* @param treeModel javax.swing.tree.DefaultTreeModel
*/
public TreeExpansionListener getTreeExpansionListener(TreeModel treeModel)
{
return this; // treeModel can be ignored
}
/**
* @param tableModel javax.swing.table.DefaultTableModel
* @param treeNode javax.swing.tree.DefaultMutableTreeNode
*/
private void insertTableRow(DefaultTableModel tableModel,
DefaultMutableTreeNode treeNode,
int index)
{
TypeSystemNode typeSystemNode = (TypeSystemNode)treeNode.getUserObject();
String type = "";
if (typeSystemNode instanceof TypeAssociator) {
type = ((TypeAssociator)typeSystemNode).getAssociatedType();
}
java.lang.Object[] row =
{new NodeMapper(typeSystemNode,typeSystemNode.getInstanceNodeTypeName()),
new NodeMapper(typeSystemNode,type),
new NodeMapper(typeSystemNode,typeSystemNode.getName())};
tableModel.insertRow(index,row);
}
/**
*/
public void run ( )
{
Object argument = threadArguments.get(Thread.currentThread().getName());
if (argument instanceof DefaultTreeModel)
{
DefaultTreeModel treeModel = (DefaultTreeModel)argument;
ModelParticipant root =
(ModelParticipant)((DefaultMutableTreeNode)treeModel.getRoot()).getUserObject();
root.buildTree(treeModel,null);
}
if (argument instanceof Object[]) {
Object[] args = (Object[])argument;
DefaultTreeModel treeModel = (DefaultTreeModel)args[0];
ModelParticipant modPart = (ModelParticipant)args[1];
expandModPart(modPart,treeModel);
}
}
/**
* Starts Thread that calls expand() on ModelParticipant of the TreeNode
* @param treeModel javax.swing.tree.DefaultTreeModel
* @param treeNode javax.swing.tree.DefaultMutableTreeNode
*/
private void startExpandNode(DefaultTreeModel treeModel,
DefaultMutableTreeNode treeNode)
{
ModelParticipant modPart = (ModelParticipant)treeNode.getUserObject();
if (!expandedModParts.containsKey(treeNode)) {
System.out.println("expanding node: "+treeNode);
Thread thread = new Thread(this);
Object[] args = new Object[2];
args[0] = treeModel;
args[1] = modPart;
threadArguments.put(thread.getName(),args);
// run() takes the model out of the Hashtable
thread.start(); // start asynchronous expand
// modPart.expand(treeModel);
}
}
/**
* @param e javax.swing.event.TreeExpansionEvent
*/
public void treeCollapsed(TreeExpansionEvent e)
{
return;
}
/**
* @param e javax.swing.event.TreeExpansionEvent
*/
public synchronized void treeExpanded(TreeExpansionEvent e)
{
javax.swing.JTree jTree = (javax.swing.JTree)e.getSource();
DefaultTreeModel treeModel = (DefaultTreeModel)jTree.getModel();
TreePath path = e.getPath();
DefaultMutableTreeNode treeNode =
(DefaultMutableTreeNode)path.getPathComponent(path.getPathCount()-1);
treeViewsToUpdate.put(treeNode,jTree); // deposit TreeView which should display added nodes immediately
startExpandNode(treeModel,treeNode);
}
public void treeNodesChanged(TreeModelEvent te) {}
public void treeNodesInserted(TreeModelEvent te)
{
// System.out.println("treeNodesInserted()");
DefaultMutableTreeNode treeNode =
(DefaultMutableTreeNode)te.getTreePath().getLastPathComponent();
Vector tableModels = (Vector)treeNodesAndTableModels.get(treeNode);
DefaultTableModel tableModel;
int[] indices = te.getChildIndices();
if (tableModels!=null)
{
// else: there are no TableModels for the TreeNode
for (int i=0; i<indices.length; i++) {
for (Enumeration e = tableModels.elements(); e.hasMoreElements(); ) {
tableModel = (DefaultTableModel)e.nextElement();
insertTableRow(tableModel,(DefaultMutableTreeNode)treeNode.getChildAt(indices[i]),indices[i]);
}
}
}
}
public void treeNodesRemoved(TreeModelEvent te) {}
public void treeStructureChanged(TreeModelEvent te) {}
}