net.sf.jasperreports.engine.export.tabulator.DimensionEntries.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jasperreports.engine.export.tabulator.DimensionEntries.java

Source

/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.jasperreports.engine.export.tabulator;

import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.jasperreports.engine.JRRuntimeException;

/**
 * @author Lucian Chirita (lucianc@users.sourceforge.net)
 */
public class DimensionEntries<T extends DimensionEntry> {
    private static final Log log = LogFactory.getLog(DimensionEntries.class);
    public static final String EXCEPTION_MESSAGE_KEY_END_OUT_OF_RANGE = "export.tabulator.dimension.end.out.of.range";
    public static final String EXCEPTION_MESSAGE_KEY_START_OUT_OF_RANGE = "export.tabulator.dimension.start.out.of.range";

    private DimensionControl<T> control;
    private TreeSet<T> entries;

    public DimensionEntries(DimensionControl<T> control) {
        this.control = control;
        this.entries = new TreeSet<T>();

        // TODO lucianc no index for column
        T univEntry = control.createEntry(DimensionEntry.MINUS_INF, DimensionEntry.PLUS_INF);
        this.entries.add(univEntry);
    }

    @Override
    public String toString() {
        return "DimensionEntries " + logId();
    }

    protected String logId() {
        return Integer.toHexString(hashCode());
    }

    public DimensionRange<T> getRange(int start, int end) {
        if (start > end) {
            throw new IllegalArgumentException(start + " > " + end);
        }
        if (start <= DimensionEntry.MINUS_INF) {
            throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_START_OUT_OF_RANGE, new Object[] { start });
        }
        if (end >= DimensionEntry.PLUS_INF) {
            throw new JRRuntimeException(EXCEPTION_MESSAGE_KEY_END_OUT_OF_RANGE, new Object[] { end });
        }

        T startKey = control.entryKey(start);
        T floor = entries.floor(startKey);
        assert floor != null;

        NavigableSet<T> tailSet = entries.tailSet(floor, true);

        T endKey = control.entryKey(end);
        T ceiling = tailSet.ceiling(endKey);

        NavigableSet<T> rangeSet;
        if (ceiling == null) {
            rangeSet = tailSet;
        } else {
            rangeSet = tailSet.headSet(ceiling, false);
        }

        return new DimensionRange<T>(start, end, floor, ceiling, rangeSet);
    }

    public DimensionRange<T> addEntries(DimensionRange<T> range) {
        T resultStart = addStartEntry(range);
        assert resultStart != null && resultStart.startCoord == range.start;

        T resultEnd = addEndEntry(range);
        assert resultEnd != null && resultEnd.startCoord == range.end;

        // check if the final range is the same as the initial range
        if (resultStart.startCoord == range.floor.startCoord
                && (range.ceiling != null && resultEnd.startCoord == range.ceiling.startCoord)) {
            return range;
        }

        // not the same, create a new range 
        NavigableSet<T> resultRange = range.rangeSet.subSet(resultStart, true, resultEnd, false);
        return new DimensionRange<T>(range.start, range.end, resultStart, resultEnd, resultRange);
    }

    protected T addStartEntry(DimensionRange<T> range) {
        T resultStart;
        if (range.floor.startCoord < range.start) {
            int entryEnd;
            T splitEntry = null;
            if (range.floor.endCoord > range.start) {
                splitEntry = range.floor;
                entryEnd = splitEntry.endCoord;
            } else {
                assert range.floor == entries.last();
                if (range.floor.endCoord < range.start) {
                    addEntry(range.floor.endCoord, range.start, null);
                }
                entryEnd = range.end;
            }

            resultStart = addEntry(range.start, entryEnd, splitEntry);
        } else {
            resultStart = range.floor;
        }
        return resultStart;
    }

    protected T addEndEntry(DimensionRange<T> range) {

        T resultEnd;
        if (range.ceiling != null && range.ceiling.startCoord == range.end) {
            resultEnd = range.ceiling;
        } else {
            T last = range.rangeSet.last();
            // we just added the start entry, so rangeSet can't be empty
            assert last != null;

            if (range.ceiling == null) {
                assert last.endCoord > range.end;
                resultEnd = addEntry(range.end, last.endCoord, last);
            } else //range.ceiling.startCoord > range.end
            {
                resultEnd = addEntry(range.end, range.ceiling.startCoord, last);
            }
        }
        return resultEnd;
    }

    protected T addEntry(int startCoord) {
        T entryKey = control.entryKey(startCoord);
        T floorEntry = entries.floor(entryKey);
        assert floorEntry != null;

        T startEntry;
        if (floorEntry.startCoord == startCoord) {
            startEntry = floorEntry;
        } else //floorEntry.startCoord < startCoord
        {
            startEntry = addEntry(startCoord, floorEntry.endCoord, floorEntry);
        }

        return startEntry;
    }

    protected T addEntry(int startCoord, int endCoord) {
        assert startCoord < endCoord;
        T entryKey = control.entryKey(startCoord);
        T floorEntry = entries.floor(entryKey);
        assert floorEntry != null;
        assert endCoord <= floorEntry.endCoord;

        T startEntry;
        if (floorEntry.startCoord == startCoord) {
            startEntry = floorEntry;
        } else //floorEntry.startCoord < startCoord
        {
            startEntry = addEntry(startCoord, floorEntry.endCoord, floorEntry);
        }

        if (endCoord < startEntry.endCoord) {
            addEntry(endCoord, startEntry.endCoord, startEntry);
        }
        return startEntry;
    }

    protected T addEntry(int startCoord, int endCoord, T splitEntry) {
        assert startCoord < endCoord;
        T entry = control.createEntry(startCoord, endCoord);
        boolean added = entries.add(entry);
        assert added;

        if (splitEntry == null) {
            assert (entry == entries.first()
                    && (entries.size() == 1 || endCoord == entries.higher(entry).startCoord))
                    || (entry == entries.last()
                            && (entries.size() == 1 || startCoord == entries.lower(entry).endCoord));
        } else {
            assert splitEntry.startCoord < startCoord;
            assert splitEntry.endCoord == endCoord;

            splitEntry.endCoord = startCoord;
            control.entrySplit(splitEntry, entry);
        }

        if (log.isTraceEnabled()) {
            log.trace(logId() + ": added entry " + entry + ", split " + splitEntry);
        }

        return entry;
    }

    public void addMargins(int extent) {
        if (log.isTraceEnabled()) {
            log.trace("add margins to extent " + extent);
        }

        T firstEntry = entries.higher(entries.first());
        int marginStart = (firstEntry == null || firstEntry.startCoord > 0) ? 0 : firstEntry.startCoord;

        T lastEntry = entries.lower(entries.last());
        int marginEnd = (lastEntry == null || lastEntry.endCoord < extent) ? extent : lastEntry.endCoord;

        DimensionRange<T> range = getRange(marginStart, marginEnd);
        addEntries(range);
    }

    public void removeEntry(T entry, T prevEntry) {
        assert prevEntry.endCoord == entry.startCoord;
        boolean removed = entries.remove(entry);
        assert removed;
        prevEntry.endCoord = entry.endCoord;

        if (log.isTraceEnabled()) {
            log.trace(logId() + ": removed entry at " + entry.startCoord);
        }
    }

    public NavigableSet<T> getEntries() {
        return entries;
    }

    public SortedSet<T> getUserEntries() {
        return entries.subSet(entries.first(), false, entries.last(), false);
    }

    public DimensionControl<T> getControl() {
        return control;
    }
}