Search in sources :

Example 1 with GridEvent

use of org.corpus_tools.annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method splitRowsOnGaps.

/**
 * Splits events of a row if they contain a gap. Gaps are found using the token index (provided as
 * ANNIS specific {@link SFeature}. Inserted events have a special style to mark them as gaps.
 *
 * @param row
 * @param graph
 * @param token2index
 */
private static void splitRowsOnGaps(Row row, final SDocumentGraph graph, Map<SToken, Integer> token2index) {
    ListIterator<GridEvent> itEvents = row.getEvents().listIterator();
    while (itEvents.hasNext()) {
        GridEvent event = itEvents.next();
        int lastTokenIndex = -1;
        // sort the coveredIDs
        LinkedList<String> sortedCoveredToken = new LinkedList<>(event.getCoveredIDs());
        Collections.sort(sortedCoveredToken, (o1, o2) -> {
            SToken node1 = (SToken) graph.getNode(o1);
            SToken node2 = (SToken) graph.getNode(o2);
            if (node1 == node2) {
                return 0;
            }
            if (node1 == null) {
                return -1;
            }
            if (node2 == null) {
                return +1;
            }
            long tokenIndex1 = token2index.get(node1);
            long tokenIndex2 = token2index.get(node2);
            return ((Long) (tokenIndex1)).compareTo(tokenIndex2);
        });
        // first calculate all gaps
        List<GridEvent> gaps = new LinkedList<>();
        for (String id : sortedCoveredToken) {
            SToken node = (SToken) graph.getNode(id);
            int tokenIndex = token2index.get(node);
            // sanity check
            if (tokenIndex >= event.getLeft() && tokenIndex <= event.getRight()) {
                int diff = tokenIndex - lastTokenIndex;
                if (lastTokenIndex >= 0 && diff > 1) {
                    // we detected a gap
                    GridEvent gap = new GridEvent(event.getId() + "_gap_" + gaps.size(), lastTokenIndex + 1, tokenIndex - 1, "");
                    gap.setGap(true);
                    gaps.add(gap);
                }
                lastTokenIndex = tokenIndex;
            } else {
                // reset gap search when discovered there were token we use for
                // hightlighting but do not actually cover
                lastTokenIndex = -1;
            }
        }
        // end for each covered token id
        ListIterator<GridEvent> itGaps = gaps.listIterator();
        // remember the old right value
        int oldRight = event.getRight();
        int gapNr = 0;
        while (itGaps.hasNext()) {
            GridEvent gap = itGaps.next();
            if (gapNr == 0) {
                // shorten original event
                event.setRight(gap.getLeft() - 1);
            }
            // insert the real gap
            itEvents.add(gap);
            int rightBorder = oldRight;
            if (itGaps.hasNext()) {
                // don't use the old event right border since the gap should only go until
                // the next event
                GridEvent nextGap = itGaps.next();
                itGaps.previous();
                rightBorder = nextGap.getLeft() - 1;
            }
            // insert a new event node that covers the rest of the event
            GridEvent after = new GridEvent(event);
            after.setId(event.getId() + "_after_" + gapNr);
            after.setLeft(gap.getRight() + 1);
            after.setRight(rightBorder);
            itEvents.add(after);
            gapNr++;
        }
    }
}
Also used : SToken(org.corpus_tools.salt.common.SToken) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) LinkedList(java.util.LinkedList)

Example 2 with GridEvent

use of org.corpus_tools.annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class SingleGridComponent method createAnnotationGrid.

private boolean createAnnotationGrid() {
    String resultID = input.getId();
    grid = new AnnotationGrid(mediaController, pdfController, resultID);
    grid.addStyleName(getMainStyle());
    grid.addStyleName(Helper.CORPUS_FONT_FORCE);
    grid.setEscapeHTML(Boolean.parseBoolean(input.getMappings().getOrDefault(MAPPING_ESCAPE_HTML, "true")));
    LinkedList<Class<? extends SNode>> types = new LinkedList<>();
    if (isShowingSpanAnnotations()) {
        types.add(SSpan.class);
    }
    if (isShowingTokenAnnotations()) {
        types.add(SToken.class);
    }
    grid.setAnnosWithNamespace(EventExtractor.computeDisplayedNamespace(input, types));
    layout.addComponent(grid);
    SDocumentGraph graph = input.getDocument().getDocumentGraph();
    List<SNode> sortedSegmentationNodes = Helper.getSortedSegmentationNodes(this.segmentationName, graph);
    Map<SToken, Integer> token2index = Helper.createToken2IndexMap(graph, this.enforcedText);
    Preconditions.checkArgument(!token2index.isEmpty(), "Token list must be non-empty");
    LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation = computeAnnotationRows(token2index);
    // Get Mappings
    String gridTemplates = input.getMappings().getOrDefault(MAPPING_GRID_TEMPLATES, "");
    // Parse Mappings
    if (!gridTemplates.equals("")) {
        String[] split = gridTemplates.split("\\|\\|");
        for (String s : split) {
            // example of s: entity="person"==>:), or infstat==><b>%%value%%</b>
            String[] unit_split = s.split("==>");
            Set<Map.Entry<String, ArrayList<Row>>> set = rowsByAnnotation.entrySet();
            // Displaying elements of LinkedHashMap
            Iterator<Map.Entry<String, ArrayList<Row>>> iterator = set.iterator();
            while (iterator.hasNext()) {
                // iterate over rows
                Map.Entry<String, ArrayList<Row>> me = iterator.next();
                String rowKey = me.getKey();
                ArrayList<Row> rowValue = me.getValue();
                for (Row rowValue1 : rowValue) {
                    ArrayList<GridEvent> rowEvents = rowValue1.getEvents();
                    if (unit_split[0].indexOf('=') < 0) {
                        // unit_split[0] is a single instruction, e.g., infstat
                        // check if the key of a row in rowsByAnnotation is unit_split[0]
                        // if it is, we need to change every value of this row, else we dont do anything
                        String rowName = rowKey.split("::")[1];
                        if (rowName.equals(unit_split[0])) {
                            // iterate over all values and replace the value with the unit_split[1]
                            for (GridEvent ev : rowEvents) {
                                String origValue = ev.getValue();
                                String newValue = unit_split[1].replaceAll("%%value%%", origValue);
                                ev.setValue(newValue);
                            }
                        }
                    } else {
                        // its a instruction like entity='person'
                        // first break this split into entity and person
                        // check if rowKey is entity, then when iterating over events, check if value is
                        // person
                        String rowName = rowKey.split("::")[1];
                        String targetRow = unit_split[0].split("=")[0];
                        String targetValue = unit_split[0].split("=")[1].replaceAll("\"", "");
                        if (rowName.equals(targetRow)) {
                            // iterate over all values and replace the value with the unit_split[1]
                            for (GridEvent ev : rowEvents) {
                                String origValue = ev.getValue();
                                if (origValue.equals(targetValue)) {
                                    ev.setValue(unit_split[1]);
                                }
                            // String newValue = unit_split[1].replaceAll("%%value%%",origValue);
                            }
                        }
                    }
                }
            }
        }
    }
    // add tokens as row
    Row tokenRow = computeTokenRow(sortedSegmentationNodes, graph, rowsByAnnotation, token2index);
    String tokenRowCaption = "tok";
    if (isHidingToken()) {
        // We have to add the invisible token row avoid issues with the layout
        // (see https://github.com/korpling/ANNIS/issues/524)
        // but we don't want the invisible token layer to override an actual "tok"
        // annotation layer (see https://github.com/korpling/ANNIS/issues/596)
        tokenRow.setStyle("invisible_token");
        tokenRowCaption = "";
        grid.setTokRowKey("");
    }
    if (isTokenFirst()) {
        // copy original list but add token row at the beginning
        LinkedHashMap<String, ArrayList<Row>> newList = new LinkedHashMap<>();
        newList.put(tokenRowCaption, Lists.newArrayList(tokenRow));
        newList.putAll(rowsByAnnotation);
        rowsByAnnotation = newList;
    } else {
        // just add the token row to the end of the list
        rowsByAnnotation.put(tokenRowCaption, Lists.newArrayList(tokenRow));
    }
    EventExtractor.removeEmptySpace(rowsByAnnotation, tokenRow);
    // check if the token row only contains empty values
    boolean tokenRowIsEmpty = true;
    for (GridEvent tokenEvent : tokenRow.getEvents()) {
        if (tokenEvent.getValue() != null && !tokenEvent.getValue().trim().isEmpty()) {
            tokenRowIsEmpty = false;
            break;
        }
    }
    if (!isHidingToken() && canShowEmptyTokenWarning()) {
        lblEmptyToken.setVisible(tokenRowIsEmpty);
    }
    grid.setRowsByAnnotation(rowsByAnnotation);
    return !tokenRowIsEmpty;
}
Also used : SNode(org.corpus_tools.salt.core.SNode) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) SToken(org.corpus_tools.salt.common.SToken) AnnotationGrid(org.corpus_tools.annis.gui.widgets.grid.AnnotationGrid) SDocumentGraph(org.corpus_tools.salt.common.SDocumentGraph) LinkedList(java.util.LinkedList) Row(org.corpus_tools.annis.gui.widgets.grid.Row) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 3 with GridEvent

use of org.corpus_tools.annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class SingleGridComponent method computeTokenRow.

private Row computeTokenRow(List<SNode> tokens, SDocumentGraph graph, LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, Map<SToken, Integer> token2index) {
    /*
     * we will only add tokens of one texts which is mentioned by any included annotation.
     */
    Set<String> validTextIDs = new HashSet<>();
    if (enforcedText == null) {
        Iterator<ArrayList<Row>> itAllRows = rowsByAnnotation.values().iterator();
        while (itAllRows.hasNext()) {
            ArrayList<Row> rowsForAnnotation = itAllRows.next();
            for (Row r : rowsForAnnotation) {
                validTextIDs.addAll(r.getTextIDs());
            }
        }
        /**
         * we want to show all token if no valid text was found and we have only one text and the
         * first one if there is more than one text.
         */
        List<STextualDS> allTexts = graph.getTextualDSs();
        if (validTextIDs.isEmpty() && allTexts != null && (allTexts.size() == 1 || allTexts.size() == 2)) {
            validTextIDs.add(allTexts.get(0).getId());
        }
    } else {
        validTextIDs.add(enforcedText.getId());
    }
    Row tokenRow = new Row();
    for (SNode t : tokens) {
        // get the Salt ID of the STextualDS of this token
        STextualDS tokenText = Helper.getTextualDSForNode(t, graph);
        // only add token if text ID matches the valid one
        if (tokenText != null && validTextIDs.contains(tokenText.getId()) && hasSegmentation(t, this.segmentationName)) {
            Range<Integer> coveredRange = Helper.getLeftRightSpan(t, graph, token2index);
            String text = extractTextForToken(t, segmentationName);
            GridEvent event = new GridEvent(t.getId(), coveredRange.lowerEndpoint(), coveredRange.upperEndpoint(), text);
            event.setTextID(tokenText.getId());
            // check if the token is a matched node
            Long match = isCoveredTokenMarked() ? markCoveredTokens(input.getMarkedAndCovered(), t) : tokenMatch(t);
            event.setMatch(match);
            tokenRow.addEvent(event);
        }
    }
    return tokenRow;
}
Also used : SNode(org.corpus_tools.salt.core.SNode) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) ArrayList(java.util.ArrayList) STextualDS(org.corpus_tools.salt.common.STextualDS) Row(org.corpus_tools.annis.gui.widgets.grid.Row) HashSet(java.util.HashSet)

Example 4 with GridEvent

use of org.corpus_tools.annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method splitRowsOnIslands.

/**
 * Splits events of a row if they overlap an island. Islands are areas between the token which are
 * included in the result.
 *
 * @param row
 * @param graph
 * @param text
 * @param token2index
 */
private static void splitRowsOnIslands(Row row, final SDocumentGraph graph, STextualDS text, Map<SToken, Integer> token2index) {
    BitSet tokenCoverage = new BitSet();
    // get the sorted token
    List<SToken> sortedTokenList = graph.getSortedTokenByText();
    // add all token belonging to the right text to the bit set
    ListIterator<SToken> itToken = sortedTokenList.listIterator();
    while (itToken.hasNext()) {
        SToken t = itToken.next();
        if (text == null || text == Helper.getTextualDSForNode(t, graph)) {
            int tokenIndex = token2index.get(t);
            tokenCoverage.set(tokenIndex);
        }
    }
    ListIterator<GridEvent> itEvents = row.getEvents().listIterator();
    while (itEvents.hasNext()) {
        GridEvent event = itEvents.next();
        BitSet eventBitSet = new BitSet();
        eventBitSet.set(event.getLeft(), event.getRight() + 1);
        // restrict event bitset on the locations where token are present
        eventBitSet.and(tokenCoverage);
        // and we need to split it
        if (eventBitSet.nextClearBit(event.getLeft()) <= event.getRight()) {
            // remove the original event
            row.removeEvent(itEvents);
            // The event bitset now marks all the locations which the event should
            // cover.
            // Make a list of new events for each connected range in the bitset
            int subElement = 0;
            int offset = eventBitSet.nextSetBit(0);
            while (offset >= 0) {
                int end = eventBitSet.nextClearBit(offset) - 1;
                if (offset < end) {
                    GridEvent newEvent = new GridEvent(event);
                    newEvent.setId(event.getId() + "_islandsplit_" + subElement++);
                    newEvent.setLeft(offset);
                    newEvent.setRight(end);
                    row.addEvent(itEvents, newEvent);
                }
                offset = eventBitSet.nextSetBit(end + 1);
            }
        }
    // end if we need to split
    }
}
Also used : SToken(org.corpus_tools.salt.common.SToken) GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) BitSet(java.util.BitSet)

Example 5 with GridEvent

use of org.corpus_tools.annis.gui.widgets.grid.GridEvent in project ANNIS by korpling.

the class EventExtractor method removeEmptySpace.

public static void removeEmptySpace(LinkedHashMap<String, ArrayList<Row>> rowsByAnnotation, Row tokenRow) {
    List<Range<Integer>> gaps = new LinkedList<>();
    BitSet totalOccupancyGrid = new BitSet();
    for (Map.Entry<String, ArrayList<Row>> layer : rowsByAnnotation.entrySet()) {
        for (Row r : layer.getValue()) {
            totalOccupancyGrid.or(r.getOccupancyGridCopy());
        }
    }
    // bug report.
    if (tokenRow != null) {
        totalOccupancyGrid.or(tokenRow.getOccupancyGridCopy());
    }
    // The Range class can give us the next bit that is not set. Use this
    // to detect gaps. A gap starts from the next non-set bit and goes to
    // the next set bit.
    Range<Integer> gap = Range.closed(-1, totalOccupancyGrid.nextSetBit(0));
    while (true) {
        int gapStart = totalOccupancyGrid.nextClearBit(gap.upperEndpoint() + 1);
        int gapEnd = totalOccupancyGrid.nextSetBit(gapStart);
        if (gapEnd <= 0) {
            break;
        }
        gap = Range.closed(gapStart, gapEnd - 1);
        gaps.add(gap);
    }
    int gapID = 0;
    int totalOffset = 0;
    for (Range<Integer> gRaw : gaps) {
        // adjust the space range itself
        Range<Integer> g = Range.closed(gRaw.lowerEndpoint() - totalOffset, gRaw.upperEndpoint() - totalOffset);
        int offset = g.upperEndpoint() - g.lowerEndpoint();
        totalOffset += offset;
        for (Entry<String, ArrayList<Row>> rowEntry : rowsByAnnotation.entrySet()) {
            ArrayList<Row> rows = rowEntry.getValue();
            for (Row r : rows) {
                List<GridEvent> eventsCopy = new LinkedList<>(r.getEvents());
                for (GridEvent e : eventsCopy) {
                    if (e.getLeft() >= g.upperEndpoint()) {
                        r.removeEvent(e);
                        e.setLeft(e.getLeft() - offset);
                        e.setRight(e.getRight() - offset);
                        r.addEvent(e);
                    }
                }
                // add a special space event
                String spaceCaption = "";
                if ("tok".equalsIgnoreCase(rowEntry.getKey())) {
                    spaceCaption = "(...)";
                }
                GridEvent spaceEvent = new GridEvent("gap-" + gapID, g.lowerEndpoint(), g.lowerEndpoint(), spaceCaption);
                spaceEvent.setSpace(true);
                r.addEvent(spaceEvent);
                gapID++;
            }
        }
    }
}
Also used : GridEvent(org.corpus_tools.annis.gui.widgets.grid.GridEvent) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) Range(com.google.common.collect.Range) LinkedList(java.util.LinkedList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Row(org.corpus_tools.annis.gui.widgets.grid.Row) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Aggregations

GridEvent (org.corpus_tools.annis.gui.widgets.grid.GridEvent)9 ArrayList (java.util.ArrayList)7 Row (org.corpus_tools.annis.gui.widgets.grid.Row)7 GridKt (com.github.mvysny.kaributesting.v8.GridKt)3 LocatorJ._click (com.github.mvysny.kaributesting.v8.LocatorJ._click)3 LocatorJ._find (com.github.mvysny.kaributesting.v8.LocatorJ._find)3 LocatorJ._get (com.github.mvysny.kaributesting.v8.LocatorJ._get)3 LocatorJ._setValue (com.github.mvysny.kaributesting.v8.LocatorJ._setValue)3 MockVaadin (com.github.mvysny.kaributesting.v8.MockVaadin)3 NotificationsKt (com.github.mvysny.kaributesting.v8.NotificationsKt)3 DataProvider (com.vaadin.data.provider.DataProvider)3 ListDataProvider (com.vaadin.data.provider.ListDataProvider)3 VaadinIcons (com.vaadin.icons.VaadinIcons)3 Page (com.vaadin.server.Page)3 ContentMode (com.vaadin.shared.ui.ContentMode)3 UIScopeImpl (com.vaadin.spring.internal.UIScopeImpl)3 Accordion (com.vaadin.ui.Accordion)3 Button (com.vaadin.ui.Button)3 ComboBox (com.vaadin.ui.ComboBox)3 Component (com.vaadin.ui.Component)3