/*******************************************************************************
* Copyright (c) 2013 hangum.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* hangum - initial API and implementation
******************************************************************************/
package com.hangum.tadpole.rdb.erd.core.actions;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.graph.DirectedGraph;
import org.eclipse.draw2d.graph.DirectedGraphLayout;
import org.eclipse.draw2d.graph.Edge;
import org.eclipse.draw2d.graph.EdgeList;
import org.eclipse.draw2d.graph.Node;
import org.eclipse.draw2d.graph.NodeList;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gef.ui.actions.SelectionAction;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import com.hangum.tadpole.commons.exception.dialog.ExceptionDetailsErrorDialog;
import com.hangum.tadpole.commons.libs.core.message.CommonMessages;
import com.hangum.tadpole.rdb.erd.core.Messages;
import com.hangum.tadpole.rdb.erd.core.part.RelationEditPart;
import com.hangum.tadpole.rdb.erd.core.part.TableEditPart;
import com.hangum.tadpole.rdb.erd.stanalone.Activator;
import com.hangum.tadpole.rdb.model.Relation;
import com.hangum.tadpole.rdb.model.Table;
import com.swtdesigner.ResourceManager;
/**
* autolayout action
*
* @author hangum
*
*/
public class AutoLayoutAction extends SelectionAction {
public static final String ID = "com.hangum.tadpole.erd.core.actions.AutoLayoutAction"; //$NON-NLS-1$
private static final Logger logger = Logger.getLogger(AutoLayoutAction.class);
private GraphicalViewer viewer;
public AutoLayoutAction(IWorkbenchPart part, GraphicalViewer graphicalViewer) {
super(part);
setLazyEnablementCalculation(false);
this.viewer = graphicalViewer;
}
@Override
protected void init() {
setText(Messages.get().AutoLayoutAction_0);
setToolTipText(Messages.get().AutoLayoutAction_0);
setId(ID);
setImageDescriptor( ResourceManager.getPluginImageDescriptor(Activator.PLUGIN_ID, "resources/icons/layout_info.png"));
setEnabled(true);
}
@Override
protected boolean calculateEnabled() {
return true;
}
public GraphicalViewer getViewer() {
return viewer;
}
@Override
public void run() {
try {
CompoundCommand commands = new CompoundCommand();
List models = getViewer().getContents().getChildren();
NodeList graphNodes = new NodeList();
EdgeList graphEdges = new EdgeList();
// nodes
for(int i=0;i<models.size();i++){
Object obj = models.get(i);
if(obj instanceof TableEditPart){
TableEditPart editPart = (TableEditPart) obj;
Table model = (Table) editPart.getModel();
EntityNode node = new EntityNode();
node.model = model;
node.width = editPart.getFigure().getSize().width;
node.height = editPart.getFigure().getSize().height + 40;
graphNodes.add(node);
}
}
// edge
for (int i = 0; i < models.size(); i++) {
Object obj = models.get(i);
if(obj instanceof TableEditPart){
TableEditPart tableEditpart = (TableEditPart) obj;
List outgoing = tableEditpart.getSourceConnections();
for (int j = 0; j < outgoing.size(); j++) {
RelationEditPart conn = (RelationEditPart) outgoing.get(j);
EntityNode source = (EntityNode) getNode(graphNodes, (Table)conn.getSource().getModel());
EntityNode target = (EntityNode) getNode(graphNodes, (Table)conn.getTarget().getModel());
if(source != null && target != null){
ConnectionEdge edge = new ConnectionEdge(source, target);
Relation relation = (Relation)conn.getModel();
edge.model = relation.getSource();
graphEdges.add(edge);
}
}
}
}
DirectedGraph graph = new DirectedGraph();
graph.nodes = graphNodes;
graph.edges = graphEdges;
new DirectedGraphLayout().visit(graph);
for (int i = 0; i < graph.nodes.size(); i++) {
EntityNode node = (EntityNode) graph.nodes.getNode(i);
commands.add(new LayoutCommand(node.model, node.x+10, node.y+10));
}
getViewer().getEditDomain().getCommandStack().execute(commands);
} catch(Exception e) {
logger.error(Messages.get().AutoLayoutAction_2, e);
Status errStatus = new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e); //$NON-NLS-1$
ExceptionDetailsErrorDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),CommonMessages.get().Error, Messages.get().AutoLayoutAction_3, errStatus); //$NON-NLS-1$
}
}
private static EntityNode getNode(NodeList list, Table model){
for(int i=0;i<list.size();i++){
EntityNode node = (EntityNode) list.get(i);
if(node.model == model){
return node;
}
}
return null;
}
private class EntityNode extends Node {
private Table model;
}
private class ConnectionEdge extends Edge {
private Table model;
public ConnectionEdge(EntityNode source, EntityNode target){
super(source, target);
}
}
/**
* Command to relocate the entity model.
* This command is executed as a part of CompoundCommand.
*/
private class LayoutCommand extends Command {
private Table target;
private int x;
private int y;
private int oldX;
private int oldY;
public LayoutCommand(Table target, int x, int y){
this.target = target;
this.x = x;
this.y = y;
this.oldX = target.getConstraints().x;
this.oldY = target.getConstraints().y;
}
public void execute() {
this.target.setConstraints(new Rectangle(this.x, this.y, -1, -1));
}
public void undo() {
this.target.setConstraints(new Rectangle(this.oldX, this.oldY, -1, -1));
}
}
}