ro.nextreports.server.web.pivot.PivotTable.java Source code

Java tutorial

Introduction

Here is the source code for ro.nextreports.server.web.pivot.PivotTable.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 ro.nextreports.server.web.pivot;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.RepeatingView;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.collections.MultiMap;
import org.apache.wicket.util.convert.IConverter;

import ro.nextreports.server.pivot.PivotField;
import ro.nextreports.server.pivot.PivotModel;
import ro.nextreports.server.pivot.PivotUtils;

/**
 * @author Decebal Suiu
 */
public class PivotTable extends Panel {

    private static final long serialVersionUID = 1L;

    public PivotTable(String id, PivotModel pivotModel) {
        super(id);

        List<PivotField> columnFields = pivotModel.getFields(PivotField.Area.COLUMN);
        List<PivotField> rowFields = pivotModel.getFields(PivotField.Area.ROW);
        List<PivotField> dataFields = pivotModel.getFields(PivotField.Area.DATA);

        List<List<Object>> rowKeys = pivotModel.getRowKeys();
        List<List<Object>> columnKeys = pivotModel.getColumnKeys();

        // rendering header
        RepeatingView column = new RepeatingView("header");
        add(column);
        int headerRowCount = columnFields.size();
        if (headerRowCount == 0) {
            headerRowCount = 1;
        }
        if (dataFields.size() > 1) {
            // add an extra row (the row with data field titles)
            headerRowCount++;
        }

        Component tmp = null;
        for (int i = 0; i < headerRowCount; i++) {
            // rendering row header (first columns)
            WebMarkupContainer tr = new WebMarkupContainer(column.newChildId());
            column.add(tr);
            RepeatingView rowHeader = new RepeatingView("rowHeader");
            tr.add(rowHeader);

            for (int j = 0; j < rowFields.size(); j++) {
                if (i < headerRowCount - 1) {
                    // rendering an empty cell
                    tmp = new Label(rowHeader.newChildId(), "");
                    tmp.add(AttributeModifier.append("class", "empty"));
                    rowHeader.add(tmp);
                } else {
                    // rendering row field
                    tmp = createTitleLabel(rowHeader.newChildId(), rowFields.get(j));
                    rowHeader.add(tmp);
                }
            }

            // rendering column keys
            RepeatingView value = new RepeatingView("value");
            tr.add(value);
            for (List<Object> columnKey : columnKeys) {
                if (i < columnFields.size()) {
                    PivotField columnField = columnFields.get(i);
                    tmp = createValueLabel(value.newChildId(), columnKey.get(i), columnField);
                    tmp.add(AttributeModifier.append("colspan", dataFields.size()));
                    value.add(tmp);
                } else {
                    for (PivotField dataField : dataFields) {
                        tmp = createTitleLabel(value.newChildId(), dataField);
                        value.add(tmp);
                    }
                }
            }

            // rendering grand total column
            RepeatingView grandTotalColumn = new RepeatingView("grandTotalColumn");
            if (i == 0) {
                tmp = new Label(grandTotalColumn.newChildId(), getString("pivot.grandTotal"));
                tmp.add(AttributeModifier.append("colspan", dataFields.size()));
                grandTotalColumn.add(tmp);
            } else if (i < columnFields.size()) {
                tmp = new WebMarkupContainer(grandTotalColumn.newChildId());
                tmp.add(AttributeModifier.append("colspan", dataFields.size()));
                tmp.add(AttributeModifier.append("class", "empty"));
                grandTotalColumn.add(tmp);
            } else {
                for (PivotField dataField : dataFields) {
                    tmp = createTitleLabel(value.newChildId(), dataField);
                    grandTotalColumn.add(tmp);
                }
            }
            grandTotalColumn.setVisible(!columnFields.isEmpty() && pivotModel.isShowGrandTotalForRow());
            tr.add(grandTotalColumn);
        }

        // rendering rows
        RepeatingView row = new RepeatingView("row");
        add(row);
        for (List<Object> rowKey : rowKeys) {
            WebMarkupContainer tr = new WebMarkupContainer(row.newChildId());
            row.add(tr);
            RepeatingView rowHeader = new RepeatingView("rowHeader");
            tr.add(rowHeader);

            for (int k = 0; k < rowKey.size(); k++) {
                PivotField rowField = rowFields.get(k);
                tmp = createValueLabel(rowHeader.newChildId(), rowKey.get(k), rowField);
                rowHeader.add(tmp);
            }

            RepeatingView value = new RepeatingView("value");
            tr.add(value);

            for (List<Object> columnKey : columnKeys) {
                for (PivotField dataField : dataFields) {
                    Number cellValue = (Number) pivotModel.getValueAt(dataField, rowKey, columnKey);
                    tmp = createValueLabel(value.newChildId(), cellValue, dataField);
                    value.add(tmp);
                }
            }

            if (!columnFields.isEmpty() && pivotModel.isShowGrandTotalForRow()) {
                MultiMap<PivotField, Object> values = new MultiMap<PivotField, Object>();
                for (List<Object> columnKey : columnKeys) {
                    for (PivotField dataField : dataFields) {
                        values.addValue(dataField, pivotModel.getValueAt(dataField, rowKey, columnKey));
                    }
                }
                for (PivotField dataField : dataFields) {
                    double grandTotalForRow = 0.0d;

                    List<Object> items = values.get(dataField);
                    for (Object item : items) {
                        if (item != null) {
                            grandTotalForRow += ((Number) item).doubleValue();
                        }
                    }

                    tmp = createGrandTotalLabel(value.newChildId(), grandTotalForRow, true);
                    tmp.add(AttributeModifier.append("class", "grand-total"));
                    value.add(tmp);
                }
            }
        }

        WebMarkupContainer grandTotalRow = new WebMarkupContainer("grandTotalRow");
        grandTotalRow.setVisible(!rowFields.isEmpty() && pivotModel.isShowGrandTotalForColumn());
        add(grandTotalRow);

        Label grandTotalRowHeader = new Label("rowHeader", getString("pivot.grandTotal"));
        grandTotalRowHeader.add(AttributeModifier.append("colspan", rowFields.size()));
        grandTotalRow.add(grandTotalRowHeader);

        RepeatingView value = new RepeatingView("value");
        grandTotalRow.add(value);
        Map<PivotField, Double> grandTotal = new HashMap<PivotField, Double>();
        for (List<Object> columnKey : columnKeys) {
            MultiMap<PivotField, Object> values = new MultiMap<PivotField, Object>();
            for (List<Object> rowKey : rowKeys) {
                for (PivotField dataField : dataFields) {
                    values.addValue(dataField, pivotModel.getValueAt(dataField, rowKey, columnKey));
                }
            }
            for (PivotField dataField : dataFields) {
                double grandTotalForColumn = 0.0d;

                List<Object> items = values.get(dataField);
                for (Object item : items) {
                    if (item != null) {
                        grandTotalForColumn += ((Number) item).doubleValue();
                    }
                }

                if (!grandTotal.containsKey(dataField)) {
                    grandTotal.put(dataField, grandTotalForColumn);
                } else {
                    grandTotal.put(dataField, grandTotal.get(dataField) + grandTotalForColumn);
                }
                tmp = createGrandTotalLabel(value.newChildId(), grandTotalForColumn, false);
                value.add(tmp);
            }
        }
        if (!columnFields.isEmpty() && pivotModel.isShowGrandTotalForRow()) {
            for (PivotField dataField : dataFields) {
                tmp = createGrandTotalLabel(value.newChildId(), grandTotal.get(dataField), true);
                value.add(tmp);
            }
        }
    }

    /**
     * Retrieves a label that display the pivot table title (for fields on ROW and DATA areas) 
     */
    protected Label createTitleLabel(String id, PivotField pivotField) {
        String title = pivotField.getTitle();
        if (pivotField.getArea().equals(PivotField.Area.DATA)) {
            title += " (" + pivotField.getAggregator().getFunction().toUpperCase() + ")";
        }

        return new Label(id, title);
    }

    protected Label createValueLabel(String id, Object value, final PivotField pivotField) {
        return new Label(id, Model.of((Serializable) value)) {

            private static final long serialVersionUID = 1L;

            @SuppressWarnings("unchecked")
            @Override
            public <C> IConverter<C> getConverter(Class<C> type) {
                IConverter<C> converter = (IConverter<C>) pivotField.getConverter();
                if (converter != null) {
                    return converter;
                }

                return super.getConverter(type);
            }

        };
    }

    protected Label createGrandTotalLabel(String id, Object value, boolean forRow) {
        return new Label(id, Model.of((Serializable) value));
    }

}