/*
* funCKit - functional Circuit Kit
* Copyright (C) 2013 Lukas Elsner <open@mindrunner.de>
* Copyright (C) 2013 Peter Dahlberg <catdog2@tuxzone.org>
* Copyright (C) 2013 Julian Stier <mail@julian-stier.de>
* Copyright (C) 2013 Sebastian Vetter <mail@b4sti.eu>
* Copyright (C) 2013 Thomas Poxrucker <poxrucker_t@web.de>
* Copyright (C) 2013 Alexander Treml <alex.treml@directbox.com>
*
* 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 de.sep2011.funckit.controller;
import de.sep2011.funckit.model.graphmodel.Brick;
import de.sep2011.funckit.model.graphmodel.Circuit;
import de.sep2011.funckit.model.graphmodel.Element;
import de.sep2011.funckit.model.graphmodel.implementations.commands.PasteCommand;
import de.sep2011.funckit.model.sessionmodel.EditPanelModel;
import de.sep2011.funckit.model.sessionmodel.SessionModel;
import de.sep2011.funckit.model.sessionmodel.Settings;
import de.sep2011.funckit.validator.Check;
import de.sep2011.funckit.validator.MultipleCollisionCheck;
import de.sep2011.funckit.validator.Result;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static javax.swing.SwingUtilities.isLeftMouseButton;
import static javax.swing.SwingUtilities.isRightMouseButton;
/**
* Tool for pasting Elements.
*/
public class PasteTool extends AbstractTool {
/**
* Create a new Paste Tool.
*
* @param c
* the associated {@link Controller}, should not be null
*/
public PasteTool(Controller c) {
this.controller = c;
}
@Override
public void mouseMoved(MouseEvent e, EditPanelModel editPanelModel) {
super.mouseMoved(e, editPanelModel);
Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation());
moveElementsInCopyBuffer(editPanelModel, click);
SessionModel sm = controller.getSessionModel();
showGhosts(editPanelModel, sm);
}
@Override
public void mouseDragged(MouseEvent e, EditPanelModel editPanelModel) {
super.mouseDragged(e, editPanelModel);
Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation());
moveElementsInCopyBuffer(editPanelModel, click);
SessionModel sm = controller.getSessionModel();
showGhosts(editPanelModel, sm);
}
@Override
public void mouseWheelMoved(MouseWheelEvent e, EditPanelModel editPanelModel) {
super.mouseWheelMoved(e, editPanelModel);
Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation());
moveElementsInCopyBuffer(editPanelModel, click);
SessionModel sm = controller.getSessionModel();
showGhosts(editPanelModel, sm);
}
/**
* Setsa the ghosts for the paste tool into the model.
*
* @param editPanelModel the panel model to show the ghosts in
* @param sessionModel the currently used session model
*/
public void showGhosts(EditPanelModel editPanelModel, SessionModel sessionModel) {
boolean wasAuto = editPanelModel.isAutoNotify();
editPanelModel.setAutoNotify(false);
if (editPanelModel.getGhosts() != null && editPanelModel.getGhosts().isEmpty()) {
editPanelModel.setGhosts(new LinkedHashSet<Element>(sessionModel.getCopyBuffer()
.getElements()));
} else {
editPanelModel.setGhosts(editPanelModel.getGhosts());
}
Set<Element> ghosts = editPanelModel.getGhosts();
Check collisionCheck = new MultipleCollisionCheck(ghosts);
Result result = collisionCheck.perform(editPanelModel.getCircuit());
if (result.isPassed()) {
sessionModel.getCurrentProject().setErrorGhosts(null);
} else {
sessionModel.getCurrentProject().setErrorGhosts(ghosts);
}
editPanelModel.notifyObservers();
editPanelModel.setAutoNotify(wasAuto);
}
/**
* Moves the Elements inside the copy buffer to the given position (mouse in center).
*
* @param editPanelModel the affected edit panel model
* @param click the position to move to (center of the elements)
*/
public void moveElementsInCopyBuffer(EditPanelModel editPanelModel, Point click) {
boolean gridLock = controller.getSessionModel().getSettings()
.getBoolean(Settings.GRID_LOCK);
SessionModel sm = controller.getSessionModel();
Circuit copyBuffer = sm.getCopyBuffer();
Set<Element> cpBufferElems = copyBuffer.getElements();
Rectangle copyCircuitRect = new Rectangle(copyBuffer.getBoundingRectangle());
/* find some Brick to use for Grid Lock if enabled (uses first it finds) */
Element gridLockElem = null;
for (Iterator<Element> it = cpBufferElems.iterator(); it.hasNext() && gridLockElem == null
&& gridLock;) {
Element elem = it.next();
if (elem instanceof Brick) {
gridLockElem = elem;
}
}
int lockDx = 0;
int lockDy = 0;
if (gridLockElem != null) {
Point p1 = new Point(gridLockElem.getPosition());
elementToClickPos(p1, copyCircuitRect, click);
posMouseOnCenter(p1, copyCircuitRect, click);
Point p2 = lockPointOnGrid(p1);
lockDx = p2.x - p1.x;
lockDy = p2.y - p1.y;
}
/* Move Elements to click Position */
for (Element elem : cpBufferElems) {
Point pos = elem.getPosition();
elementToClickPos(pos, copyCircuitRect, click);
/* move to grid lock */
pos.x += lockDx;
pos.y += lockDy;
posMouseOnCenter(pos, copyCircuitRect, click);
elem.setPosition(pos);
}
}
private static void elementToClickPos(Point pos, Rectangle copyCircuitRect, Point click) {
/* Adjust positions so the bounding rect starts at (0,0) */
pos.x -= copyCircuitRect.x;
pos.y -= copyCircuitRect.y;
/* move to mouse Position */
pos.x += click.x;
pos.y += click.y;
}
private static void posMouseOnCenter(Point pos, Rectangle copyCircuitRect, Point click) {
/* Cursor to center */
pos.x -= copyCircuitRect.width / 2;
pos.y -= copyCircuitRect.height / 2;
}
@Override
public void mouseClicked(MouseEvent e, EditPanelModel editPanelModel) {
Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation());
SessionModel sessionModel = controller.getSessionModel();
if (isLeftMouseButton(e)) {
moveElementsInCopyBuffer(editPanelModel, click);
List<Brick> bricks = new LinkedList<Brick>();
for (Element element : sessionModel.getCopyBuffer().getElements()) {
if (element instanceof Brick) {
bricks.add((Brick) element);
}
}
Check collision = new MultipleCollisionCheck(bricks);
if (collision.perform(editPanelModel.getCircuit()).isPassed()) {
Circuit pasteCircuit = sessionModel.getCopyBuffer().getCopy();
sessionModel.getCurrentGraphCommandDispatcher().dispatch(
new PasteCommand(editPanelModel.getCircuit(), pasteCircuit));
editPanelModel.setGhosts(new LinkedHashSet<Element>());
}
} else if (isRightMouseButton(e)) {
sessionModel.restoreTool(); // NOTE: tool has been saved before
// paste tool gets set.
}
}
@Override
public PasteTool getNewInstance(Controller c) {
return this;
}
@Override
protected void cancelCurrentAction(EditPanelModel editPanelModel) {
controller.getSessionModel().restoreTool();
}
}