/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * 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; either version 3 of the License, or (at your option) * any later version. * 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 http://www.gnu.org/licenses/ */ package com.bc.ceres.swing.figure.support; import com.bc.ceres.core.ExtensionManager; import com.bc.ceres.grender.Rendering; import com.bc.ceres.grender.Viewport; import com.bc.ceres.swing.figure.Figure; import com.bc.ceres.swing.figure.FigureSelection; import com.bc.ceres.swing.figure.Handle; import java.awt.Graphics2D; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.Transferable; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class DefaultFigureSelection extends DefaultFigureCollection implements FigureSelection { private List<Handle> handles; private Handle selectedHandle; private int selectionStage; public DefaultFigureSelection() { this.selectionStage = 0; } @Override public <E> E getExtension(Class<E> extensionType) { return ExtensionManager.getInstance().getExtension(this, extensionType); } @Override public int getSelectionStage() { return selectionStage; } @Override public void setSelectionStage(int selectionStage) { if (this.selectionStage != selectionStage) { this.selectionStage = selectionStage; if (selectionStage == 0) { removeAllFigures(); } updateHandles(); fireFigureChanged(); } } @Override public Handle[] getHandles() { if (handles != null) { return handles.toArray(new Handle[handles.size()]); } return NO_HANDLES; } @Override public Handle getSelectedHandle() { return selectedHandle; } @Override public void setSelectedHandle(Handle handle) { if (this.selectedHandle != handle) { if (this.selectedHandle != null) { this.selectedHandle.setSelected(false); } this.selectedHandle = handle; if (this.selectedHandle != null) { this.selectedHandle.setSelected(true); if (handles == null) { handles = new ArrayList<Handle>(); } if (!handles.contains(handle)) { handles.add(this.selectedHandle); } } fireFigureChanged(); } } @Override public boolean isSelectable() { // selections are not selectable. return false; } @Override public boolean isSelected() { // selections are never selected. return false; } @Override public void setSelected(boolean selected) { // selections cannot be selected. } @Override public String getPresentationName() { return getFigureCount() == 0 ? "" : getFigureCount() == 1 ? "Figure" : "Figures"; } @Override public Object getSelectedValue() { return getFigureCount() > 0 ? getFigure(0) : null; } @Override public Object[] getSelectedValues() { return getFigures(); } @Override public boolean isEmpty() { return getFigureCount() == 0; } @Override public Transferable createTransferable(boolean copy) { return new FigureTransferable(getFigures(), copy); } @Override protected boolean addFigureImpl(int index, Figure figure) { if (figure.isSelectable()) { figure.setSelected(true); return super.addFigureImpl(index, figure); } return false; } @Override protected Figure[] addFiguresImpl(Figure[] figures) { figures = filterSelectableFigures(figures); for (Figure figure : figures) { figure.setSelected(true); } return super.addFiguresImpl(figures); } @Override protected boolean removeFigureImpl(Figure figure) { boolean removed = super.removeFigureImpl(figure); if (removed) { figure.setSelected(false); } return removed; } @Override protected Figure[] removeFiguresImpl() { Figure[] removedFigures = super.removeFiguresImpl(); for (Figure figure : removedFigures) { figure.setSelected(false); } return removedFigures; } /** * Notifies this object that it is no longer the clipboard owner. * This method will be called when another application or another * object within this application asserts ownership of the clipboard. * * @param clipboard the clipboard that is no longer owned * @param contents the contents which this owner had placed on the clipboard */ @Override public void lostOwnership(Clipboard clipboard, Transferable contents) { System.out.println("lostOwnership: clipboard = " + clipboard + ", contents = " + contents); if (contents instanceof FigureTransferable) { FigureTransferable figureTransferable = (FigureTransferable) contents; if (figureTransferable.isSnapshot()) { figureTransferable.dispose(); } } } @Override public FigureSelection clone() { final DefaultFigureSelection figureSelection = (DefaultFigureSelection) super.clone(); figureSelection.handles = null; figureSelection.selectedHandle = null; figureSelection.selectionStage = 0; return figureSelection; } @Override public String toString() { return getClass().getName() + "[figureCount=" + getFigureCount() + "]"; } @Override public Figure[] removeAllFigures() { disposeHandles(); selectionStage = 0; return super.removeAllFigures(); } @Override public void draw(Rendering rendering) { if (getFigureCount() == 0 || getSelectionStage() < 1) { return; } final Graphics2D g = rendering.getGraphics(); final Viewport vp = rendering.getViewport(); AffineTransform m2v = vp.getModelToViewTransform(); final Figure[] figures = getFigures(); if (figures.length > 1) { for (int i = 1; i < figures.length; i++) { Figure figure = figures[i]; g.setPaint(StyleDefaults.MULTI_SELECTION_STROKE_PAINT); g.setStroke(StyleDefaults.MULTI_SELECTION_STROKE); g.draw(getExtendedBounds(figure, m2v)); } g.setPaint(StyleDefaults.SELECTION_STROKE_PAINT); g.setStroke(StyleDefaults.FIRST_OF_MULTI_SELECTION_STROKE); g.draw(getExtendedBounds(figures[0], m2v)); } g.setPaint(StyleDefaults.SELECTION_STROKE_PAINT); g.setStroke(StyleDefaults.SELECTION_STROKE); g.draw(getBounds(this, m2v)); if (handles != null) { for (Handle handle : handles) { handle.draw(rendering); } } } private static Rectangle2D getExtendedBounds(Figure figure, AffineTransform m2v) { return getExtendedBounds(getBounds(figure, m2v)); } private static Rectangle2D getBounds(Figure figure, AffineTransform m2v) { return m2v.createTransformedShape(figure.getBounds()).getBounds2D(); } static Rectangle2D getExtendedBounds(Rectangle2D bounds) { return new Rectangle2D.Double(bounds.getX() - 0.5 * StyleDefaults.SELECTION_EXTEND_SIZE, bounds.getY() - 0.5 * StyleDefaults.SELECTION_EXTEND_SIZE, bounds.getWidth() + StyleDefaults.SELECTION_EXTEND_SIZE, bounds.getHeight() + StyleDefaults.SELECTION_EXTEND_SIZE); } private void updateHandles() { disposeHandles(); if (this.selectionStage != 0) { handles = new ArrayList<Handle>(Arrays.asList(createHandles(this.selectionStage))); } } private void disposeHandles() { if (handles != null) { for (Handle handle : handles) { handle.dispose(); } } handles = null; selectedHandle = null; } private static Figure[] filterSelectableFigures(Figure[] figures) { boolean allSelectable = true; for (Figure figure : figures) { if (!figure.isSelectable()) { allSelectable = false; break; } } if (!allSelectable) { ArrayList<Figure> selectableFigures = new ArrayList<Figure>(figures.length); for (Figure figure : figures) { if (figure.isSelectable()) { selectableFigures.add(figure); } } figures = selectableFigures.toArray(new Figure[selectableFigures.size()]); } return figures; } }