All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ingenias.editor.events.ChangeNARYEdgeLocation Maven / Gradle / Ivy

There is a newer version: 1.0.9
Show newest version
/** 
 * Copyright (C) 2010  Jorge J. Gomez-Sanz
 * 
 * This file is part of the INGENME tool. INGENME is an open source meta-editor
 * which produces customized editors for user-defined modeling languages
 *
 * This program 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 version 3 of the License
 *
 * This program 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 program.  If not, see 
 **/

package ingenias.editor.events;

import ingenias.editor.Model;
import ingenias.editor.ModelJGraph;
import ingenias.editor.cell.*;
import ingenias.editor.entities.Entity;
import ingenias.editor.entities.ViewPreferences;

import java.awt.*;

import javax.swing.*;
import java.awt.Graphics;
import java.awt.geom.Line2D;
import java.awt.geom.Line2D.Float;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.*;

import org.jgraph.graph.*;
import org.jgraph.*;
import org.jgraph.event.*;

/**
 * This class reallocates a n-ary edge so the central point of the
 * set of ports that it inter-connects. The position is calculated
 * by adding the (x,y) of each port and dividing by the number of
 * ports
 */
public class ChangeNARYEdgeLocation
implements org.jgraph.event.GraphModelListener {
	private Object workingObject = null;
	private boolean alreadyExecuting = true;
	private int counter = 0;
	JGraph graph = null;
	private boolean enabled=true;

	public ChangeNARYEdgeLocation(JGraph graph) {
		this.graph = graph;
	}

	public void graphChanged(org.jgraph.event.GraphModelEvent gme) {

		if (enabled && alreadyExecuting && (gme.getChange().getInserted()==null
				||gme.getChange().getInserted().length==0 )) {
			alreadyExecuting=false;
			Hashtable changes = new Hashtable();
			Map old = gme.getChange().getPreviousAttributes();
			Map newAt = gme.getChange().getAttributes();
			if (old != null) {
				// No autocenter. Just watch that no overlapping occurs.
				Iterator keys = old.keySet().iterator();

				while (keys.hasNext()) {					
					Object current = keys.next();

					Map oluomap = (Map) old.get(current);
					Map newuomap = (Map) newAt.get(current);
					if ((GraphConstants.getBounds(oluomap)==null 
							||GraphConstants.getBounds(newuomap)==null) ){

						if (current instanceof NAryEdge)  {
							this.processChange(current,changes);				
						}
					} else {
						Rectangle rect1 = GraphConstants.getBounds(oluomap).getBounds();
						Rectangle rect2 = GraphConstants.getBounds(newuomap).getBounds();
						if (((rect1 == null || rect2 == null || !rect1.equals(rect2))) &&
								current instanceof NAryEdge) {
							this.processChange( current,changes);						
						}
					}

				}


				solveOverlappings((ModelJGraph) graph, changes);

				if (changes.size()>0){
					graph.getModel().edit(changes, null, null, null);					
				}
			}
			alreadyExecuting=true;
		}

	}

	public static void solveOverlappings(ModelJGraph graph,
			Hashtable map) {		
				Hashtable naryedgeatts=new  Hashtable();
			for (int k=0;k naries = map.keySet();
			for (Object currentnary:naries){
				if (currentnary instanceof NAryEdge){
					Rectangle2D rect1= GraphConstants.getBounds(map.get(currentnary));
					detectingOverlappingsAndRadialLayout(map, naryedgeatts,
							currentnary, rect1,graph);

				}
			}
	
	}



	private static void detectingOverlappingsAndRadialLayout(
			Hashtable map,
			Hashtable naryedgeatts, Object currentnary,
			Rectangle2D rect1, ModelJGraph graph) {
		HashSet nset = new HashSet();
		nset.addAll(naryedgeatts.keySet());
		nset.remove(currentnary);


		double cxr1 = rect1.getX();
		double cyr1=  rect1.getY();
		Rectangle rectn1=new Rectangle((int)(cxr1),(int)(cyr1),(int)rect1.getWidth(),(int)rect1.getHeight());

		double distance = 10;
		double angle = 0;

		while (checkOverlapping(rectn1,(NAryEdge) currentnary,nset,naryedgeatts,graph)){		
			double nx=Math.max(rect1.getX()+distance*Math.cos(angle),0);
			double ny=Math.max(rect1.getY()+distance*Math.sin(angle),0);				 
			rectn1=new Rectangle((int)(nx),(int)(ny),(int)rect1.getWidth(),(int)rect1.getHeight());
			angle = angle + 2;
			if (angle >=360){
				distance = distance + 15;
				angle = 0;
			};
		};

		GraphConstants.setBounds(map.get(currentnary),rectn1);		
		rect1=rectn1;

	}

	private static void detectingOverlappingsAndSpringLayout(
			Hashtable map,
			Hashtable naryedgeatts, Object currentnary,
			Rectangle2D rect1, ModelJGraph graph) {
		HashSet nset = new HashSet();
		nset.addAll(naryedgeatts.keySet());
		nset.remove(currentnary);
		for (Object othernary:naryedgeatts.keySet()){
			if (othernary!=currentnary){
				Rectangle2D rect2=GraphConstants.getBounds(naryedgeatts.get(othernary));
				if (rect1.intersects(rect2)){
					double cxr1 = rect1.getCenterX();
					double cyr1=rect1.getCenterY();
					double cxr2=rect2.getCenterX();
					double cyr2=rect2.getCenterY();						
					double dx=cxr1-cxr2;
					double dy=cyr1-cyr2;
					double module=Math.sqrt(dx*dx+dy*dy);
					dx=dx/module;
					dy=dy/module;
					double distance=3;
					boolean additionaloverlapping=true;
					HashSet overlappingcheckset = new HashSet();
					overlappingcheckset.addAll(nset);
					Rectangle rectn1=null;
					do{
						rectn1=new Rectangle((int)(rect1.getX()-distance*dx),(int)(rect1.getY()-distance*dy),(int)rect1.getWidth(),(int)rect1.getHeight());
						distance=distance+5;
						//	System.err.println("increasing distance "+distance+ " checking over "+overlappingcheckset.size());
					} while (checkOverlapping(rectn1,(NAryEdge) currentnary,overlappingcheckset,naryedgeatts,graph));			
					GraphConstants.setBounds(map.get(currentnary),rectn1);			
					rect1=rectn1;
				}
			}
		}
	}

	private static boolean checkOverlapping(Rectangle rect1,NAryEdge currentNary,
			HashSet overlappingcheckset,
			Hashtable changes, ModelJGraph graph) {
		Iterator it = overlappingcheckset.iterator();
		Rectangle2D rect2=null;
		boolean intersectsline=evaluateCurrentNAryEdge(rect1, graph,
				false, currentNary);
		if (it.hasNext() && !intersectsline){

			do {
				NAryEdge current=(NAryEdge) it.next();
				Map next = changes.get(current);				
				if (next!=null){
					rect2=GraphConstants.getBounds(next);
					intersectsline=intersectsline|| evaluateCurrentNAryEdge(rect1, graph, intersectsline, current);			
				}				
			} while (it.hasNext() && (rect2==null || !rect1.intersects(rect2)) && !intersectsline);
		}
		// this slows down things a lot
		for (int k=0;k