/*******************************************************************************
* Copyright 2010 Simon Mieth
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.kabeja.svg.action;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.kabeja.processing.BoundsFilter;
import org.kabeja.svg.SVGConstants;
import org.kabeja.svg.SVGUtils;
import org.kabeja.ui.PropertiesEditor;
import org.kabeja.ui.PropertiesListener;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.events.MouseEvent;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGMatrix;
import de.miethxml.toolkit.ui.UIUtils;
public class SelectionAction extends AbstractAction implements SVGDocumentAction,
EventListener, PropertiesEditor, ItemListener, CanvasUpdateRunnable,
GroupActionUnSelector {
protected boolean selecting = false;
protected boolean dragging = false;
protected Element selectionRectangle;
protected float startX = 0;
protected float startY = 0;
protected SVGMatrix matrix;
protected Map properties = new HashMap();
protected List listeners = new ArrayList();
float lastX;
float lastY;
protected boolean process = false;
protected boolean state = false;
protected CanvasUpdateManager updateManager;
public SelectionAction() {
super("Selection",
new ImageIcon(UIUtils.resourceToBytes(SelectionAction.class,
"/icons/cut_edit.gif")));
putValue(SHORT_DESCRIPTION, Messages.getString("editor.action.cut.area"));
}
public void handleEvent(Event evt) {
if (this.state) {
MouseEvent event = (MouseEvent) evt;
if (evt.getType().equals(SVGConstants.SVGEVENT_CLICK) && selecting) {
selecting = false;
removeSelectionRectangle();
// evt.stopPropagation();
} else if (evt.getType().equals(SVGConstants.SVGEVENT_MOUSEDOWN) &&
!selecting) {
// setup the start and end positions
this.matrix = ((SVGDocument) this.selectionRectangle
.getOwnerDocument()).getRootElement()
.getScreenCTM().inverse();
this.startX = (matrix.getA() * event.getClientX()) +
(matrix.getC() * event.getClientY()) + matrix.getE();
this.startY = (matrix.getB() * event.getClientX()) +
(matrix.getD() * event.getClientY()) + matrix.getF();
this.changePosition(this.startX, this.startY,
event.getClientX(), event.getClientX());
this.selectionRectangle.setAttributeNS(null, "visibility",
"visible");
selecting = true;
// evt.stopPropagation();
} else if (evt.getType().equals(SVGConstants.SVGEVENT_MOUSEMOVE) &&
selecting) {
// evt.getTarget()
// System.out.println("moving with button");
if ((Math.abs(lastX - event.getScreenX()) > 1) ||
(Math.abs(lastY - event.getScreenY()) > 1)) {
this.changePosition(this.startX, this.startY,
event.getClientX(), event.getClientY());
lastX = event.getScreenX();
lastY = event.getScreenY();
}
} else if (evt.getType().equals(SVGConstants.SVGEVENT_MOUSEUP) &&
selecting) {
selecting = false;
process = true;
this.changePosition(this.startX, this.startY,
event.getClientX(), event.getClientY());
this.firePropertiesUpdated();
}
}
}
protected void removeSelectionRectangle() {
this.selectionRectangle.setAttributeNS(null, "visibility", "hidden");
this.process = false;
this.firePropertiesUpdated();
}
protected void changePosition(float x, float y, float endX, float endY) {
this.selectionRectangle.setAttributeNS(null, "y", "" + y);
float width = (float) (((matrix.getA() * endX) +
(matrix.getC() * endY) + matrix.getE()) - x);
float height = (float) (((matrix.getB() * endX) +
(matrix.getD() * endY) + matrix.getF()) - y);
if (width < 0) {
this.selectionRectangle.setAttributeNS(null, "x",
"" + SVGUtils.formatNumberAttribute(x + width));
this.selectionRectangle.setAttributeNS(null, "width",
"" + SVGUtils.formatNumberAttribute(Math.abs(width)));
} else {
this.selectionRectangle.setAttributeNS(null, "x",
"" + SVGUtils.formatNumberAttribute(x));
this.selectionRectangle.setAttributeNS(null, "width",
"" + SVGUtils.formatNumberAttribute(width));
}
if (height < 0) {
this.selectionRectangle.setAttributeNS(null, "y",
"" + SVGUtils.formatNumberAttribute(y + height));
this.selectionRectangle.setAttributeNS(null, "height",
"" + SVGUtils.formatNumberAttribute(Math.abs(height)));
} else {
this.selectionRectangle.setAttributeNS(null, "y", "" + y);
this.selectionRectangle.setAttributeNS(null, "height",
"" + SVGUtils.formatNumberAttribute(height));
}
}
public void setDocument(SVGDocument doc) {
Element el = doc.getElementById("draft");
String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
// we parse the viewBox
String s = doc.getDocumentElement().getAttribute("viewBox");
String[] data = s.split("\\s+");
Element rectangle = doc.createElementNS(svgNS, "rect");
// we create a invisible rectangle for the capturing the mouse events
double x = Double.parseDouble(data[0]);
double y = Double.parseDouble(data[1]);
double width = Double.parseDouble(data[2]);
double height = Double.parseDouble(data[3]);
rectangle.setAttributeNS(null, "x",
SVGUtils.formatNumberAttribute((x - (width / 2))));
rectangle.setAttributeNS(null, "y",
SVGUtils.formatNumberAttribute(y - (height / 2)));
rectangle.setAttributeNS(null, "width",
SVGUtils.formatNumberAttribute(width * 2));
rectangle.setAttributeNS(null, "height",
SVGUtils.formatNumberAttribute(height * 2));
rectangle.setAttributeNS(null, "style", "fill:blue;opacity:0.0;");
EventTarget t = (EventTarget) rectangle;
t.addEventListener("click", this, false);
t.addEventListener("mousedown", this, false);
t.addEventListener("mouseup", this, false);
t.addEventListener("mousemove", this, false);
this.selectionRectangle = doc.createElementNS(svgNS, "rect");
this.selectionRectangle.setAttributeNS(null, "x", data[0]);
this.selectionRectangle.setAttributeNS(null, "y", data[1]);
this.selectionRectangle.setAttributeNS(null, "width", data[2]);
this.selectionRectangle.setAttributeNS(null, "height", data[3]);
this.selectionRectangle.setAttributeNS(null, "style",
"fill:blue;fill-opacity:0.10;stroke:black;stroke-width:0.10%;stroke-opacity:1.0");
this.selectionRectangle.setAttributeNS(null, "visibility", "hidden");
//doc.getDocumentElement().appendChild(this.selectionRectangle);
//doc.getDocumentElement().appendChild(rectangle);
doc.getDocumentElement()
.insertBefore(rectangle, doc.getDocumentElement().getFirstChild());
doc.getDocumentElement().insertBefore(this.selectionRectangle, rectangle);
}
public void addPropertiesListener(PropertiesListener listener) {
this.listeners.add(listener);
}
public Map getProperties() {
return this.properties;
}
public void removePropertiesListener(PropertiesListener listener) {
this.listeners.remove(listener);
}
public void setProperties(Map properties) {
}
protected void firePropertiesUpdated() {
// update the properties data
double height = Double.parseDouble(this.selectionRectangle.getAttribute(
"height"));
// TODO Auto-generated method stub
this.properties.put(BoundsFilter.PROPERTY_X,
this.selectionRectangle.getAttribute("x"));
this.properties.put(BoundsFilter.PROPERTY_Y,
"" +
(((-1) * Double.parseDouble(this.selectionRectangle.getAttribute(
"y"))) - height));
this.properties.put(BoundsFilter.PROPERTY_WIDTH,
this.selectionRectangle.getAttribute("width"));
this.properties.put(BoundsFilter.PROPERTY_HEIGHT, "" + height);
this.properties.put(BoundsFilter.PROPERTY_PROCESS,
Boolean.toString(process));
Iterator i = this.listeners.iterator();
while (i.hasNext()) {
PropertiesListener listener = (PropertiesListener) i.next();
listener.propertiesChanged(this.properties);
}
}
public void actionPerformed(ActionEvent e) {
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
this.state = true;
} else {
this.state = false;
// this should run in the UpdateManager RunnableQueue
this.removeSelectionRectangle();
}
}
public void setCanvasUpdateManager(CanvasUpdateManager manager) {
this.updateManager = manager;
}
}