annis.gui.docbrowser.DocBrowserController.java Source code

Java tutorial

Introduction

Here is the source code for annis.gui.docbrowser.DocBrowserController.java

Source

/*
 * Copyright 2013 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.docbrowser;

import annis.gui.AnnisUI;
import annis.libgui.Background;
import annis.libgui.Helper;
import annis.libgui.PluginSystem;
import annis.libgui.visualizers.FilteringVisualizerPlugin;
import annis.libgui.visualizers.VisualizerInput;
import annis.libgui.visualizers.VisualizerPlugin;
import annis.service.objects.CorpusConfig;
import annis.service.objects.RawTextWrapper;
import annis.service.objects.Visualizer;
import com.google.common.base.Joiner;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.sun.jersey.api.client.WebResource;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.Resource;
import com.vaadin.server.Sizeable.Unit;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.Component;
import com.vaadin.ui.Panel;
import com.vaadin.ui.ProgressBar;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang3.StringUtils;
import org.corpus_tools.salt.common.SDocument;
import org.corpus_tools.salt.common.SaltProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Represents a global controller for the doc browser feature.
 *
 * @author Benjamin Weienfels <b.pixeldrama@gmail.com>
 */
public class DocBrowserController implements Serializable {

    private final Logger log = LoggerFactory.getLogger(DocBrowserController.class);

    // holds the complete state of the gui
    private final AnnisUI ui;

    // track the already initiated doc browsers
    private final Map<String, Component> initedDocBrowsers;

    // cache for already initiated visualizations, the key is the doc name
    private final Map<String, Component> initiatedVis;

    // keep track of already visible doc visualizer, so it easy to switch to them.
    private final Map<String, Panel> visibleVisHolder;

    private static final Resource EYE_ICON = FontAwesome.EYE;

    private static final Resource DOC_ICON = FontAwesome.FILE_TEXT_O;

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

    public DocBrowserController(AnnisUI ui) {
        this.ui = ui;
        this.initedDocBrowsers = new HashMap<>();
        this.initiatedVis = new HashMap<>();
        this.visibleVisHolder = new HashMap<>();
    }

    public void openDocVis(String corpus, String doc, Visualizer visConfig, Button btn) {

        final String canonicalTitle = corpus + " > " + doc + " - " + "Visualizer: " + visConfig.getDisplayName();
        final String tabCaption = StringUtils.substring(canonicalTitle, 0, 15) + "...";

        if (visibleVisHolder.containsKey(canonicalTitle)) {
            Panel visHolder = visibleVisHolder.get(canonicalTitle);
            ui.getSearchView().getTabSheet().setSelectedTab(visHolder);
            return;
        }

        Panel visHolder = new Panel();
        visHolder.setSizeFull();
        visHolder.addDetachListener(new ClientConnector.DetachListener() {
            @Override
            public void detach(ClientConnector.DetachEvent event) {
                visibleVisHolder.remove(canonicalTitle);
            }
        });

        // first set loading indicator
        ProgressBar progressBar = new ProgressBar(1.0f);
        progressBar.setIndeterminate(true);
        progressBar.setSizeFull();
        VerticalLayout layoutProgress = new VerticalLayout(progressBar);
        layoutProgress.setSizeFull();
        layoutProgress.setComponentAlignment(progressBar, Alignment.MIDDLE_CENTER);

        visHolder.setContent(layoutProgress);

        Tab visTab = ui.getSearchView().getTabSheet().addTab(visHolder, tabCaption);
        visTab.setDescription(canonicalTitle);
        visTab.setIcon(EYE_ICON);
        visTab.setClosable(true);
        ui.getSearchView().getTabSheet().setSelectedTab(visTab);

        // register visible visHolder
        this.visibleVisHolder.put(canonicalTitle, visHolder);

        Background.run(new DocVisualizerFetcher(corpus, doc, canonicalTitle, visConfig.getType(), visHolder,
                visConfig, btn, UI.getCurrent()));
    }

    public void openDocBrowser(String corpus) {
        // if not already init, do it now
        if (!initedDocBrowsers.containsKey(corpus)) {
            DocBrowserPanel docBrowser = DocBrowserPanel.initDocBrowserPanel(ui, corpus);
            initedDocBrowsers.put(corpus, docBrowser);
        }

        // init tab and put to front
        TabSheet.Tab tab = ui.getSearchView().getTabSheet().addTab(initedDocBrowsers.get(corpus), corpus);
        tab.setIcon(DOC_ICON);
        tab.setClosable(true);
        ui.getSearchView().getTabSheet().setSelectedTab(tab);
    }

    /**
     * Creates the input. It only takes the salt project or the raw text from the
     * text table, never both, since the increase the performance for large texts.
     *
     * @param corpus the name of the toplevel corpus
     * @param docName the name of the document
     * @param config the visualizer configuration
     * @param isUsingRawText indicates, whether the text from text table is taken,
     * or if the salt project is traversed.
     * @param nodeAnnoFilter A list of node annotation names for filtering the nodes or null if no filtering should be applied.
     * @return a {@link VisualizerInput} input, which is usable for rendering the
     * whole document.
     */
    public static VisualizerInput createInput(String corpus, String docName, Visualizer config,
            boolean isUsingRawText, List<String> nodeAnnoFilter) {
        VisualizerInput input = new VisualizerInput();

        // set mappings and namespaces. some visualizer do not survive without   
        input.setMappings(parseMappings(config));
        input.setNamespace(config.getNamespace());

        String encodedToplevelCorpus = urlPathEscape.escape(corpus);
        String encodedDocument = urlPathEscape.escape(docName);
        if (isUsingRawText) {
            WebResource w = Helper.getAnnisWebResource();
            w = w.path("query").path("rawtext").path(encodedToplevelCorpus).path(encodedDocument);
            RawTextWrapper rawTextWrapper = w.get(RawTextWrapper.class);
            input.setRawText(rawTextWrapper);
        } else {
            // get the whole document wrapped in a salt project
            SaltProject txt = null;

            WebResource res = Helper.getAnnisWebResource().path("query").path("graph").path(encodedToplevelCorpus)
                    .path(encodedDocument);

            if (nodeAnnoFilter != null) {
                res = res.queryParam("filternodeanno", Joiner.on(",").join(nodeAnnoFilter));
            }

            txt = res.get(SaltProject.class);

            if (txt != null) {
                SDocument sDoc = txt.getCorpusGraphs().get(0).getDocuments().get(0);
                input.setResult(sDoc);
            }
        }

        return input;
    }

    private static Properties parseMappings(Visualizer config) {
        Properties mappings = new Properties();

        if (config.getMappings() != null) {
            // split the entrys
            String[] entries = config.getMappings().split(";");
            for (String e : entries) {
                // split key-value
                String[] keyvalue = e.split(":", 2);
                if (keyvalue.length == 2) {
                    mappings.put(keyvalue[0].trim(), keyvalue[1].trim());
                }
            }
        }

        return mappings;
    }

    private class DocVisualizerFetcher implements Runnable {

        Visualizer config;

        String corpus;

        String doc;

        final Button btn;

        private final String canonicalTitle;

        private final String type;

        private final Panel visHolder;

        private VisualizerInput input;

        public DocVisualizerFetcher(String corpus, String doc, String canonicalTitle, String type, Panel visHolder,
                Visualizer config, Button btn, final UI ui) {
            this.corpus = corpus;
            this.doc = doc;
            this.btn = btn;
            this.config = config;
            this.canonicalTitle = canonicalTitle;
            this.type = type;
            this.visHolder = visHolder;
        }

        @Override
        public void run() {
            input = null;

            final boolean createVis = !initiatedVis.containsKey(canonicalTitle);

            final VisualizerPlugin visualizer = ((PluginSystem) ui).getVisualizer(type);

            List<String> nodeAnnoFilter = null;
            if (visualizer instanceof FilteringVisualizerPlugin) {
                nodeAnnoFilter = ((FilteringVisualizerPlugin) visualizer).getFilteredNodeAnnotationNames(corpus,
                        doc, parseMappings(config));
            }

            // check if a visualization is already initiated
            {
                if (createVis) {
                    // fetch the salt project - so long part
                    input = createInput(corpus, doc, config, visualizer.isUsingRawText(), nodeAnnoFilter);

                }
            }

            // after initializing the visualizer update the gui
            ui.access(new Runnable() {
                @Override
                public void run() {

                    btn.setEnabled(true);

                    if (createVis && input != null) {
                        // create and format visualizer

                        Component vis = visualizer.createComponent(input, null);
                        vis.addStyleName(Helper.CORPUS_FONT_FORCE);
                        vis.setPrimaryStyleName("docviewer");
                        vis.setCaption(canonicalTitle);
                        vis.setWidth(100, Unit.PERCENTAGE);
                        vis.setHeight(-1, Unit.PIXELS);

                        // update visualizer memory cache
                        initiatedVis.put(canonicalTitle, vis);
                    }

                    Component vis = initiatedVis.get(canonicalTitle);
                    visHolder.setContent(vis);

                }
            });
        }
    }

    public boolean docsAvailable(String id) {
        if (ui != null) {
            CorpusConfig corpusConfig = ui.getCorpusConfigWithCache(id);

            if (corpusConfig != null) {
                if (corpusConfig.containsKey("browse-documents")) {
                    return Boolean.parseBoolean(corpusConfig.getConfig("browse-documents"));
                }

                // get the default config
                else {
                    corpusConfig = ui.getCorpusConfigWithCache(Helper.DEFAULT_CONFIG);
                    boolean browseDocuments = Boolean
                            .parseBoolean(corpusConfig.getConfig("browse-documents", "true"));
                    return browseDocuments;
                }
            }
        }

        return true;
    }
}