/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.transformation.ui.part;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.FanRouter;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.IFigure;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.Request;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
import org.teiid.designer.diagram.ui.DiagramUiConstants;
import org.teiid.designer.diagram.ui.DiagramUiPlugin;
import org.teiid.designer.diagram.ui.actions.ScaledFontManager;
import org.teiid.designer.diagram.ui.connection.NodeConnectionEditPart;
import org.teiid.designer.diagram.ui.connection.NodeConnectionModel;
import org.teiid.designer.diagram.ui.layout.DefaultLayoutNode;
import org.teiid.designer.diagram.ui.layout.LayoutGroup;
import org.teiid.designer.diagram.ui.layout.LayoutHelper;
import org.teiid.designer.diagram.ui.layout.LayoutNode;
import org.teiid.designer.diagram.ui.layout.LayoutUtilities;
import org.teiid.designer.diagram.ui.layout.MmTreeLayout;
import org.teiid.designer.diagram.ui.layout.TreeLayout;
import org.teiid.designer.diagram.ui.layout.spring.SpringLayout;
import org.teiid.designer.diagram.ui.model.AbstractFreeDiagramModelNode;
import org.teiid.designer.diagram.ui.model.DiagramModelNode;
import org.teiid.designer.diagram.ui.part.AbstractDefaultEditPart;
import org.teiid.designer.diagram.ui.part.AbstractDiagramEditPart;
import org.teiid.designer.diagram.ui.part.AbstractFreeEditPart;
import org.teiid.designer.diagram.ui.part.DiagramEditPart;
import org.teiid.designer.diagram.ui.util.DiagramUiUtilities;
import org.teiid.designer.diagram.ui.util.DiagramXYLayoutEditPolicy;
import org.teiid.designer.diagram.ui.util.LassoDragTracker;
import org.teiid.designer.metamodels.diagram.Diagram;
import org.teiid.designer.transformation.ui.PluginConstants;
import org.teiid.designer.ui.IDiagramTypeEditPart;
import org.teiid.designer.ui.common.graphics.GlobalUiColorManager;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.query.ui.UiConstants;
import org.teiid.query.ui.UiPlugin;
/**
* TransformationDiagramEditPart
*
* @since 8.0
*/
public class TransformationDiagramEditPart extends AbstractDiagramEditPart
implements IPropertyChangeListener,
IDiagramTypeEditPart {
/** Singleton instance of MarqueeDragTracker. */
static DragTracker m_dragTracker = null;
private boolean isDependencyDiagram = false;
private TransformationDiagramLayout diagramLayout = new TransformationDiagramLayout();
private String sCurrentRouterStyle = DiagramUiConstants.DiagramRouterStyles.FAN_ROUTER;
/**
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
**/
@Override
protected IFigure createFigure() {
Figure newFigure = getFigureFactory().createFigure(getModel());
setCurrentDiagramFont(ScaledFontManager.getFont());
// Set dependency diagram boolean if necessary.
if( getDiagramType() != null &&
getDiagramType().equals(PluginConstants.DEPENDENCY_DIAGRAM_TYPE_ID) )
isDependencyDiagram = true;
return newFigure;
}
private String getDiagramType() {
return ((Diagram)((DiagramModelNode)getModel()).getModelObject()).getType();
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#createEditPolicies()
* You need to tell how children nodes will be layed out...
**/
@Override
protected void createEditPolicies() {
setSelectablePart(false);
installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramXYLayoutEditPolicy());
}
/**
* This method is not mandatory to implement, but if you do not implement
* it, you will not have the ability to rectangle-selects several figures...
**/
@Override
public DragTracker getDragTracker(Request req) {
// Unlike in Logical Diagram Editor example, I use a singleton because this
// method is Entered >> several time, so I prefer to save memory ; and it works!
if (m_dragTracker == null) {
m_dragTracker = new LassoDragTracker();
}
return m_dragTracker;
}
private boolean hasChildren() {
if( getViewer().getContents().getChildren().size() > 0 )
return true;
return false;
}
/* (non-JavaDoc)
* @see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
**/
@Override
public void propertyChange(PropertyChangeEvent evt) {
super.propertyChange(evt);
String prop = evt.getPropertyName();
if (prop.equals(DiagramUiConstants.DiagramNodeProperties.CHILDREN)) {
layout();
}
if (prop.equals(DiagramUiConstants.DiagramNodeProperties.LAYOUT)) {
layout();
}
}
/**
* @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
* @since 5.0
*/
@Override
public void propertyChange(org.eclipse.jface.util.PropertyChangeEvent theEvent) {
if (theEvent.getProperty().equals(UiConstants.Prefs.TREE_DIAGRAM_LAYOUT)) {
// We need to re-open the diagram to fully re-draw and layout.
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
ModelEditorManager.open(getModelObject(), true);
}
});
// now we need to re-layout the diagram
}
}
@Override
public void layout(boolean layoutChildren) {
if( !hasChildren() )
return;
if( layoutChildren) {
EditPart canvasEditPart = getViewer().getContents();
List canvasChildren = canvasEditPart.getChildren();
Iterator iter = canvasChildren.iterator();
EditPart nextEditPart = null;
while (iter.hasNext()) {
nextEditPart = (EditPart)iter.next();
if ( nextEditPart instanceof DiagramEditPart ) {
((DiagramEditPart)nextEditPart).layout(layoutChildren);
}
}
}
// super.layout(layoutChildren);
// Check it's model node, if was layed out, don't re-layout!!
if( !((DiagramModelNode)getModel()).wasLayedOut() || isDependencyDiagram ) {
layout();
} else {
((DiagramModelNode)getModel()).recoverObjectProperties();
}
// now process the Association Labels, if any:
List arylSourceConnections = new ArrayList();
if ( !arylSourceConnections.isEmpty() ) {
Iterator itSourceConns = arylSourceConnections.iterator();
while( itSourceConns.hasNext() ) {
NodeConnectionModel ncmSourceConn = (NodeConnectionModel)itSourceConns.next();
ncmSourceConn.setRouterStyle( sCurrentRouterStyle );
ncmSourceConn.layout();
}
}
}
@Override
public void layout() {
if( !hasChildren() )
return;
if( getDiagramType() != null &&
getDiagramType().equals(PluginConstants.DEPENDENCY_DIAGRAM_TYPE_ID) ) {
runDependencyLayout();
} else {
// Let's just use the TransformationDiagramLayout here and not the manager.
diagramLayout.setDiagramNode((DiagramModelNode)getModel());
diagramLayout.run();
this.getFigure().repaint();
}
// Update Anchors and Links
updateAnchorsAndLinks();
}
private void runDependencyLayout() {
EObject primaryVG = ((Diagram)((DiagramModelNode)getModel()).getModelObject()).getTarget();
DiagramModelNode vgDiagramNode = DiagramUiUtilities.getDiagramModelNode(primaryVG, (DiagramModelNode)getModel());
// Now let's create a layoutGroup with only TNodes and Tables
List tNodesAndTables = new ArrayList();
List allChildren = ((DiagramModelNode)getModel()).getChildren();
Iterator iter = allChildren.iterator();
Object nextNode = null;
while (iter.hasNext()) {
nextNode = iter.next();
if ( nextNode instanceof DiagramModelNode && !(nextNode instanceof AbstractFreeDiagramModelNode)) {
// Add each component (table or transformation) to the layout manager.
tNodesAndTables.add( nextNode );
}
}
LayoutGroup layoutGroup = new LayoutGroup(tNodesAndTables);
if( layoutGroup.getType() == LayoutHelper.SIMPLE_LAYOUT ) {
LayoutNode rootNode = new DefaultLayoutNode(vgDiagramNode);
// LayoutUtilities.runTreeLayout(layoutGroup, rootNode);
TreeLayout layout = new TreeLayout(layoutGroup.getLayoutNodes(), 10, 10, 400, 400);
layout.setRoot(rootNode);
layout.setOrientation(MmTreeLayout.ORIENTATION_ROOT_LEFT);
layout.setFixedSpacing(true);
layout.setFixedXSpacing(100);
layout.setFixedYSpacing(100);
layout.setUseObjectsSizes(true);
layout.run();
layoutGroup.setFinalPositions();
} else {
// Use Spring Layout here
LayoutUtilities.runColumnLayout(layoutGroup, 20);
SpringLayout layout = new SpringLayout(layoutGroup.getLayoutNodes());
layout.setAutoEdgeLength(true);
layout.setStartLocation(20, 20);
layout.setAutomaticSingleSpacing(true);
layout.setSpecifyLayoutSize(true);
layout.setEpsilon(.2);
layout.setHorizontalAlignment(SpringLayout.LEFT_ALIGNMENT);
layout.setUseObjectsSizes(false);
layout.setVerticalAlignment(SpringLayout.TOP_ALIGNMENT);
layout.setXSpacing(400);
layout.setYSpacing(400);
int size = (int)layout.getSizeEstimate();
layout.setLayoutSize(size*2);
layout.run();
layoutGroup.setFinalPositions();
}
}
private void updateAnchorsAndLinks() {
EditPart canvasEditPart = getViewer().getContents();
List canvasChildren = canvasEditPart.getChildren();
Iterator iter = canvasChildren.iterator();
EditPart nextEditPart = null;
while (iter.hasNext()) {
nextEditPart = (EditPart)iter.next();
if ( nextEditPart instanceof DiagramEditPart && ! (nextEditPart instanceof AbstractFreeEditPart )) {
((DiagramEditPart)nextEditPart).createOrUpdateAnchorsLocations(false);
((AbstractDefaultEditPart)nextEditPart).refreshAllLabels();
}
}
}
public boolean hasConnections() {
EditPart canvasEditPart = getViewer().getContents();
Iterator iter = canvasEditPart.getChildren().iterator();
DiagramEditPart nextEditPart = null;
while (iter.hasNext()) {
nextEditPart = (DiagramEditPart)iter.next();
if( !nextEditPart.getSourceConnections().isEmpty() ||
!nextEditPart.getTargetConnections().isEmpty() )
return true;
}
return false;
}
/**
* Reset font from Font Managar and call layout on all diagram objects.
**/
@Override
public void refreshFont(boolean refreshChildren) {
// Diagram needs to also do a layout here
super.refreshFont(refreshChildren);
// But not at the diagram level
if( hasChildren()) {
EditPart canvasEditPart = getViewer().getContents();
List canvasChildren = canvasEditPart.getChildren();
Iterator iter = canvasChildren.iterator();
EditPart nextEditPart = null;
while (iter.hasNext()) {
nextEditPart = (EditPart)iter.next();
if ( nextEditPart instanceof DiagramEditPart ) {
((DiagramEditPart)nextEditPart).layout(true);
}
}
}
}
/**
* @see org.eclipse.gef.editparts.AbstractEditPart#refreshVisuals()
**/
@Override
protected void refreshVisuals() {
ConnectionLayer cLayer = (ConnectionLayer)getLayer(LayerConstants.CONNECTION_LAYER);
if ( sCurrentRouterStyle.equals( DiagramUiConstants.DiagramRouterStyles.FAN_ROUTER ) ) {
cLayer.setConnectionRouter(new FanRouter());
}
}
public DiagramEditPart getTransformEditPart() {
EditPart canvasEditPart = getViewer().getContents();
Iterator iter = canvasEditPart.getChildren().iterator();
DiagramEditPart nextEditPart = null;
while (iter.hasNext()) {
nextEditPart = (DiagramEditPart)iter.next();
if( nextEditPart instanceof TransformationEditPart )
return nextEditPart;
}
return null;
}
public DiagramModelNode getTargetOfTransform() {
DiagramModelNode targetGroupNode = null;
// get TransformDiagramNode.
DiagramEditPart transformEP = getTransformEditPart();
if( transformEP != null ) {
// get it's source connections.
List sourceConnections = transformEP.getSourceConnections();
// get the "targetNode" on this connection.
if( sourceConnections.size() == 1 ) {
NodeConnectionEditPart sourceConnection = (NodeConnectionEditPart)sourceConnections.iterator().next();
targetGroupNode = (DiagramModelNode)((NodeConnectionModel)sourceConnection.getModel()).getTargetNode();
}
}
return targetGroupNode;
}
@Override
public void updateForPreferences() {
RGB currentBkgdColor;
if (isDependencyDiagram) {
// dependency diagram:
currentBkgdColor = PreferenceConverter.getColor(
DiagramUiPlugin.getDefault().getPreferenceStore(),
PluginConstants.Prefs.Appearance.DEPENDENCY_BKGD_COLOR);
} else {
// regular transformation diagram:
currentBkgdColor = PreferenceConverter.getColor(
DiagramUiPlugin.getDefault().getPreferenceStore(),
PluginConstants.Prefs.Appearance.TRANSFORM_BKGD_COLOR);
} // endif
this.getFigure().setBackgroundColor(GlobalUiColorManager.getColor(currentBkgdColor));
refreshFont(true);
layout(false);
}
/**
* @see org.teiid.designer.diagram.ui.part.AbstractDefaultEditPart#activate()
* @since 5.0
*/
@Override
public void activate() {
super.activate();
UiPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
}
/**
* @see org.teiid.designer.diagram.ui.part.AbstractDefaultEditPart#deactivate()
* @since 5.0
*/
@Override
public void deactivate() {
super.deactivate();
UiPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
}
}