annis.gui.querybuilder.TigerQueryBuilderCanvas.java Source code

Java tutorial

Introduction

Here is the source code for annis.gui.querybuilder.TigerQueryBuilderCanvas.java

Source

/*
 * 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() {
        }
    }
}