/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2016 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.cache;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import org.pentaho.reporting.engine.classic.core.MetaAttributeNames;
import org.pentaho.reporting.engine.classic.core.MetaTableModel;
import org.pentaho.reporting.engine.classic.core.wizard.DataAttributeContext;
import org.pentaho.reporting.engine.classic.core.wizard.DataAttributes;
import org.pentaho.reporting.engine.classic.core.wizard.DefaultConceptQueryMapper;
import org.pentaho.reporting.engine.classic.core.wizard.DefaultDataAttributeContext;
import org.pentaho.reporting.engine.classic.core.wizard.DefaultDataAttributes;
import org.pentaho.reporting.engine.classic.core.wizard.EmptyDataAttributes;
import org.pentaho.reporting.engine.classic.core.wizard.ImmutableDataAttributes;
import org.pentaho.reporting.libraries.base.util.GenericObjectTable;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
public class CachableTableModel extends AbstractTableModel implements MetaTableModel {
private GenericObjectTable<DefaultDataAttributes> cellAttributes;
private GenericObjectTable<Object> cellValues;
private ArrayList<DataAttributes> columnAttributes;
private DataAttributes tableAttributes;
private DataAttributeContext dataAttributeContext;
public CachableTableModel( final TableModel model ) {
dataAttributeContext = new DefaultDataAttributeContext();
columnAttributes = new ArrayList<DataAttributes>();
if ( model instanceof MetaTableModel ) {
final MetaTableModel metaTableModel = (MetaTableModel) model;
initFromMetaModel( metaTableModel );
} else {
initDefaultMetaData( model );
}
initData( model );
}
protected void initFromMetaModel( final MetaTableModel metaTableModel ) {
final int columnCount = metaTableModel.getColumnCount();
for ( int i = 0; i < columnCount; i++ ) {
final DataAttributes originalColAttrs = metaTableModel.getColumnAttributes( i );
if ( isSaneMetaData( metaTableModel, i ) ) {
columnAttributes.add( ImmutableDataAttributes.create( originalColAttrs, dataAttributeContext ) );
} else {
final String columnName = metaTableModel.getColumnName( i );
final Class columnType = metaTableModel.getColumnClass( i );
final DefaultDataAttributes attributes = new DefaultDataAttributes();
attributes.setMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.NAME,
DefaultConceptQueryMapper.INSTANCE, columnName );
attributes.setMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.TYPE,
DefaultConceptQueryMapper.INSTANCE, columnType );
attributes.merge( originalColAttrs, dataAttributeContext );
columnAttributes.add( ImmutableDataAttributes.create( attributes, dataAttributeContext ) );
}
}
if ( metaTableModel.isCellDataAttributesSupported() ) {
cellAttributes = new GenericObjectTable<DefaultDataAttributes>( metaTableModel.getRowCount(), columnCount );
for ( int row = 0; row < metaTableModel.getRowCount(); row += 1 ) {
for ( int columns = 0; columns < columnCount; columns += 1 ) {
final DefaultDataAttributes attributes = new DefaultDataAttributes();
attributes.merge( metaTableModel.getCellDataAttributes( row, columns ), dataAttributeContext );
cellAttributes.setObject( row, columns, attributes );
}
}
}
final DefaultDataAttributes attributes = new DefaultDataAttributes();
attributes.merge( metaTableModel.getTableAttributes(), dataAttributeContext );
tableAttributes = attributes;
}
private boolean isSaneMetaData( final MetaTableModel metaTableModel, int i ) {
final String columnName = metaTableModel.getColumnName( i );
final Class columnType = metaTableModel.getColumnClass( i );
final DataAttributes originalColAttrs = metaTableModel.getColumnAttributes( i );
final String nameFromMeta =
(String) originalColAttrs.getMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.NAME,
String.class, dataAttributeContext );
if ( !ObjectUtilities.equal( columnName, nameFromMeta ) ) {
return false;
}
final Class colTypeFromMeta =
(Class<?>) originalColAttrs.getMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.TYPE,
Class.class, dataAttributeContext );
if ( !ObjectUtilities.equal( columnType, colTypeFromMeta ) ) {
return false;
}
return true;
}
protected void initData( final TableModel model ) {
cellValues =
new GenericObjectTable<Object>( Math.max( 1, model.getRowCount() ), Math.max( 1, model.getColumnCount() ) );
for ( int row = 0; row < model.getRowCount(); row += 1 ) {
for ( int columns = 0; columns < model.getColumnCount(); columns += 1 ) {
cellValues.setObject( row, columns, model.getValueAt( row, columns ) );
}
}
}
protected void initDefaultMetaData( final TableModel model ) {
for ( int i = 0; i < model.getColumnCount(); i++ ) {
final String columnName = model.getColumnName( i );
final Class columnType = model.getColumnClass( i );
final DefaultDataAttributes attributes = new DefaultDataAttributes();
attributes.setMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.NAME,
DefaultConceptQueryMapper.INSTANCE, columnName );
attributes.setMetaAttribute( MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.TYPE,
DefaultConceptQueryMapper.INSTANCE, columnType );
columnAttributes.add( attributes );
}
tableAttributes = EmptyDataAttributes.INSTANCE;
}
public String getColumnName( final int column ) {
final DataAttributes attributes = columnAttributes.get( column );
return (String) attributes.getMetaAttribute( MetaAttributeNames.Core.NAMESPACE,
MetaAttributeNames.Core.NAME, String.class, dataAttributeContext );
}
public Class getColumnClass( final int columnIndex ) {
final DataAttributes attributes = columnAttributes.get( columnIndex );
return (Class) attributes.getMetaAttribute( MetaAttributeNames.Core.NAMESPACE,
MetaAttributeNames.Core.TYPE, Class.class, dataAttributeContext );
}
public DataAttributes getCellDataAttributes( final int row, final int column ) {
if ( cellAttributes == null ) {
throw new IllegalStateException();
}
return cellAttributes.getObject( row, column );
}
public boolean isCellDataAttributesSupported() {
return cellAttributes != null;
}
public DataAttributes getColumnAttributes( final int column ) {
return columnAttributes.get( column );
}
public DataAttributes getTableAttributes() {
return tableAttributes;
}
public int getRowCount() {
return cellValues.getRowCount();
}
public int getColumnCount() {
return columnAttributes.size();
}
public Object getValueAt( final int rowIndex, final int columnIndex ) {
return cellValues.getObject( rowIndex, columnIndex );
}
public static boolean isSafeToCache( final TableModel model ) {
final int columnCount = model.getColumnCount();
for ( int i = 0; i < columnCount; i += 1 ) {
Class columnClass = model.getColumnClass( i );
while ( columnClass.isArray() ) {
columnClass = columnClass.getComponentType();
}
if ( String.class.equals( columnClass ) ) {
continue;
}
if ( Number.class.isAssignableFrom( columnClass ) ) {
continue;
}
if ( Date.class.isAssignableFrom( columnClass ) ) {
continue;
}
if ( Boolean.class.equals( columnClass ) ) {
continue;
}
if ( columnClass.isPrimitive() ) {
continue;
}
if ( Paint.class.isAssignableFrom( columnClass ) ) {
continue;
}
if ( Shape.class.isAssignableFrom( columnClass ) ) {
continue;
}
if ( Stroke.class.isAssignableFrom( columnClass ) ) {
continue;
}
if ( columnClass.isEnum() ) {
continue;
}
return false;
}
return true;
}
}