Package simtools.diagram

Source Code of simtools.diagram.DiagramSelection$ShapeHorizontalPositionComparator

/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 1999-2003, by :
*     Corporate:
*         Astrium SAS
*         EADS CRC
*     Individual:
*         Claude Cazenave
*        Nicolas Brodu
*         Jean-Baptiste Lièvremont
*
*
* $Id: DiagramSelection.java,v 1.28 2009/01/08 17:04:08 ogor Exp $
*
* Changes
* -------
* 25-Sep-2003 : Initial public release (NB);
*
*/

package simtools.diagram;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import javax.swing.event.UndoableEditEvent;
import javax.swing.undo.CompoundEdit;
import javax.swing.undo.UndoableEdit;

import simtools.diagram.gate.Connection;
import simtools.diagram.gate.Gate;
import simtools.diagram.gate.GatedComponent;
import simtools.diagram.undo.DeleteEdit;
import simtools.diagram.undo.DepthChangedEdit;
import simtools.diagram.undo.GateDisconnectEdit;
import simtools.diagram.undo.ResizeEdit;

import simtools.util.ListenerManager;

/**
* This class is used to define a selection area on a diagram.
* @see DiagramComponent
* @see ElementsContainer
*
* @author Claude Cazenave
*
* @version 1.1 2001
*/
public class DiagramSelection extends Rectangle {

    /** The element container that contains the selected elements */
    private ElementsContainer _elementContainer;
   
    /** true if an area is selected */
    private boolean _selArea=false;

    /** the list of selected shapes */
    private ArrayList _selectedElements;

    /** a hashtable of selected shapes */
    private Hashtable _selectedShapesMap;


    /** the gid step to compute the translation */
    private int _grid;


    /** listeners */
    private ListenerManager _listeners = new ListenerManager();

    /**
     * Creates a new empty diagram selection
     */
    public DiagramSelection(ElementsContainer elementContainer){
        _elementContainer = elementContainer;
        _elementContainer.setSelection(this);
       
        _selectedElements=new ArrayList();
        _selectedShapesMap=new Hashtable();
        _selArea=false;
        width=-1;
        _grid=0;
    }


    /**
     * gets the list of elements in the diagram component  using this diagram selection.
     * @return the list of elements in the diagram component
     */
    public ElementsContainer getElementContainer(){
        return _elementContainer;
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Propagates to listeners
     */
    protected void propagate(){
        synchronized(_listeners) {
            int n = _listeners.size(); // only one call outside loop
            for (int i=0; i<n; ++i) {
                DiagramSelectionListener dsl = (DiagramSelectionListener)_listeners.get(i);
                if (dsl!=null) dsl.selectionChanged(this);
            }
        }
    }

    /**
     * Adds a new Listener on component selection
     */
    public void addListener(DiagramSelectionListener dcpl){
        // take care of duplicates
        _listeners.add(dcpl);
    }

    /**
     * Removes a Listener on component selection
     */
    public void removeListener(DiagramSelectionListener dcpl){
        _listeners.remove(dcpl);
    }

    /**
     * Removes all Listeners on component selection
     */
    public void removeAllListeners(){
        _listeners.clear();
    }


    /**
     * Checks if one shape is selected
     * @param s the shape
     * @return true if it is selected
     */
    public boolean isSelected(Shape s){
        return _selectedShapesMap.containsKey(s);
    }

    /**
     * Checks if one shape is selected
     * @param s the shape
     * @return the selected shape or null if not selected
     */
    public ElementSelection getSelectedShape(Shape s){
        return (ElementSelection)_selectedShapesMap.get(s);
    }

    /**
     * Checks if a shape already selected contains the specified position
     * @param ox point coordinate along X axis
     * @param oy point coordinate along Y axis
     * @return true if a selected shape exists at these coordinates
     */
    public boolean isSelected(int ox, int oy){
        boolean res = false;
        for(int i=0; i<_selectedElements.size() && !res; i++){
            ElementSelection ss=(ElementSelection)_selectedElements.get(i);
            boolean isContained =  ss.element.contains(ox,oy);
            res = isContained;
        }
        return res;
    }

    /**
     * Get the selected shape at these coordinates
     * @param ox point coordinate along X axis
     * @param oy point coordinate along Y axis
     * @return selected shape at these coordinates or null if no selection at these coordinates
     */
    public Shape getSelectedShapeAt(int ox, int oy){
        Shape res = null;

        for(int i=0; i<_selectedElements.size() && res==null;i++){
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            Shape s=ss.element;
            if(s.contains(ox,oy)){
                res = s;
            }
        }
        return res;
    }

    /**
     * Checks if the selection is empty
     * @return true if the selection is empty
     */
    public boolean isEmpty(){
        return _selectedElements.isEmpty();
    }

    /**
     * Checks if the selection is defined by a rectangle shape
     * and the user is modifiing its size
     */
    public boolean isSizing(){
        return _selArea;
    }

    /**
     * Empties the selection
     */
    public void unselect(){
        clear();
        _selArea=false;
        width=-1;
        propagate();
    }

    /**
     * Selects one shape at the given point.
     * Previous selected shapes are unselected.
     *
     * @param ox point coordinate along X axis
     * @param oy point coordinate along Y axis
     * @return true if a shape is added
     */
    public boolean selectPoint(int ox, int oy) {
        unselect();
       
        boolean res = addShapeAt(ox, oy);
        propagate();
        return res;
    }

    /**
     * Selects all the shapes. Previous selected shapes
     * are unselected.
     * @return true if a shape is added
     */
    public boolean selectAll() {
        unselect();
       
        boolean res = addAllShapes();
        propagate();
        return res;
    }

    /**
     * Gets the amount of shape in the selection
     * @return the shape count
     */
    public int getShapeCount(){
        return _selectedElements.size();
    }

    /**
     * Gets the nth shape in the selection
     * @param i shape number
     * @return the shape
     */
    public Shape getShape(int i){
        return getSelection(i).element;
    }
   
    public ElementSelection getSelection(int i){
        ElementSelection ss=(ElementSelection)_selectedElements.get(i);
        return ss;
    }

    /**
     * @return he list of selected shapes
     */
    public List getShapes(){
        return new ArrayList(_selectedShapesMap.keySet());
    }

    /**
     * Gets the nth DiagramSelectedShape in the selection
     * @param i shape number
     * @return the DiagramSelectedShape
     */
    public ElementSelection getSelectedShape(int i){
        return (ElementSelection)
        _selectedElements.get(i);
    }

    /**
     * Removes one shape
     * @param i the shape number
     */
    public void removeShapeAt(int i){
        ElementSelection ss=(ElementSelection)_selectedElements.get(i);
        _selectedElements.remove(i);
        _selectedShapesMap.remove(ss.element);
    }

    /**
     *
     * If the point corresponds to an selected element, unselect it, otherwise add the corresponding selection.
     * @param ox point coordinate along X axis
     * @param oy point coordinate along Y axis
     * @return true if selection has changed
     */
    public boolean addPoint(int ox, int oy){
        boolean selectionHasChanged = false;

        _selArea = false;
        width = -1;

        // first look up in selected shapes
        for(int i=0; i<_selectedElements.size() &&!selectionHasChanged; i++) {
            ElementSelection ss=(ElementSelection) _selectedElements.get(i);
            Shape s=ss.element;
           
            if(s.contains(ox,oy)){

                // Remove this shape from the selection
                _selectedElements.remove(i);
                _selectedShapesMap.remove(s);

                selectionHasChanged =  true;
            }
        }

        if (!selectionHasChanged){
            selectionHasChanged = addShapeAt(ox,oy);
        }

        if (selectionHasChanged){
            propagate();
        }
        return selectionHasChanged;
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Selects shapes inside an area
     * Previous selected shapes are unselected.
     * @param ox origin along X axis
     * @param oy origin along Y axis
     * @param w area width
     * @param h area height
     * @return true if a shape is added
     */
    public boolean selectArea(int ox,int oy,int w,int h){
        _selArea=true;
        clear();
        if(w<0){
            x=ox+w;
            width=-w;
        }
        else{
            x=ox;
            width=w;
        }
        if(h<0){
            y=oy+h;
            height=-h;
        }
        else{
            y=oy;
            height=h;
        }
        boolean res=addShapesInside();
        propagate();
        return res;
    }

    /**
     * End of the definition of the area size
     * The area rectangle is no more needed
     * Selected shapes are the one computed at the previous
     * call of selectArea
     * @return true if the area was sizing
     */
    public boolean selectAreaEnd() {
        if (_selArea) {
            _selArea = false;
            width = -1;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Sets the grid step for translation computation
     * @param gris the gid step
     */
    public void setGrid(int grid){
        if(grid<0){
            _grid=0;
        }
        else{
            _grid=grid;
        }
    }

    /**
     * Gets the grid step for translation computation
     * @return the grid step
     */
    public int getGrid(){
        return _grid;
    }

    /**
     * Gets the grid nearest position
     * @param v a coordinate
     * @return the nearest grid position for this coordiante
     */
    public int gridPosition(int v){
        int m;
        if(_grid==0){
            return v;
        }
        m = v %_grid;
        if(m>(_grid/2)){
            return v+_grid-m;
     
        } else{
            return v-m;
        }
    }

    /**
     * Gets a list of selected diagram elements
     */
    public Vector getSelectedElements(){
        Vector v=new Vector(_selectedElements.size());
        for(int i=0;i<_selectedElements.size();i++){
            ElementSelection ss=(ElementSelection)
            _selectedElements.get(i);
            v.addElement(ss.element);
        }
        return v;
    }

   
    public Element cloneElement(Element e){
        return null;    // cannot clone element by default
    }
   
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Creates a copy of the selected shapes.
     * @param p the selection origin
     * @return a vector of shape
     */
    public Vector copySelection(Point p){
        Vector v = new Vector(_selectedElements.size());

        List selectedConnectors = new ArrayList();
        List selectedGatedComponent = new ArrayList();
        Hashtable clonedGates = new Hashtable();

        // clone shapes and translate them according to
        // new origin
        for(int i=0;i<_selectedElements.size();i++){
            ElementSelection ss=(ElementSelection)_selectedElements.get(i);
            Element s=ss.element;

            if (s instanceof Connection){
                selectedConnectors.add(s);

            } else {
                Element ns = cloneElement(s);

                if(ns!=null){
                    ns.translate(-p.x, -p.y);

                    v.addElement(ns);
                }
                if (s instanceof GatedComponent){
                    selectedGatedComponent.add(s);

                    // Kept the relation between the existing and the new gate
                    List oldGates = new ArrayList(((GatedComponent)s).getGates());
                    List newGates = new ArrayList(((GatedComponent)ns).getGates());

                    for(int j=0;j<oldGates.size(); j++){
                        clonedGates.put(oldGates.get(j), newGates.get(j));
                    }
                }
            }
        }

        // Now Copy the connectors
        for (int i = 0; i < selectedConnectors.size(); i++) {
            Connection connection = (Connection) selectedConnectors.get(i);
            Element ns=cloneElement( (Element)connection );

            if (ns!=null){
                ns.translate(-p.x, -p.y);

                v.addElement(ns);

                Gate fisrtGate = (Gate) connection.getFirstEndGate();
                Gate lastGate = (Gate) connection.getLastEndGate();

                Gate newFg = null;
                Gate newLg = null;

                if ((fisrtGate!=null) && selectedGatedComponent.contains(fisrtGate.getOwner())){
                    newFg = (Gate) clonedGates.get(fisrtGate);
                }
                if ((lastGate!=null) && selectedGatedComponent.contains(lastGate.getOwner())){
                    newLg = (Gate) clonedGates.get(lastGate);
                }
                if (newFg != null){
                    ((Connection)ns).connect(newFg, true);
                }

                if (newLg != null){
                    ((Connection)ns).connect(newLg, false);
                }
            }
        }
        return v;
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Deletes the selected shapes
     */
    public void deleteSelection(){
        CompoundEdit ce = new CompoundEdit();

        for(int i=0;i<_selectedElements.size();i++){
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
           
            Element as = ss.element;
            as.processShapeRemoving();
           
            ce.addEdit(new DeleteEdit((getElementContainer()), as));

            if (ss.element instanceof GatedComponent){
                GatedComponent gc = (GatedComponent)ss.element;

                List gates = gc.getGates();
                for(int k=0; k< gates.size(); k++){
                    Gate gate =  ((Gate)gates.get(k));
                    List connections = gate.getConnections();

                    for(int j=0; j< connections.size(); j++){
                        Connection connection = (Connection)connections.get(j);   
                        if (connection.isConnected(gate)){
                            ce.addEdit(new GateDisconnectEdit(connection, gate, connection.getFirstEndGate()!=null && connection.getFirstEndGate().equals(gate)));
                            connection.disconnect(gate);
                        }
                    }
                }
            }


            if (ss.element instanceof Connection){
                Connection gc = (Connection)ss.element;
                if (gc.getFirstEndGate() != null){
                    ce.addEdit(new GateDisconnectEdit(gc, gc.getFirstEndGate(), true));
                    gc.disconnect(gc.getFirstEndGate());
                }
                if (gc.getLastEndGate() != null){
                    ce.addEdit(new GateDisconnectEdit(gc, gc.getLastEndGate(), false));
                    gc.disconnect(gc.getLastEndGate());
                }
            }
            deleteShape(ss.element);
        }

        ce.end();
       
        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate( new UndoableEditEvent(dc, ce));
       
        unselect();
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Aligns the selected shapes
     */
    public void alignSelection(){
        int depx=0;
        int depy=0;
        CompoundEdit ce = new CompoundEdit();

        for(int i=0;i<_selectedElements.size();i++){
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            depx = gridPosition(ss.currentPoint.x) - ss.currentPoint.x;
            depy = gridPosition(ss.currentPoint.y) - ss.currentPoint.y;

            ss.translateShape(depx, depy);
            ce.addEdit(ss.translateShapeEnd());
        }

        ce.end();
       
        DiagramComponent dc = getElementContainer().getComponent();
        dc._compoundEdit.addEdit(ce);
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Check if a point can be translated.
     * A point translation can be performed if:
     * <ul>
     <li>Only one shape is selected
     *  <li>The selection is a {@link TranslatableShapePointsSelection} and there is a point at given position
     * </ul>
     * @param posX - current x position
     * @param posY - current x position
     * @return
     */
    public boolean canTranslatePointAt(int posX, int posY) {
        boolean  res = false;
        if (getShapeCount() == 1 && getSelection(0) instanceof TranslatableShapePointsSelection){
            res = ((TranslatableShapePointsSelection)getSelection(0)).hasPointAt(posX, posY);
        }
        return  res;
    }
   
    /**
     * Translate the selected point.
     * @param dx
     * @param dy
     * @param translationWay
     */
    public void translatePoint(int dx, int dy){
        if ( getShapeCount() == 1 && getSelection(0) instanceof TranslatableShapePointsSelection){
            ((TranslatableShapePointsSelection) _selectedElements.get(0)).translatePoint(dx, dy);
        }
    }

    public void translatePointEnd(){
        UndoableEdit ue = null;

        if ( getShapeCount() == 1 && getSelection(0) instanceof TranslatableShapePointsSelection){
            ue = ((TranslatableShapePointsSelection) _selectedElements.get(0)).translatePointEnd();
        }

        if (ue != null){
            DiagramComponent dc = getElementContainer().getComponent();
            dc._compoundEdit.addEdit(ue);
        }
    }
   

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Check if resize or translate is required.
     *
     * This implementation can resize elements if:
     * <ul>
     <li>The selection contains only one component
     *  <li>The selected component is resizable
     *  <li>This is not a selection of point
     * </ul>
     *
     *
     * @param x the mouse location
     * @param y the mouse location
     * @return 0 if no resize else the resize way 1=N, 2=NE,..
     */
    public int checkResizeWay(int x, int y) {
        int res = 0;

        if (_selectedElements.size() == 1) {
            ElementSelection ss=(ElementSelection) _selectedElements.get(0);
           
            if ( (! (ss instanceof ShapePointsSelection) ) && ss.element!=null && ss.element instanceof Resizable) {
               
                Rectangle2D b=ss.element.getBounds2D();
                b.setFrame(b.getX()+5.,b.getY()+5.,b.getWidth()-10.,b.getHeight()-10.);

                // look for the closest corner
                int oc=b.outcode(x,y);
                switch(oc){
                case Rectangle2D.OUT_TOP:
                    res = 1;
                    break;
                case Rectangle2D.OUT_TOP|Rectangle2D.OUT_RIGHT:
                    res =  2;
                    break;
                   
                case Rectangle2D.OUT_RIGHT:
                    res =  3;
                    break;
                   
                case Rectangle2D.OUT_RIGHT|Rectangle2D.OUT_BOTTOM:
                    res =  4;
                    break;
                   
                case Rectangle2D.OUT_BOTTOM:
                    res =  5;
                    break;
                   
                case Rectangle2D.OUT_BOTTOM|Rectangle2D.OUT_LEFT:
                    res =  6;
                    break;
                   
                case Rectangle2D.OUT_LEFT:
                    res =  7;
                    break;
                   
                case Rectangle2D.OUT_LEFT|Rectangle2D.OUT_TOP:
                    res =  8;
                    break;
                }
            }
        }
        return res;
    }


    /**
     * Resize the selection.
     *
     * This implementation can resize elements if:
     * <ul>
     <li>The selection contains only one component
     *  <li>This element is a resizable object
     *  <li> This element is not a connection selection
     * </ul>
     *
     * @param dx resize value on X axis
     * @param dy resize value on Y axis
     * @param way the resize way : 1=N, 2=NE, ...
     */
    public void resizeSelection(int dx, int dy, int way){
        int depx= dx;
        int depy= dy;
        int dtw=0;
        int dth=0;
        int deltax=0;
        int deltay=0;
        int dtx=0;
        int dty=0;

        if (_selectedElements.size() == 1) {
            ElementSelection selection = (ElementSelection) _selectedElements.get(0);
           
            if (selection.element!=null && selection.element instanceof Resizable) {
                CompoundEdit ce= new CompoundEdit();
          
                switch(way){
                case 1:
                case 5:
                    dx=0;
                    break;
                case 3:
                case 7:
                    dy=0;
                    break;
                }

                Rectangle oldBounds, newBounds;

                oldBounds = selection.element.getBounds();
                switch(way){
                case 1:
                    dtw=0;
                    dth=-depy;
                    break;
                case 2:
                    dtw=depx;
                    dth=-depy;
                    break;
                case 3:
                    dtw=depx;
                    dth=0;
                    break;
                case 4:
                    dtw=depx;
                    dth=depy;
                    break;
                case 5:
                    dtw=0;
                    dth=depy;
                    break;
                case 6:
                    dtw=-depx;
                    dth=depy;
                    break;
                case 7:
                    dtw=-depx;
                    dth=0;
                    break;
                case 8:
                    dtw=-depx;
                    dth=-depy;
                    break;
                }

                // Resize the shape
                resizeShape(selection.element, dtw, dth);

                if(ce!=null){
                    ce.addEdit(new ResizeEdit(dtw, dth, (Resizable)selection.element));
                }  

                newBounds = selection.element.getBounds();
                deltax = newBounds.width - oldBounds.width;
                deltay = newBounds.height - oldBounds.height;
                switch(way){
                case 1:
                    break;
                case 2:
                    break;
                case 3:
                    break;
                case 4:
                    dtx=0;
                    dty=deltay;
                    break;
                case 5:
                    dtx=0;
                    dty=deltay;
                    break;
                case 6:
                    dtx=-deltax;
                    dty=deltay;
                    break;
                case 7:
                    dtx=-deltax;
                    dty=0;
                    break;
                case 8:
                    dtx=-deltax;
                    dty=0;
                    break;
                }

                // Resize the shape
                selection.translateShape(dtx, dty);
             
                ce.end();   
               
                DiagramComponent dc = getElementContainer().getComponent();
                dc._compoundEdit.addEdit(ce);
            }
        }
    }


    /**
     * Ends the resize of selected shapes
     */
    public void resizeShapesEnd(){
        CompoundEdit ce = new CompoundEdit();

        for (int i=0;i<_selectedElements.size();i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);

            UndoableEdit ue = ss.translateShapeEnd();
            if (ue != null && ue.isSignificant()){
                ce.addEdit(ue);
            }
        }

        ce.end();
        if(ce.isSignificant()) { 
            DiagramComponent dc = getElementContainer().getComponent();
            dc._compoundEdit.addEdit(ce);
        }
    }
  
   
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Translates the selected shapes
     */
    public void translateShapes(int dx, int dy){

        // Compute the translation step according to the grid
        int depx = 0;
        int depy = 0;
        if (!_selectedElements.isEmpty()){
            ElementSelection selection = (ElementSelection)_selectedElements.get(0);
            selection.translateReferencePoint(dx, dy);
           
            depx = gridPosition(selection.referencePoint.x) - selection.currentPoint.x;
            depy = gridPosition(selection.referencePoint.y) - selection.currentPoint.y;

        }

        // Apply the translation to selected shapes
        for (int i=0;i<_selectedElements.size();i++) {
            ElementSelection selection = (ElementSelection)_selectedElements.get(i);
            selection.translateShape(depx, depy);
        }

        // Translate the selection area
        translate(dx,dy);
    }

    /**
     * Ends the tranlation of selected shapes
     */
    public void translateShapesEnd(){
        CompoundEdit ce = new CompoundEdit();
       
        for (int i=0;i<_selectedElements.size();i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
           
            UndoableEdit ue = ss.translateShapeEnd();
            if (ue != null && ue.isSignificant()){
                ce.addEdit(ue);
            }
        }

        ce.end();
        if(ce.isSignificant()) { 
            DiagramComponent dc = getElementContainer().getComponent();
            dc._compoundEdit.addEdit(ce);
        }
    }
   
   
    /////////////////////////////////////////////////////////////////////////////

    /**
     * Brings the selected shapes to the top of the display
     */
    public void bringSelectionToFront() {
        List selectedElements = getSelectedElements();
       
        int[] indices = new int[selectedElements.size()];
        int i;

        // Construct the list of indices
        for(i=0; i<indices.length; i++) {
            // The objects are necessarily shapes from this object
            indices[i]=getElementContainer().indexOf(selectedElements.get(i));
        }
        // Sort the indices in order to preserve the depth inside of the selection
        Arrays.sort(indices);

        Object tmp;
        int indice;
        CompoundEdit ce = new CompoundEdit();
        for(i=0; i<indices.length; i++) {
            indice=indices[i]-i;
            tmp=getElementContainer().get(indice);
            getElementContainer().remove(indice);
            getElementContainer().add(tmp);
            ce.addEdit(new DepthChangedEdit(getElementContainer(), indice, getElementContainer().size()-1));
        }
       
        ce.end();
        getElementContainer().getComponent().fireUndoableEditUpdate(new UndoableEditEvent(getElementContainer(), ce));
        getElementContainer().getComponent().repaint();
    }

    /**
     * Brings the selected shapes one step closer to the top of the display
     */
    public void bringSelectionForward() {
        List selectedElements = getSelectedElements();
       
        int[] indices = new int[selectedElements.size()];
        int i;

        // Construct the list of indices
        for(i=0; i<indices.length; i++) {
            // The objects are necessarily shapes from this object
            indices[i]=getElementContainer().indexOf(selectedElements.get(i));
        }
        // Sort the indices in order to preserve the depth inside of the selection
        Arrays.sort(indices);
       
        Object tmp;
        int indice;
        CompoundEdit ce = new CompoundEdit();
        for(i=indices.length; i>0; i--) {
            indice=indices[i-1];
            if(indice < getElementContainer().size()-1) {
                tmp=getElementContainer().get(indice);
                getElementContainer().remove(indice);
                getElementContainer().add(indice+1, tmp);
                ce.addEdit(new DepthChangedEdit(getElementContainer(), indice, indice+1));
            }
        }
       
        ce.end();
        getElementContainer().getComponent().fireUndoableEditUpdate(new UndoableEditEvent(getElementContainer(), ce));
        getElementContainer().getComponent().repaint();
    }

    /**
     * Sends the selected shapes one step deeper in the document
     */
    public void sendSelectionBackward() {
        List selectedElements = getSelectedElements();
       
        int[] indices = new int[selectedElements.size()];
        int i;

        // Construct the list of indices
        for(i=0; i<indices.length; i++) {
            // The objects are necessarily shapes from this object
            indices[i]= getElementContainer().indexOf(selectedElements.get(i));
        }
        // Sort the indices in order to preserve the depth inside of the selection
        Arrays.sort(indices);
       
        Object tmp;
        int indice;
        CompoundEdit ce = new CompoundEdit();
        for(i=0; i<indices.length; i++) {
            indice=indices[i];
            if(indice > 0) {
                tmp=getElementContainer().get(indice);
                getElementContainer().remove(indice);
                getElementContainer().add(indice-1, tmp);
                ce.addEdit(new DepthChangedEdit(getElementContainer(), indice, indice-1));
            }
        }
       
        ce.end();
        getElementContainer().getComponent().fireUndoableEditUpdate(new UndoableEditEvent(getElementContainer(), ce));
        getElementContainer().getComponent().repaint();
    }

    /**
     * Sends the selected shapes to the bottom of the document
     */
    public void sendSelectionToBack() {
        List selectedElements = getSelectedElements();

        int[] indices = new int[selectedElements.size()];
        int i;

        // Construct the list of indices
        for(i=0; i<indices.length; i++) {
            // The objects are necessarily shapes from this object
            indices[i]=getElementContainer().indexOf(selectedElements.get(i));
        }
        // Sort the indices in order to preserve the depth inside of the selection
        Arrays.sort(indices);

        Object tmp;
        int indice;
        CompoundEdit ce = new CompoundEdit();
        for(i=0; i<indices.length; i++) {
            indice=indices[i];
            tmp=getElementContainer().get(indice);
            getElementContainer().remove(indice);
            getElementContainer().add(i, tmp);
            ce.addEdit(new DepthChangedEdit(getElementContainer(), indice, i));
        }

        ce.end();
        getElementContainer().getComponent().fireUndoableEditUpdate(new UndoableEditEvent(getElementContainer(), ce));
        getElementContainer().getComponent().repaint();
    }

    /////////////////////////////////////////////////////////////////////////////

    /**
     * Align the content of the selection on the top
     * of the highest shape
     */
    public void alignSelectionToTop() {

        int topBound = Integer.MAX_VALUE;
        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();
            if(s.getBounds().y < topBound) {
                topBound = s.getBounds().y;
            }
        }

        CompoundEdit ce = new CompoundEdit();
        int dy;
        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dy = topBound - ss.element.getBounds().y;
            ss.translateShape(0, dy);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }  
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();
    }

    /**
     * Align the content of the selection on the bottom
     * of the lowest shape
     */
    public void alignSelectionToBottom() {

        int bottomBound = Integer.MIN_VALUE;

        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();

            if(s.getBounds().y + s.getBounds().height > bottomBound) {
                bottomBound = s.getBounds().y + s.getBounds().height;
            }
        }

        CompoundEdit ce = new CompoundEdit();
        int dy;
        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dy = bottomBound - ss.element.getBounds().y - ss.element.getBounds().height;

            ss.translateShape(0, dy);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
           
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();
    }

    /**
     * Align the content of the selection on the left
     * of the leftmost shape
     */
    public void alignSelectionToLeft() {

        int leftBound = Integer.MAX_VALUE;

        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();
           
            if(s.getBounds().x < leftBound) {
                leftBound = s.getBounds().x;
            }
        }

        CompoundEdit ce = new CompoundEdit();
        int dx;
        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dx = leftBound - ss.element.getBounds().x;

            ss.translateShape(dx,0);
           
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }  
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();
    }

    /**
     * Align the content of the selection on the right
     * of the rightmost shape
     */
    public void alignSelectionToRight() {

        int rightBound = Integer.MIN_VALUE;

        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();
            if(s.getBounds().x + s.getBounds().width > rightBound) {
                rightBound = s.getBounds().x + s.getBounds().width;
            }
        }

        CompoundEdit ce = new CompoundEdit();
        int dx;
        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dx = rightBound - ss.element.getBounds().x - ss.element.getBounds().width;

            ss.translateShape(dx,0);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();
    }

    /**
     * Align the content of the selection on its vertical barycentre
     */
    public void alignSelectionVCenter() {

        int vCenter = 0;

        Rectangle bounds;
        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();
            bounds = s.getBounds();
            vCenter += bounds.y + bounds.height/2;
        }
        vCenter /= _selectedElements.size();

        CompoundEdit ce = new CompoundEdit();
        int dy;

        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dy = vCenter - ss.element.getBounds().y - ss.element.getBounds().height/2;
           
            ss.translateShape(0,dy);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();

    }

    /**
     * Align the content of the selection on its horizontal barycentre
     */
    public void alignSelectionHCenter() {

        int hCenter = 0;

        Rectangle bounds;

        for(int i=0; i<_selectedElements.size(); i++) {
            Shape s = ((ElementSelection)_selectedElements.get(i)).getShape();
            bounds = s.getBounds();
            hCenter += bounds.x + bounds.width/2;
        }
        hCenter /= _selectedElements.size();

        CompoundEdit ce = new CompoundEdit();
        int dx;



        for(int i=0; i<_selectedElements.size(); i++) {
            ElementSelection ss = (ElementSelection)_selectedElements.get(i);
            dx = hCenter - ss.element.getBounds().x - ss.element.getBounds().width/2;
            ss.translateShape(dx,0);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }
        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();   
    }

    /**
     * Sort shapes according their horizontal position.
     * Shapes are sorted form left to right
     * @author zxpletran007
     *
     */
    public class ShapeHorizontalPositionComparator implements Comparator{
        public int   compare(Object o1, Object o2){
            return ( (((ElementSelection)o1)).element.getBounds().x - (((ElementSelection)o2)).element.getBounds().x); // Throw classCastException if objects to compare are not instance of AbstractShape
        }
    }

    /**
     * Sort shapes according their vertical position.
     * Shapes are sorted form top to botton
     * @author zxpletran007
     *
     */
    public class ShapeVerticalPositionComparator implements Comparator{
        public int   compare(Object o1, Object o2){
            return ( (((ElementSelection)o1)).element.getBounds().y - (((ElementSelection)o2)).element.getBounds().y); // Throw classCastException if objects to compare are not instance of AbstractShape
        }
    }
    /**
     * Distributes the selected shapes so there is equal horizontal distance between the edges of all them
     */
    public void distributeSelectionHorizontally() {

        List selection = (List)_selectedElements.clone()// make a copy

        Collections.sort(selection, new ShapeHorizontalPositionComparator());

        // Compute a mean distance
        int meanDistance=0;

        Rectangle bounds, previousBounds;
        for(int i=1; i<selection.size(); i++) {
            previousBounds= ((ElementSelection)selection.get(i-1)).getShape().getBounds();
            bounds = ((ElementSelection)selection.get(i)).getShape().getBounds();
            meanDistance+= bounds.x - (previousBounds.x + previousBounds.width);
        }
        meanDistance/=selection.size()-1;

        // Trnaslate shapes
        CompoundEdit ce = new CompoundEdit();

        Shape shape, previousShape;
        for(int i=1; i<selection.size(); i++) {
            ElementSelection ss = ((ElementSelection)selection.get(i));
            shape = ss.getShape();
            previousShape= ((ElementSelection)selection.get(i-1)).getShape();
            int dx = previousShape.getBounds().x + previousShape.getBounds().width + meanDistance  - shape.getBounds().x;

            ss.translateShape(dx,0);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }

        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint();
    }

    /**
     * Distributes the selected shapes so there is equal vertical distance between the edges of all them
     */
    public void distributeSelectionVertically() {

        List selection = (List)_selectedElements.clone();   // make a copy

        Collections.sort(selection, new ShapeVerticalPositionComparator());

        // Compute a mean distance
        int meanDistance=0;

        Rectangle bounds, previousBounds;
        for(int i=1; i<selection.size(); i++) {
            previousBounds= ((ElementSelection)selection.get(i-1)).getShape().getBounds();
            bounds = ((ElementSelection)selection.get(i)).getShape().getBounds();
            meanDistance+= bounds.y - (previousBounds.y + previousBounds.height);
        }
        meanDistance/=selection.size()-1;

        // Translate shapes
        CompoundEdit ce = new CompoundEdit();
        Shape shape, previousShape;
        for(int i=1; i<selection.size(); i++) {
            ElementSelection ss = ((ElementSelection)selection.get(i));
            shape = ss.getShape();
            previousShape= ((ElementSelection)selection.get(i-1)).getShape();

            int dy = previousShape.getBounds().y + previousShape.getBounds().height + meanDistance  - shape.getBounds().y;

            ss.translateShape(0, dy);
            if(ce!=null){
                ce.addEdit(ss.translateShapeEnd());
            }

        }
        ce.end();

        DiagramComponent dc = getElementContainer().getComponent();
        dc.fireUndoableEditUpdate(new UndoableEditEvent(dc, ce));
        dc.repaint()
    }

    /**
     * Computes shape origin before its move
     * for a rectangle the top-left point coordinate is returned
     * for a default shape the top-left point coordinate of its bounds is returned
     * By overriding this method, specif shapes can be managed
     * @param s the shape
     * @param p a Point to put coordinates into
     *  (if null then a new Point is returned)
     * @return a Point with coordinates
     */
    public Point getShapeOrigin(Shape s, Point p){
        Point res= ((p==null) ? (new Point()) : p );
        if(s instanceof Rectangle){
            Rectangle r=(Rectangle)s;
            res.x=r.x;
            res.y=r.y;
       
        } else{
            Rectangle r=s.getBounds();
            res.x=r.x;
            res.y=r.y;
        }
        return res;
    }

   
    /**
     * Resizes a shape
     * By overriding this method, specif shapes can be managed
     * @param s the resizable shape
     * @param dx x resizing
     * @param dy y resizing
     */
    public void resizeShape(Shape s, int dx, int dy){
        if(s instanceof Resizable){
            Resizable r=(Resizable)s;
            r.resize(dx, dy);
        }
    }

    /**
     * Deletse a shape
     * By overriding this method, one can use an other iterator
     * on the shapes.
     * @param s the shape
     */
    public void deleteShape(Shape s){
        if(getElementContainer() !=null){
            getElementContainer().remove(s);
        }
    }

    /**
     * Removes all the selected shapes
     */
    protected void clear(){
        _selectedElements.clear();
        _selectedShapesMap.clear();
    }
    /**
     * Adds a selected shape if it is not already selected
     * @return true if shape is added
     */
    protected boolean add(ElementSelection dss){
        int selectionOldCount = getShapeCount();
       
        if(!_selectedShapesMap.containsKey(dss.element)){
            // Selected shapes are sorted according to their depth
            int index=0;
           
            if (getElementContainer() != null){
                for(index=0;index<_selectedElements.size();index++){
                    if (getElementContainer().indexOf( ((ElementSelection)_selectedElements.get(index)).element) >getElementContainer().indexOf(dss.element))
                        break;
                }
            }
            _selectedElements.add(index, dss);
            _selectedShapesMap.put(dss.element,dss);
        }
        return selectionOldCount != getShapeCount();
    }

    /**
     * Add all the shapes to the selection.
     * @return true if selection has changed
     */
    protected boolean addAllShapes(){
        int selectionOldCount = getShapeCount();

        if (! (getElementContainer() == null || getElementContainer().size() == 0)) {
            for (int i = 0; i < getElementContainer().size(); i++) {
                Element s = (Element) getElementContainer().get(i);
                add(createShapeSelection(s));
            }
        }

        return selectionOldCount != getShapeCount();
    }

    /**
     * The first shape which contains the given coordinates
     * is added to the selected shapes list.
     * By overriding this method, one can use an other iterator
     * on the shapes.
     * @param ox the x coordinate
     * @param oy the y coordinate
     * @return true if selection has changed
     */
    protected boolean addShapeAt(int ox, int oy){
        int selectionOldCount = getShapeCount();

        if(getElementContainer() != null){
           
            boolean addedShape = false;
            for(int i=0; i<getElementContainer().size() && !addedShape;i++){
                Element s = (Element)getElementContainer().get(i);

                if(s.contains(ox,oy)){
                    add(createShapeSelection(s));
                }
            }
        }
        return  selectionOldCount != getShapeCount();
    }

    protected ElementSelection createShapeSelection(Element s){
        ElementSelection res;
       
        Point shapeOrigin = getShapeOrigin(s,null);
        if(s instanceof SelectableShapeInterface){
            res = (((SelectableShapeInterface)s).createSelection(shapeOrigin, this));

        } else {
            res = (new ElementSelection(s, shapeOrigin));
        }
       
        return res;
    }

    /**
     * Get the first shape found at given position which is not a connection.
     * @param ox
     * @param oy
     * @return the first shape found at given position
     */
    public Shape getShapeAt(int ox, int oy){
        Shape res = null;

        if(getElementContainer() != null){
            for(int i=0; i<getElementContainer().size() && res==null;i++){
                Shape s = (Shape)getElementContainer().get(i);
                if( !(s instanceof Connection) && s.contains(ox,oy)){
                    res = s;
                }
            }
        }
        return res;
    }
   
    /**
     * Get the first connection found at given position.
     * @param ox
     * @param oy
     * @return the first connection found at given position
     */
    public Connection getConnectionAt(int ox, int oy){
        Connection res = null;

        if(getElementContainer() != null){
            for(int i=0; i<getElementContainer().size() && res==null;i++){
                Shape s = (Shape)getElementContainer().get(i);
                if((s instanceof Connection) && s.contains(ox,oy)){
                    res = (Connection)s;
                }
            }
        }
        return res;
    }
   
    /**
     * All the shapes which are inside the selection area
     * By overriding this method, one can use an other iterator
     * on the shapes.
     * @return  true if selection has changed
     */
    protected boolean addShapesInside(){
        int selectionOldCount = getShapeCount();

        if(getElementContainer() !=null){
            for(int i=0;i<getElementContainer().size();i++){
                Element s=(Element)getElementContainer().get(i);

                if(contains(s.getBounds())){
                    add(createShapeSelection(s));
                }
            }
        }
        return  selectionOldCount != getShapeCount();
    }
}
TOP

Related Classes of simtools.diagram.DiagramSelection$ShapeHorizontalPositionComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.