/**
* @file: InfoExplorer2Implementation.java
* @author: tlc
* @date: 2006-12-9
* @version: 1.0.0
*/
package de.FeatureModellingTool.InfoExplorer2;
import java.awt.Component;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeModelEvent;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeSelectionModel;
import org.jdesktop.swingx.JXTreeTable;
import applet.WebConstantDefinition;
import de.FeatureModellingTool.FeatureModel.CFRelation;
import de.FeatureModellingTool.FeatureModel.Constraint;
import de.FeatureModellingTool.FeatureModel.ConstraintModel;
import de.FeatureModellingTool.FeatureModel.ConstraintModelProperties;
import de.FeatureModellingTool.FeatureModel.Feature;
import de.FeatureModellingTool.FeatureModel.FeatureModel;
import de.FeatureModellingTool.FeatureModel.FeatureModelProperties;
import de.FeatureModellingTool.FeatureModel.FeatureRelation;
import de.FeatureModellingTool.FeatureModel.VPConstraint;
import de.FeatureModellingTool.InfoExplorer.ConstantDefinition;
import de.reuse.Context;
import de.reuse.ContextImplementation;
import javax.swing.JTable;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeModelListener;
/**
* @author tlc
*/
public class InfoExplorer2Implementation extends JScrollPane implements InfoExplorer2, InfoExplorer2UI, ConstantDefinition {
private JXTreeTable treeTable = null;
private FeatureTreeTableModel treeTableModel = null;
protected FeatureModel featureModel = null;
protected ConstraintModel constraintModel = null;
protected final FeatureModelPropertyChangeListener featureModelPropertyChangeListener = new FeatureModelPropertyChangeListener();
protected final ConstraintModelPropertyChangeListener constraintModelPropertyChangeListener = new ConstraintModelPropertyChangeListener();
protected final ContextImplementation context = new ContextImplementation();
public static final String ID_VIRTUAL_ROOT = "id-virtual-root";
public InfoExplorer2Implementation() {
FeatureNode root = new FeatureNode(context, FeatureNode.NODE_TYPE_ROOT);
treeTableModel = new FeatureTreeTableModel(root);
treeTable = new JXTreeTable(treeTableModel);
treeTable.setTreeCellRenderer(new FeatureTreeCellRender());
treeTable.setRootVisible(true);
treeTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
treeTableModel.addTreeModelListener(new TreeModelListener() {
public void treeNodesChanged(TreeModelEvent e) {
treeTable.packAll();
}
public void treeNodesInserted(TreeModelEvent e) {
treeTable.packAll();
}
public void treeNodesRemoved(TreeModelEvent e) {
treeTable.packAll();
}
@Override
public void treeStructureChanged(TreeModelEvent e) {
treeTable.packAll();
}
});
treeTable.addTreeExpansionListener(new TreeExpansionListener() {
@Override
public void treeExpanded(TreeExpansionEvent event) {
treeTable.packAll();
}
@Override
public void treeCollapsed(TreeExpansionEvent event) {
treeTable.packAll();
}
});
//treeTable.getColumn(4).setCellRenderer(new TextPaneCellRenderer());
context.addContextChangeListener(new ContextChangeListener());
context.getMVContext().addContextChangeListener(new MVContextChangeListener());
}
protected class ContextChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent e) {
contextChange(e);
}
}
@Override
public Context getContext() {
return context;
}
public JComponent getExplorerComponent() {
return treeTable;
}
protected class MVContextChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent e) {
mvContextChange(e);
}
}
protected void contextChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if (FEATURE_MODEL.equals(propertyName)) {
if (featureModel != null) {
featureModel.removePropertyChangeListener(featureModelPropertyChangeListener);
}
featureModel = (FeatureModel) e.getNewValue();
if (featureModel != null) {
featureModel.addPropertyChangeListener(featureModelPropertyChangeListener);
}
} else if (CONSTRAINT_MODEL.equals(propertyName)) {
if (constraintModel != null) {
constraintModel.removePropertyChangeListener(constraintModelPropertyChangeListener);
}
constraintModel = (ConstraintModel) e.getNewValue();
if (constraintModel != null) {
constraintModel.addPropertyChangeListener(constraintModelPropertyChangeListener);
}
}
if (featureModel != null && constraintModel != null) {
createTreeTableModel();
///--��ʾ�ڵ�������
treeTable.putClientProperty("JTree.lineStyle", "Angled");
treeTable.setColumnControlVisible(true);
treeTable.setRolloverEnabled(true);
treeTable.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
}
}
protected void mvContextChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
if (MOUSE_LISTENER.equals(propertyName)) {
Object value;
MouseListener mouseListener;
value = e.getOldValue();
if (value != null) {
mouseListener = (MouseListener) value;
treeTable.removeMouseListener(mouseListener);
}
value = e.getNewValue();
if (value != null) {
mouseListener = (MouseListener) value;
treeTable.addMouseListener(mouseListener);
}
}
}
protected class FeatureModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
FeatureNode root = (FeatureNode) treeTable.getTreeTableModel().getRoot();
Map<String, String> refineRelation = new TreeMap<String, String>();
refineRelation.put(FeatureRelation.DECOMPOSE, "decompose");
refineRelation.put(FeatureRelation.ATTRIBUTE, "attribute");
Object evtSource = evt.getSource();
if (Feature.class.isInstance(evtSource)) {
Feature feature = (Feature) evtSource;
FeatureNode featureNode = getTreeNode(root, feature);
treeTable.repaint();
} else if (FeatureModel.class.isInstance(evtSource)) {
if (propertyName.equals(FeatureModelProperties.FEATURE_ADDED)) {
Feature feature = (Feature) evt.getNewValue();
FeatureNode featureNode = new FeatureNode(context, feature);
//root.add(featureNode);
treeTableModel.insertNodeInto(featureNode, root, root.getChildCount());
} else if (propertyName.equals(FeatureModelProperties.FEATURE_REMOVED)) {
//--ɾ��һ���ڵ㣺�Ӹ��ڵ���ɾ���ýڵ㣬�����ýڵ�������ӽڵ���Ϊ���ڵ�
///---�����ڵ㣨��ϵ�ڵ㣩���ٰ��������ڵ㣬��ɾ�����ڵ�
Feature feature = (Feature) evt.getOldValue();
FeatureNode featureNode = getTreeNode(root, feature);
FeatureNode parent = (FeatureNode) featureNode.getParent();
//int index = parent.getIndex(featureNode);
//parent.remove(featureNode);
treeTableModel.removeNodeFromParent(featureNode);
List<FeatureNode> children = new ArrayList<FeatureNode>();
Enumeration e = featureNode.children();
while (e.hasMoreElements()) { //--���������ォchild��ӵ�root,��������e��ʹ�ñ����������ȷ
FeatureNode child = (FeatureNode) e.nextElement();
children.add(child);
}
Iterator<FeatureNode> it = children.iterator();
while (it.hasNext()) {
FeatureNode child = it.next();
//root.add(child);
treeTableModel.insertNodeInto(child, root, root.getChildCount());
}
boolean bHasMoreChildren = parent.children().hasMoreElements();
if (!bHasMoreChildren) {
//FeatureNode grandParent = (FeatureNode) parent.getParent();
//grandParent.remove(parent);
treeTableModel.removeNodeFromParent(parent);
}
} else if (propertyName.equals(FeatureModelProperties.RELATION_ADDED)) {
//--��������˾�����ϵ����endNode��ΪstartNode�����ӽڵ㣬�м���Ϲ�ϵ�ڵ�
FeatureRelation fr = (FeatureRelation) evt.getNewValue();
String relationName = fr.getName();
if (refineRelation.containsKey(relationName)) {
Feature start = fr.getStartFeature();
Feature end = fr.getEndFeature();
FeatureNode startNode = getTreeNode(root, start);
FeatureNode endNode = getTreeNode(root, end);
if (relationName.equals(FeatureRelation.DECOMPOSE)) {
FeatureNode compNode = startNode.getCompositionNode();
if (compNode == null) {
compNode = new FeatureNode(context, FeatureNode.NODE_TYPE_COMPOSITION);
//startNode.add(compNode);
treeTableModel.insertNodeInto(compNode, startNode, startNode.getChildCount());
}
//compNode.add(endNode);
treeTableModel.removeNodeFromParent(endNode);
treeTableModel.insertNodeInto(endNode, compNode, compNode.getChildCount());
} else if (relationName.equals(FeatureRelation.ATTRIBUTE)) {
FeatureNode compNode = startNode.getCharacterizationNode();
if (compNode == null) {
compNode = new FeatureNode(context, FeatureNode.NODE_TYPE_CHARACTERIZATION);
//startNode.add(compNode);
treeTableModel.insertNodeInto(compNode, startNode, startNode.getChildCount());
}
//compNode.add(endNode);
treeTableModel.removeNodeFromParent(endNode);
treeTableModel.insertNodeInto(endNode, compNode, compNode.getChildCount());
}
}
} else if (propertyName.equals(FeatureModelProperties.RELATION_REMOVED)) {
//--���ɾ���˾�����ϵ����endNode��Ϊroot, ���endNode�ĸ��ڵ�(��ϵ�ڵ㣩û�������ӽڵ��ˣ���ɾ��endNode�ĸ��ڵ�
FeatureRelation fr = (FeatureRelation) evt.getOldValue();
String relationName = fr.getName();
if (refineRelation.containsKey(relationName)) {
Feature start = fr.getStartFeature();
Feature end = fr.getEndFeature();
FeatureNode startNode = getTreeNode(root, start);
FeatureNode endNode = getTreeNode(root, end);
FeatureNode relationNode = (FeatureNode) endNode.getParent();
//root.add(endNode);
treeTableModel.removeNodeFromParent(endNode);
treeTableModel.insertNodeInto(endNode, root, root.getChildCount());
boolean bHasMoreChildren = relationNode.children().hasMoreElements();
if (!bHasMoreChildren) {
//FeatureNode grandParent = (FeatureNode) relationNode.getParent();
//grandParent.remove(relationNode);
treeTableModel.removeNodeFromParent(relationNode);
}
}
}
}
//treeTable.updateUI();
}
}
protected class ConstraintModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
FeatureNode root = (FeatureNode) treeTable.getTreeTableModel().getRoot();
if (propertyName.equals(ConstraintModelProperties.RELATION_ADDED)) {
//--���������VPConstraint�ϵĹ�ϵ��
CFRelation relation = (CFRelation) evt.getNewValue();
Constraint constraint = relation.getConstraint();
if (constraint instanceof VPConstraint) {
VPConstraint vpc = (VPConstraint) constraint;
Feature feature = relation.getFeature();
FeatureNode featureNode = getTreeNode(root, feature);
boolean isSource = relation.isSource();
if (isSource) { //--������source��ϵ: ���е�sink��Ϊsource���ӽڵ�
Iterator<Feature> it = vpc.getSinkFeatureSet().iterator();
while (it.hasNext()) {
Feature sink = it.next();
FeatureNode child = getTreeNode(root, sink);
///---���û��һ�������ϵ�Ľڵ㣬������һ�������Ľڵ�
FeatureNode specNode = featureNode.getSpecilizationNode();
if (specNode == null) {
specNode = new FeatureNode(context, FeatureNode.NODE_TYPE_SPECILIZATION);
//featureNode.add(specNode);
treeTableModel.insertNodeInto(specNode, featureNode, featureNode.getChildCount());
}
//specNode.add(child);
treeTableModel.removeNodeFromParent(child);
treeTableModel.insertNodeInto(child, specNode, specNode.getChildCount());
}
} else { //--������sink��ϵ: ������sink��Ϊsource��specNode���ӽڵ�
Iterator<Feature> it = vpc.getSourceFeatureSet().iterator();
if (it.hasNext()) {
Feature source = it.next();
FeatureNode parent = getTreeNode(root, source);
FeatureNode specNode = parent.getSpecilizationNode();
if (specNode == null) {
specNode = new FeatureNode(context, FeatureNode.NODE_TYPE_SPECILIZATION);
//parent.add(specNode);
treeTableModel.insertNodeInto(specNode, parent, parent.getChildCount());
}
//specNode.add(featureNode);
treeTableModel.removeNodeFromParent(featureNode);
treeTableModel.insertNodeInto(featureNode, specNode, specNode.getChildCount());
}
}
}
} else if (propertyName.equals(ConstraintModelProperties.RELATION_REMOVED)) {
//--���������VPConstraint�ϵĹ�ϵ��
CFRelation relation = (CFRelation) evt.getOldValue();
Constraint constraint = relation.getConstraint();
if (constraint instanceof VPConstraint) {
VPConstraint vpc = (VPConstraint) constraint;
Feature feature = relation.getFeature();
FeatureNode featureNode = getTreeNode(root, feature);
boolean isSource = relation.isSource();
if (isSource) { //--ɾ����source��ϵ: ���е�sink��Ϊ���ڵ㣬��������������Ƿ�ɾ��������ϵ�ڵ�
Iterator<Feature> it = vpc.getSinkFeatureSet().iterator();
FeatureNode specNode = null;
while (it.hasNext()) {
Feature sink = it.next();
FeatureNode sinkNode = getTreeNode(root, sink);
specNode = (FeatureNode) sinkNode.getParent();
//root.add(sinkNode);
treeTableModel.insertNodeInto(sinkNode, root, root.getChildCount());
}
if (specNode != null) {
boolean bHasMoreChildren = specNode.children().hasMoreElements();
if (!bHasMoreChildren) {
//featureNode.remove(specNode);
treeTableModel.removeNodeFromParent(specNode);
}
}
} else { //--ɾ����sink��ϵ����sink�ڵ���Ϊ���ڵ㣬���specNodeû�������ӽڵ��ˣ���ɾ��specNode
FeatureNode specNode = (FeatureNode) featureNode.getParent();
//root.add(featureNode);
treeTableModel.removeNodeFromParent(featureNode);
treeTableModel.insertNodeInto(featureNode, root, root.getChildCount());
boolean bHasMoreChildren = specNode.children().hasMoreElements();
if (!bHasMoreChildren) {
//FeatureNode sourceNode = (FeatureNode) specNode.getParent();
//sourceNode.remove(specNode);
treeTableModel.removeNodeFromParent(specNode);
}
}
}
}
//treeTable.updateUI();
}
}
private void createTreeTableModel() {
FeatureNode root = (FeatureNode) treeTableModel.getRoot();
List<FeatureNode> children = root.createChildren();
Iterator<FeatureNode> it = children.iterator();
while (it.hasNext()) { //--û�д�������������
FeatureNode child = it.next();
//root.add(child);
treeTableModel.insertNodeInto(child, root, root.getChildCount());
addNode(child);
}
return;
}
private void addNode(FeatureNode node) {
FeatureNode compositionNode = new FeatureNode(context, FeatureNode.NODE_TYPE_COMPOSITION);
boolean compositionAdded = false;
List<FeatureNode> childrenComposition = node.createChildrenByComposition();
Iterator<FeatureNode> it = childrenComposition.iterator();
while (it.hasNext()) {
if (!compositionAdded) {
//node.add(compositionNode);
treeTableModel.insertNodeInto(compositionNode, node, node.getChildCount());
compositionAdded = true;
}
FeatureNode child = it.next();
//compositionNode.add(child);
treeTableModel.insertNodeInto(child, compositionNode, compositionNode.getChildCount());
addNode(child);
}
FeatureNode specilizationNode = new FeatureNode(context, FeatureNode.NODE_TYPE_SPECILIZATION);
boolean specAdded = false;
childrenComposition = node.createChildrenBySpecilization();
it = childrenComposition.iterator();
while (it.hasNext()) {
if (!specAdded) {
//node.add(specilizationNode);
treeTableModel.insertNodeInto(specilizationNode, node, node.getChildCount());
specAdded = true;
}
FeatureNode child = it.next();
//specilizationNode.add(child);
treeTableModel.insertNodeInto(child, specilizationNode, specilizationNode.getChildCount());
addNode(child);
}
FeatureNode characterizationNode = new FeatureNode(context, FeatureNode.NODE_TYPE_CHARACTERIZATION);
boolean charAdded = false;
childrenComposition = node.createChildrenByCharacterization();
it = childrenComposition.iterator();
while (it.hasNext()) {
if (!charAdded) {
//node.add(characterizationNode);
treeTableModel.insertNodeInto(characterizationNode, node, node.getChildCount());
charAdded = true;
}
FeatureNode child = it.next();
//characterizationNode.add(child);
treeTableModel.insertNodeInto(child, characterizationNode, characterizationNode.getChildCount());
addNode(child);
}
}
//--�˴�Ҫȡ����treeTable�ϵĽڵ㣬Ӧ����root.children(); ��������root.createChildren()
//--�����Ǵ�featureModel�������ӽڵ㡣
private FeatureNode getTreeNode(FeatureNode root, Feature feature) {
if (root == null || feature == null) {
return null;
}
Enumeration e = root.children();
while (e.hasMoreElements()) {
FeatureNode featureNode = (FeatureNode) e.nextElement();
if (featureNode.getFeature() == feature) {
return featureNode;
}
featureNode = getTreeNode(featureNode, feature);
if (featureNode != null) {
return featureNode;
}
}
return null;
}
class FeatureTreeCellRender extends DefaultTreeCellRenderer {
private Icon featureIcon = null;
private Icon compositionIcon = null;
private Icon specilizationIcon = null;
private Icon characterizationIcon = null;
public FeatureTreeCellRender() {
try{
featureIcon = new ImageIcon(new URL(WebConstantDefinition.RES_HOST+"feature.png"));
compositionIcon = new ImageIcon(new URL(WebConstantDefinition.RES_HOST+"composition.png"));
specilizationIcon = new ImageIcon(new URL(WebConstantDefinition.RES_HOST+"specilization.png"));
characterizationIcon = new ImageIcon(new URL(WebConstantDefinition.RES_HOST+"characterization.png"));
}catch(Exception e){
e.printStackTrace();
}
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
Component comp = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
FeatureNode node = (FeatureNode) value;
String nodeType = node.getNodeType();
if (nodeType.equals(FeatureNode.NODE_TYPE_NORMAL)) {
setIcon(featureIcon);
} else if (nodeType.equals(FeatureNode.NODE_TYPE_COMPOSITION)) {
setIcon(compositionIcon);
} else if (nodeType.equals(FeatureNode.NODE_TYPE_SPECILIZATION)) {
setIcon(specilizationIcon);
} else if (nodeType.equals(FeatureNode.NODE_TYPE_CHARACTERIZATION)) {
setIcon(characterizationIcon);
}
return comp;
}
}
}