Java tutorial
/* * Copyright 2011 Corpuslinguistic working group Humboldt University Berlin. * * 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 annis.gui.querybuilder; import annis.gui.QueryController; import annis.gui.widgets.GripDragComponent; import annis.gui.widgets.SimpleCanvas; import annis.libgui.Helper; import annis.service.objects.AnnisAttribute; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.GenericType; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DropHandler; import com.vaadin.event.dd.acceptcriteria.AcceptAll; import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; import com.vaadin.ui.AbsoluteLayout; import com.vaadin.ui.AbsoluteLayout.ComponentPosition; import com.vaadin.ui.DragAndDropWrapper; import com.vaadin.ui.DragAndDropWrapper.WrapperTargetDetails; import com.vaadin.ui.Layout; import com.vaadin.ui.Notification; import com.vaadin.ui.Panel; import java.awt.geom.Line2D; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.slf4j.LoggerFactory; /** * * @author thomas */ public class TigerQueryBuilderCanvas extends Panel { private static final org.slf4j.Logger log = LoggerFactory.getLogger(TigerQueryBuilderCanvas.class); private SimpleCanvas canvas; private Map<NodeWindow, GripDragComponent> nodes; private List<EdgeWindow> edges; private AbsoluteLayout area; private AbsoluteDropHandler handler; private int number = 0; private NodeWindow preparedEdgeSource = null; private final QueryController controller; public TigerQueryBuilderCanvas(QueryController controller) { this.controller = controller; nodes = new HashMap<>(); edges = new ArrayList<>(); setSizeFull(); setImmediate(true); area = new AbsoluteLayout(); area.setWidth("2000px"); area.setHeight("2000px"); area.addStyleName("no-vertical-drag-hints"); area.addStyleName("no-horizontal-drag-hints"); area.addStyleName("no-box-drag-hints"); canvas = new SimpleCanvas(); canvas.setSizeFull(); canvas.addStyleName("tigerquery-builder-canvas"); handler = new AbsoluteDropHandler(this, area); DragAndDropWrapper areaPane = new DragAndDropWrapper(area); areaPane.setWidth("2000px"); areaPane.setHeight("2000px"); areaPane.setDropHandler(handler); area.addComponent(canvas, "top:0px;left:0px"); setContent(areaPane); addStyleName("no-vertical-drag-hints"); addStyleName("no-horizontal-drag-hints"); addStyleName("no-box-drag-hints"); } public void updateQuery() { controller.getState().getAql().setValue(getAQLQuery()); } public Set<String> getAvailableAnnotationNames() { Set<String> result = new TreeSet<>(); WebResource service = Helper.getAnnisWebResource(); // get current corpus selection Set<String> corpusSelection = controller.getState().getSelectedCorpora().getValue(); if (service != null && corpusSelection != null) { try { List<AnnisAttribute> atts = new LinkedList<>(); for (String corpus : corpusSelection) { atts.addAll(service.path("query").path("corpora").path(corpus).path("annotations") .queryParam("fetchvalues", "false").queryParam("onlymostfrequentvalues", "true") .get(new AnnisAttributeListType())); } for (AnnisAttribute a : atts) { if (a.getType() == AnnisAttribute.Type.node) { result.add(a.getName()); } } } catch (UniformInterfaceException ex) { log.error(null, ex); } catch (ClientHandlerException ex) { log.error(null, ex); } } return result; } public void updateLinesAndEdgePositions() { canvas.getLines().clear(); for (EdgeWindow e : edges) { GripDragComponent w1 = nodes.get(e.getSource()); GripDragComponent w2 = nodes.get(e.getTarget()); ComponentPosition p1 = area.getPosition(w1); ComponentPosition p2 = area.getPosition(w2); float x1 = p1.getLeftValue() + (w1.getWidth() / 2); float y1 = p1.getTopValue() + (w1.getHeight() / 2); float x2 = p2.getLeftValue() + (w2.getWidth() / 2); float y2 = p2.getTopValue() + (w2.getHeight() / 2); float v_x = x2 - x1; float v_y = y2 - y1; // add line canvas.getLines().add(new Line2D.Float(x1, y1, x2, y2)); // set position on half of the line for the edge window ComponentPosition posEdge = area.getPosition(e); float vectorLength = (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); float xM = x1 + (vectorLength / 2.0f) * ((x2 - x1) / vectorLength); float yM = y1 + (vectorLength / 2.0f) * ((y2 - y1) / vectorLength); double normV_x = v_x / vectorLength; double normV_y = v_y / vectorLength; double pos1_x = (2.1 * vectorLength / 3) * normV_x + x1; double pos1_y = (2.1 * vectorLength / 3) * normV_y + y1; double origDir = Math.atan2(normV_y, normV_x); double pos2_x = ((1 * vectorLength) / 3) * normV_x + x1; double pos2_y = ((1 * vectorLength) / 3) * normV_y + y1; canvas.getLines().addAll(createArrow(pos1_x, pos1_y, origDir, 20.0)); canvas.getLines().addAll(createArrow(pos2_x, pos2_y, origDir, 20.0)); posEdge.setLeftValue(xM - e.getWidth() / 2.0f); posEdge.setTopValue(yM - e.getHeight() / 2.0f); } canvas.markAsDirty(); } private List<Line2D> createArrow(double x, double y, double direction, double arrowLength) { LinkedList<Line2D> result = new LinkedList<>(); double dir1 = direction + Math.PI / 8.0; double dir2 = direction - Math.PI / 8.0; double end1_x = x - arrowLength * Math.cos(dir1); double end1_y = y - arrowLength * Math.sin(dir1); double end2_x = x - arrowLength * Math.cos(dir2); double end2_y = y - arrowLength * Math.sin(dir2); result.add(new Line2D.Double(x, y, end1_x, end1_y)); result.add(new Line2D.Double(x, y, end2_x, end2_y)); return result; } public void prepareAddingEdge(NodeWindow sourceNode) { preparedEdgeSource = sourceNode; for (NodeWindow w : nodes.keySet()) { if (w != sourceNode) { w.setPrepareEdgeDock(true); } } } public void addEdge(NodeWindow target) { for (NodeWindow w : nodes.keySet()) { w.setPrepareEdgeDock(false); } if (preparedEdgeSource != target) { boolean valid = true; for (EdgeWindow e : edges) { if (e.getSource() == preparedEdgeSource && e.getTarget() == target) { valid = false; break; } } if (valid) { EdgeWindow e = new EdgeWindow(this, preparedEdgeSource, target); e.setWidth("170px"); e.setHeight("70px"); e.addStyleName("tigerquery-builder-overlay"); edges.add(e); area.addComponent(e); updateLinesAndEdgePositions(); updateQuery(); } else { Notification.show("There is already such an edge", Notification.Type.WARNING_MESSAGE); } } } public void deleteEdge(EdgeWindow e) { area.removeComponent(e); edges.remove(e); updateLinesAndEdgePositions(); updateQuery(); } public void addNode() { final NodeWindow n = new NodeWindow(number++, this); GripDragComponent panel = new GripDragComponent(n); panel.setWidth(NodeWindow.WIDTH, Layout.Unit.PIXELS); panel.setHeight(NodeWindow.HEIGHT, Layout.Unit.PIXELS); nodes.put(n, panel); area.addComponent(panel, "top:" + (10 + ((NodeWindow.HEIGHT + 20) * (number - 1))) + "px;left:10px"); // area.addComponent(wrapper, "top:" + (10 + (120 * (number-1))) + "px;left:10px"); updateQuery(); } public void deleteNode(NodeWindow n) { LinkedList<EdgeWindow> edgesToRemove = new LinkedList<>(); for (EdgeWindow e : edges) { if (e.getSource() == n || e.getTarget() == n) { edgesToRemove.add(e); area.removeComponent(e); } } edges.removeAll(edgesToRemove); area.removeComponent(nodes.get(n)); nodes.remove(n); updateLinesAndEdgePositions(); updateQuery(); } public void clearAll() { for (EdgeWindow w : edges) { area.removeComponent(w); } edges.clear(); for (GripDragComponent w : nodes.values()) { area.removeComponent(w); } nodes.clear(); number = 0; updateLinesAndEdgePositions(); updateQuery(); } private static class AbsoluteDropHandler implements DropHandler { private AbsoluteLayout layout; private TigerQueryBuilderCanvas parent; public AbsoluteDropHandler(TigerQueryBuilderCanvas parent, AbsoluteLayout layout) { this.layout = layout; this.parent = parent; } @Override public void drop(DragAndDropEvent event) { GripDragComponent.MouseEventTransferable t = (GripDragComponent.MouseEventTransferable) event .getTransferable(); WrapperTargetDetails details = (WrapperTargetDetails) event.getTargetDetails(); if (t == null || details == null) { return; } int xChange = details.getMouseEvent().getClientX() - t.getClientX(); int yChange = details.getMouseEvent().getClientY() - t.getClientY(); // Move the component in the absolute layout ComponentPosition pos = layout.getPosition(t.getSourceComponent().getParent()); pos.setLeftValue(pos.getLeftValue() + xChange); pos.setTopValue(pos.getTopValue() + yChange); if (parent != null) { parent.updateLinesAndEdgePositions(); parent.requestRepaint(); } } @Override public AcceptCriterion getAcceptCriterion() { return AcceptAll.get(); } } public String getAQLQuery() { StringBuilder query = new StringBuilder(); StringBuffer nodeIdentityOperations = new StringBuffer(); Map<NodeWindow, Integer> nodeComponentMap = new HashMap<>(); //creating node definitions int componentCount = 0; int nodeID = 1; for (NodeWindow nodeWindow : nodes.keySet()) { List<NodeWindow.ConstraintLayout> constraints = nodeWindow.getConstraints(); if (componentCount++ > 0) { query.append(" & "); } if (constraints.size() > 0) { int nodeComponentCount = 0; for (NodeWindow.ConstraintLayout c : constraints) { if (nodeComponentCount++ > 0) { nodeIdentityOperations.append("\n& #").append(componentCount).append(" _=_ #") .append(componentCount + 1); query.append(" & "); componentCount++; } String operator = c.getOperator().replace("~", "="); String quotes = c.getOperator().equals("=") || c.getOperator().equals("!=") ? "\"" : "/"; String prefix = ""; if (c.getName().trim().isEmpty() || c.getName().trim().equals("tok")) { if (operator.equals("!=")) { if (c.getName().trim().isEmpty()) { prefix = "tok" + c.getName() + operator; } else { prefix = c.getName() + operator; } } } else { prefix = c.getName() + operator; } if ("".equals(c.getValue())) { query.append(c.getName()); } else { query.append(prefix).append(quotes).append(c.getValue()).append(quotes); } } } else { query.append("node"); } nodeComponentMap.put(nodeWindow, componentCount); nodeID++; } query.append(nodeIdentityOperations); //appending node relations for (EdgeWindow edgeWindow : edges) { query.append("\n& "); query.append('#').append(nodeComponentMap.get(edgeWindow.getSource())).append(" ") .append(edgeWindow.getOperator()).append(" ").append("#") .append(nodeComponentMap.get(edgeWindow.getTarget())); } return query.toString(); } private static class AnnisAttributeListType extends GenericType<List<AnnisAttribute>> { public AnnisAttributeListType() { } } }