/* * Copyright 2012 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.widgets.grid; import java.io.Serializable; import java.util.ArrayList; import java.util.BitSet; import java.util.HashSet; import java.util.ListIterator; import java.util.Set; /** * Represents one row in the grid view * * @author Thomas Krause <krauseto@hu-berlin.de> */ public class Row implements Serializable { private final ArrayList<GridEvent> events; private final BitSet occupancySet; private final Set<String> textIDs; /** * Default constructor. */ public Row() { this.events = new ArrayList<>(); this.textIDs = new HashSet<>(); occupancySet = new BitSet(); } /** * Adds an event to this row * @param e * @return False if could not be added because the event is overlapping an * other event in the row. */ public boolean addEvent(GridEvent e) { BitSet eventOccupance = new BitSet(e.getRight()); eventOccupance.set(e.getLeft(), e.getRight()+1, true); if(occupancySet.intersects(eventOccupance)) { return false; } // set all bits to true that are covered by the other event occupancySet.or(eventOccupance); events.add(e); if(e.getTextID() != null && !e.getTextID().isEmpty()) { textIDs.add(e.getTextID()); } return true; } /** * Adds an event to this row using {@link ListIterator#add(java.lang.Object) } * @param e * @return False if could not be added because the event is overlapping an * other event in the row. */ public boolean addEvent(ListIterator<GridEvent> iterator, GridEvent e) { BitSet eventOccupance = new BitSet(e.getRight()); eventOccupance.set(e.getLeft(), e.getRight()+1, true); if(occupancySet.intersects(eventOccupance)) { return false; } // set all bits to true that are covered by the other event occupancySet.or(eventOccupance); iterator.add(e); if(e.getTextID() != null && !e.getTextID().isEmpty()) { textIDs.add(e.getTextID()); } return true; } /** * Returns true if merge is possible. * * @param other * @return * @see #merge(annis.gui.visualizers.component.grid.Row) */ public boolean canMerge(Row other) { return !occupancySet.intersects(other.occupancySet); } /** * Merges the other row into this row. * This means all events from the other {@link Row} are added to this row. The other * {@link Row} will not be changed. * Only rows which have no overlapping events can be merged. * * @param other The other {@link Row} which will be merged into this one. * @return Returns true if merge was successfull, false if no merge was done. * * @see #canMerge(annis.gui.visualizers.component.grid.Row) */ public boolean merge(Row other) throws IllegalArgumentException { if(canMerge(other)) { occupancySet.or(other.occupancySet); for(GridEvent e : other.events) { events.add(e); } return true; } else { return false; } } public ArrayList<GridEvent> getEvents() { return events; } public boolean removeEvent(GridEvent event) { boolean success = events.remove(event); if(success) { // we never allow overlapping events in a row, so we can set the area to unoccupied occupancySet.set(event.getLeft(), event.getRight()+1, false); } return success; } /** * Call {@link ListIterator#remove() } and update internal occupancy grid. * @param iterator * @return */ public void removeEvent(ListIterator<GridEvent> iterator) { if(iterator != null) { // go one step back iterator.previous(); // get the element again GridEvent event = iterator.next(); if(event != null) { iterator.remove(); // we never allow overlapping events in a row, so we can set the area to unoccupied occupancySet.set(event.getLeft(), event.getRight() + 1, false); } } } /** * Get Salt IDs of all texts used by events of this row. * @return */ public Set<String> getTextIDs() { return new HashSet<>(textIDs); } /** * Returns a copy of the internal occupancy grid. * @return */ public BitSet getOccupancyGridCopy() { return (BitSet) occupancySet.clone(); } }