/* * 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)); } }