annis.gui.CorpusBrowserPanel.java Source code

Java tutorial

Introduction

Here is the source code for annis.gui.CorpusBrowserPanel.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;

import annis.gui.beans.CorpusBrowserEntry;
import annis.gui.objects.Query;
import annis.libgui.Helper;
import annis.service.objects.AnnisAttribute;
import annis.service.objects.AnnisCorpus;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
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.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.data.util.DefaultItemSorter;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Label;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ChameleonTheme;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.slf4j.LoggerFactory;

/**
 *
 * @author thomas
 */
public class CorpusBrowserPanel extends Panel {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(CorpusBrowserPanel.class);

    private final static Escaper urlPathEscape = UrlEscapers.urlPathSegmentEscaper();

    /**
     *
     */
    private static final long serialVersionUID = -1029743017413951838L;

    private AnnisCorpus corpus;

    private Table tblNodeAnno;

    private BeanItemContainer<CorpusBrowserEntry> containerNodeAnno;

    private Table tblEdgeTypes;

    private BeanItemContainer<CorpusBrowserEntry> containerEdgeType;

    private Table tblEdgeAnno;

    private BeanItemContainer<CorpusBrowserEntry> containerEdgeAnno;

    private Table tblMetaAnno;

    private BeanItemContainer<CorpusBrowserEntry> containerMetaAnno;

    private CitationLinkGenerator citationGenerator;

    private QueryController controller;

    public CorpusBrowserPanel(final AnnisCorpus corpus, QueryController controller) {
        super("Available annotations");
        this.corpus = corpus;
        this.controller = controller;

        setSizeFull();

        Accordion accordion = new Accordion();
        setContent(accordion);
        accordion.setSizeFull();

        containerNodeAnno = new BeanItemContainer<>(CorpusBrowserEntry.class);
        containerNodeAnno.setItemSorter(new ExampleSorter());

        containerEdgeType = new BeanItemContainer<>(CorpusBrowserEntry.class);
        containerEdgeType.setItemSorter(new ExampleSorter());

        containerEdgeAnno = new BeanItemContainer<>(CorpusBrowserEntry.class);
        containerEdgeAnno.setItemSorter(new ExampleSorter());

        containerMetaAnno = new BeanItemContainer<>(CorpusBrowserEntry.class);
        containerMetaAnno.setItemSorter(new ExampleSorter());

        citationGenerator = new CitationLinkGenerator();

        tblNodeAnno = new ExampleTable(citationGenerator, containerNodeAnno);
        tblNodeAnno.addValueChangeListener(new ExampleListener());
        tblNodeAnno.addStyleName(ChameleonTheme.TABLE_STRIPED);

        tblEdgeTypes = new ExampleTable(citationGenerator, containerEdgeType);
        tblEdgeTypes.addValueChangeListener(new ExampleListener());
        tblEdgeTypes.addStyleName(ChameleonTheme.TABLE_STRIPED);

        tblEdgeAnno = new ExampleTable(citationGenerator, containerEdgeAnno);
        tblEdgeAnno.addValueChangeListener(new ExampleListener());
        tblEdgeAnno.addStyleName(ChameleonTheme.TABLE_STRIPED);

        tblMetaAnno = new ExampleTable(citationGenerator, containerMetaAnno);
        tblMetaAnno.addValueChangeListener(new ExampleListener());
        tblMetaAnno.addStyleName(ChameleonTheme.TABLE_STRIPED);

        boolean stripNodeAnno = true;
        boolean stripEdgeName = true;
        boolean stripEdgeAnno = true;
        HashSet<String> nodeAnnoNames = new HashSet<>();
        HashSet<String> edgeAnnoNames = new HashSet<>();
        HashSet<String> edgeNames = new HashSet<>();
        HashSet<String> fullEdgeNames = new HashSet<>();
        boolean hasDominance = false;
        boolean hasEmptyDominance = false;

        List<AnnisAttribute> attributes = fetchAnnos(corpus.getName());

        // do some preparations first
        for (AnnisAttribute a : attributes) {
            if (a.getType() == AnnisAttribute.Type.node) {
                // check for ambigous names
                String name = killNamespace(a.getName());
                if (nodeAnnoNames.contains(name)) {
                    stripNodeAnno = false;
                }
                nodeAnnoNames.add(name);
            } else if (a.getType() == AnnisAttribute.Type.edge) {
                fullEdgeNames.add(a.getEdgeName());

                // check if we need to add the general dominance example edge
                if (a.getSubtype() == AnnisAttribute.SubType.d) {
                    hasDominance = true;
                    if (a.getEdgeName() == null || a.getEdgeName().isEmpty()) {
                        hasEmptyDominance = true;
                    }
                }

                String annoName = killNamespace(a.getName());
                if (edgeAnnoNames.contains(annoName)) {
                    stripEdgeAnno = false;
                }
                edgeAnnoNames.add(annoName);

            }
        }

        // check if collected edge names are unique
        for (String edgeName : fullEdgeNames) {
            String name = killNamespace(edgeName);
            if (edgeNames.contains(name)) {
                stripEdgeName = false;
            }
            edgeNames.add(name);
        }

        if (hasDominance && !hasEmptyDominance) {
            CorpusBrowserEntry cbe = new CorpusBrowserEntry();
            cbe.setName("(dominance)");
            cbe.setCorpus(corpus);
            cbe.setExample("node & node & #1 > #2");
            containerEdgeType.addBean(cbe);
        }

        // secound round, fill the actual containers
        Set<String> metaAnnosKey = new HashSet<>();
        for (AnnisAttribute a : attributes) {
            // if the annotation name is already in the example skip this.
            if (a.getType() == AnnisAttribute.Type.meta && !metaAnnosKey.contains(killNamespace(a.getName()))) {
                String name = killNamespace(a.getName());
                metaAnnosKey.add(name);
                CorpusBrowserEntry cbe = new CorpusBrowserEntry();
                cbe.setName(name);
                cbe.setExample("node & meta::" + name + "=\"" + getFirst(a.getValueSet()) + "\"");
                cbe.setCorpus(corpus);
                containerMetaAnno.addBean(cbe);
            }

            if (a.getType() == AnnisAttribute.Type.node) {
                String name = stripNodeAnno ? killNamespace(a.getName()) : a.getName();
                CorpusBrowserEntry cbe = new CorpusBrowserEntry();
                cbe.setName(name);
                cbe.setExample(name + "=\"" + getFirst(a.getValueSet()) + "\"");
                cbe.setCorpus(corpus);
                containerNodeAnno.addBean(cbe);
            } else if (a.getType() == AnnisAttribute.Type.edge) {
                // edge type entry (multiple entries will be removed automatically)
                CorpusBrowserEntry cbeEdgeType = new CorpusBrowserEntry();
                String name = stripEdgeName ? killNamespace(a.getEdgeName()) : a.getEdgeName();
                if ((name == null || name.isEmpty()) && a.getSubtype() == AnnisAttribute.SubType.d) {
                    cbeEdgeType.setName("(dominance)");
                } else {
                    cbeEdgeType.setName(name);
                }
                cbeEdgeType.setCorpus(corpus);
                if (a.getSubtype() == AnnisAttribute.SubType.p) {
                    cbeEdgeType.setExample("node & node & #1 ->" + killNamespace(name) + " #2");
                } else if (a.getSubtype() == AnnisAttribute.SubType.d) {
                    cbeEdgeType.setExample("node & node & #1 >" + killNamespace(name) + " #2");
                }
                containerEdgeType.addBean(cbeEdgeType);

                // the edge annotation entry

                if (!a.getValueSet().isEmpty()) {
                    CorpusBrowserEntry cbeEdgeAnno = new CorpusBrowserEntry();
                    String edgeAnno = stripEdgeAnno ? killNamespace(a.getName()) : a.getName();
                    cbeEdgeAnno.setName(edgeAnno);
                    cbeEdgeAnno.setCorpus(corpus);
                    if (a.getSubtype() == AnnisAttribute.SubType.p) {
                        cbeEdgeAnno.setExample("node & node & #1 ->" + killNamespace(a.getEdgeName()) + "["
                                + killNamespace(a.getName()) + "=\"" + getFirst(a.getValueSet()) + "\"] #2");
                    } else if (a.getSubtype() == AnnisAttribute.SubType.d) {
                        cbeEdgeAnno.setExample("node & node & #1 >[" + killNamespace(a.getName()) + "=\""
                                + getFirst(a.getValueSet()) + "\"] #2");
                    }
                    containerEdgeAnno.addBean(cbeEdgeAnno);
                }
            }
        }

        tblNodeAnno.setSortContainerPropertyId("name");
        tblEdgeTypes.setSortContainerPropertyId("name");
        tblEdgeAnno.setSortContainerPropertyId("name");

        if (containerNodeAnno.size() == 0) {
            placeEmptyLabel(accordion, "Node Annotations");
        } else {
            accordion.addTab(tblNodeAnno, "Node Annotations", null);
        }

        if (tblEdgeAnno.getContainerDataSource().size() == 0) {
            placeEmptyLabel(accordion, "Edge Annotations");
        } else {
            accordion.addTab(tblEdgeAnno, "Edge Annotations", null);
        }

        if (tblEdgeTypes.getContainerDataSource().size() == 0) {
            placeEmptyLabel(accordion, "Edge Types");
        } else {
            accordion.addTab(tblEdgeTypes, "Edge Types", null);
        }

        if (tblMetaAnno.getContainerDataSource().size() == 0) {
            placeEmptyLabel(accordion, "Meta Annotations");
        } else {
            accordion.addTab(tblMetaAnno, "Meta Annotations", null);
        }
    }

    private List<AnnisAttribute> fetchAnnos(String toplevelCorpus) {
        Collection<AnnisAttribute> result = new ArrayList<>();
        try {
            WebResource service = Helper.getAnnisWebResource();
            if (service != null) {
                WebResource query = service.path("query").path("corpora").path(urlPathEscape.escape(toplevelCorpus))
                        .path("annotations").queryParam("fetchvalues", "true")
                        .queryParam("onlymostfrequentvalues", "true");
                result = query.get(new AnnisAttributeListType());
            }
        } catch (UniformInterfaceException ex) {
            log.error(null, ex);
            Notification.show("Remote exception: " + ex.getLocalizedMessage(), Notification.Type.WARNING_MESSAGE);
        } catch (ClientHandlerException ex) {
            log.error(null, ex);
            Notification.show("Remote exception: " + ex.getLocalizedMessage(), Notification.Type.WARNING_MESSAGE);
        }
        return new LinkedList<>(result);
    }

    public static class ExampleTable extends Table {

        public ExampleTable(CitationLinkGenerator citationGenerator,
                BeanItemContainer<CorpusBrowserEntry> container) {
            setContainerDataSource(container);
            addGeneratedColumn("genlink", citationGenerator);
            setSizeFull();
            setSelectable(true);
            setMultiSelect(false);

            addGeneratedColumn("example", new ColumnGenerator() {
                @Override
                public Object generateCell(Table source, Object itemId, Object columnId) {
                    CorpusBrowserEntry corpusBrowserEntry = (CorpusBrowserEntry) itemId;
                    Label l = new Label(corpusBrowserEntry.getExample());
                    l.setContentMode(ContentMode.TEXT);
                    l.addStyleName(Helper.CORPUS_FONT_FORCE);
                    return l;
                }
            });

            setVisibleColumns(new String[] { "name", "example", "genlink" });
            setColumnHeaders(new String[] { "Name", "Example (click to use query)", "URL" });
            setColumnExpandRatio("name", 0.3f);
            setColumnExpandRatio("example", 0.7f);
            setImmediate(true);
        }
    }

    public class ExampleListener implements ValueChangeListener {

        @Override
        public void valueChange(ValueChangeEvent event) {

            CorpusBrowserEntry cbe = (CorpusBrowserEntry) event.getProperty().getValue();
            Set<String> corpusNameSet = new HashSet<>();
            corpusNameSet.add(corpus.getName());
            if (controller != null && cbe != null) {
                controller.setQuery(new Query(cbe.getExample(), corpusNameSet));
            }
        }
    }

    public static class ExampleSorter extends DefaultItemSorter {

        @Override
        protected int compareProperty(Object propertyId, boolean sortDirection, Item item1, Item item2) {
            if ("name".equals(propertyId)) {
                String val1 = (String) item1.getItemProperty(propertyId).getValue();
                String val2 = (String) item2.getItemProperty(propertyId).getValue();

                if (sortDirection) {
                    return val1.compareToIgnoreCase(val2);
                } else {
                    return val2.compareToIgnoreCase(val1);
                }
            } else {
                return super.compareProperty(propertyId, sortDirection, item1, item2);
            }
        }
    }

    private String killNamespace(String qName) {
        if (qName == null) {
            return "";
        }
        String[] splitted = qName.split(":");
        return splitted[splitted.length - 1];
    }

    private String getFirst(Collection<String> list) {
        Iterator<String> it = list.iterator();
        return it.hasNext() ? it.next() : null;
    }

    private static class AnnisAttributeListType extends GenericType<List<AnnisAttribute>> {

        public AnnisAttributeListType() {
        }
    }

    /**
     * Places a label with the text "(No <caption>)" in the centered middle of the accordion
     * tab.
     *
     * @param accordion the target accordion
     * @param caption is set as caption of the accordion tab
     */
    private void placeEmptyLabel(Accordion accordion, String caption) {
        VerticalLayout v = new VerticalLayout();
        v.setSizeFull();
        Label l = new Label("(No " + caption + ")");
        v.addComponent(l);
        l.setSizeUndefined();
        v.setComponentAlignment(l, Alignment.MIDDLE_CENTER);
        accordion.addTab(v, caption, null);
        l.setSizeUndefined();
    }
}