org.eclipse.birt.report.item.crosstab.core.de.internal.DimensionViewTask Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.birt.runtime Show documentation
Show all versions of org.eclipse.birt.runtime Show documentation
A component of the BIRT runtime
/*******************************************************************************
* Copyright (c) 2004 Actuate Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Actuate Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.birt.report.item.crosstab.core.de.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.birt.report.data.adapter.api.IDimensionLevel;
import org.eclipse.birt.report.item.crosstab.core.CrosstabException;
import org.eclipse.birt.report.item.crosstab.core.ICrosstabConstants;
import org.eclipse.birt.report.item.crosstab.core.ILevelViewConstants;
import org.eclipse.birt.report.item.crosstab.core.de.CrosstabReportItemHandle;
import org.eclipse.birt.report.item.crosstab.core.de.DimensionViewHandle;
import org.eclipse.birt.report.item.crosstab.core.de.LevelViewHandle;
import org.eclipse.birt.report.item.crosstab.core.de.MeasureViewHandle;
import org.eclipse.birt.report.item.crosstab.core.i18n.MessageConstants;
import org.eclipse.birt.report.item.crosstab.core.i18n.Messages;
import org.eclipse.birt.report.item.crosstab.core.util.CrosstabExtendedItemFactory;
import org.eclipse.birt.report.item.crosstab.core.util.CrosstabUtil;
import org.eclipse.birt.report.model.api.CommandStack;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.ElementFactory;
import org.eclipse.birt.report.model.api.ExtendedItemHandle;
import org.eclipse.birt.report.model.api.MemberValueHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.olap.CubeHandle;
import org.eclipse.birt.report.model.api.olap.LevelHandle;
import org.eclipse.birt.report.model.api.olap.TabularCubeHandle;
import org.eclipse.birt.report.model.elements.interfaces.IFilterConditionElementModel;
import org.eclipse.birt.report.model.elements.interfaces.ISortElementModel;
/**
* DimensionViewTask
*/
public class DimensionViewTask extends AbstractCrosstabModelTask
{
protected DimensionViewHandle dimensionView = null;
protected int axisType;
/**
*
* @param focus
*/
public DimensionViewTask( DimensionViewHandle focus )
{
super( focus );
this.dimensionView = focus;
this.axisType = dimensionView.getAxisType( );
}
/**
* Inserts a level handle into a dimension view. This method will add the
* aggregations and data-item automatically.
*
* @param dimensionView
* @param levelHandle
* @param index
* @return
* @throws SemanticException
*/
public LevelViewHandle insertLevel( LevelHandle levelHandle, int index )
throws SemanticException
{
if ( levelHandle != null )
{
// if cube dimension container of this cube level element is not
// what is referred by this dimension view, then the insertion is
// forbidden
if ( !levelHandle.getContainer( )
.getContainer( )
.getQualifiedName( )
.equals( dimensionView.getCubeDimensionName( ) ) )
{
// TODO: throw exception
dimensionView.getLogger( ).log( Level.WARNING, "" ); //$NON-NLS-1$
return null;
}
// if this level handle has referred by an existing level view,
// then log error and do nothing
if ( dimensionView.getLevel( levelHandle.getQualifiedName( ) ) != null )
{
dimensionView.getLogger( ).log( Level.SEVERE,
MessageConstants.CROSSTAB_EXCEPTION_DUPLICATE_LEVEL,
levelHandle.getQualifiedName( ) );
throw new CrosstabException( dimensionView.getModelHandle( )
.getElement( ),
Messages.getString( MessageConstants.CROSSTAB_EXCEPTION_DUPLICATE_LEVEL,
levelHandle.getQualifiedName( ) ) );
}
}
CommandStack stack = dimensionView.getCommandStack( );
stack.startTrans( Messages.getString( "DimensionViewTask.msg.insert.level" ) ); //$NON-NLS-1$
LevelViewHandle levelView = null;
try
{
ExtendedItemHandle extendedItemHandle = CrosstabExtendedItemFactory.createLevelView( dimensionView.getModuleHandle( ),
levelHandle );
if ( extendedItemHandle != null )
{
dimensionView.getLevelsProperty( ).add( extendedItemHandle,
index );
levelView = (LevelViewHandle) CrosstabUtil.getReportItem( extendedItemHandle,
LEVEL_VIEW_EXTENSION_NAME );
// if level handle is specified, do some post work after adding
if ( levelHandle != null && crosstab != null )
{
doPostInsert( levelView );
CrosstabModelUtil.updateHeaderCell( dimensionView.getCrosstab( ), CrosstabModelUtil.findPriorLevelCount( dimensionView ) + index, dimensionView.getAxisType( ) );
}
}
}
catch ( SemanticException e )
{
stack.rollback( );
throw e;
}
stack.commit( );
return levelView;
}
private void doPostInsert( LevelViewHandle levelView )
throws SemanticException
{
if ( levelView.isInnerMost( ) )
{
// if originally there is no levels and grand total,
// then remove the aggregations for the axis type and
// the counter axis level aggregations
if ( CrosstabModelUtil.getAllLevelCount( crosstab, axisType ) <= 1 )
{
// add aggregations for this level and all counter
// axis type levels except the innermost one
addAggregationForLevel( levelView, axisType );
if ( crosstab.getGrandTotal( axisType ) == null )
{
removeMeasureAggregations( axisType );
}
}
else
{
// add aggregations for this level and all counter
// axis type levels except the innermost one
addAggregationForLevel( levelView, axisType );
// add one aggregation: the original innermost level
// before this level is added and the innermost
// level in the counter axis if the orginal
// innermost has aggregation header
LevelViewHandle precedingLevel = CrosstabModelUtil.getPrecedingLevel( levelView );
int counterAxisType = CrosstabModelUtil.getOppositeAxisType( axisType );
assert precedingLevel != null;
LevelViewHandle innerMostLevelView = CrosstabModelUtil.getInnerMostLevel( crosstab,
counterAxisType );
if ( precedingLevel.getAggregationHeader( ) != null )
{
if ( innerMostLevelView != null )
{
String dimensionName = ( (DimensionViewHandle) innerMostLevelView.getContainer( ) ).getCubeDimensionName( );
String levelName = innerMostLevelView.getCubeLevelName( );
List measureList = precedingLevel.getAggregationMeasures( );
List functionList = new ArrayList( );
for ( int i = 0; i < measureList.size( ); i++ )
{
MeasureViewHandle measureView = (MeasureViewHandle) measureList.get( i );
String function = precedingLevel.getAggregationFunction( measureView );
functionList.add( function );
}
// add the data-item
addMeasureAggregations( crosstab,
dimensionName,
levelName,
counterAxisType,
( (DimensionViewHandle) precedingLevel.getContainer( ) ).getCubeDimensionName( ),
precedingLevel.getCubeLevelName( ),
measureList,
functionList );
}
else
{
// TODO add dummy grandtotal???
}
}
else
{
// orginally, the preceding one is the innermost, we add
// some aggregations for this innermost, even though it has
// no sub-total; however, now, it is not innermost and
// neither has sub-total, therefore, we should remove
// aggregations about this
removeMeasureAggregations( precedingLevel );
}
}
// valid aggregation on measure detail cell
LevelViewHandle innerestRowLevel = CrosstabModelUtil.getInnerMostLevel( crosstab,
ROW_AXIS_TYPE );
LevelViewHandle innerestColLevel = CrosstabModelUtil.getInnerMostLevel( crosstab,
COLUMN_AXIS_TYPE );
validateMeasureDetails( innerestRowLevel, innerestColLevel );
}
else
{
// if the added level view is not innermost and has
// aggregation header, then add aggregations for this
// level view and all counterpart axis levels and grand
// total
if ( levelView.getAggregationHeader( ) != null )
{
// add aggregations for this level and all counter
// axis type levels except the innermost one
addAggregationForLevel( levelView, axisType );
// handle measure header
addTotalMeasureHeader( axisType, levelView );
}
}
}
/**
* Adjust measure aggregations for the given two level views.
*
* @param crosstab
* the crosstab where the leve views reside
* @param leftDimension
* the first dimension name
* @param leftLevel
* the first level name
* @param axisType
* the row/column axis type for the first level view
* @param rightDimension
* the second dimension name
* @param rightLevel
* the second level name
* @param measures
* @param functions
* @param isAdd
* true if add aggregation, otherwise false
* @throws SemanticException
*/
private void addMeasureAggregations(
CrosstabReportItemHandle crosstab, String leftDimension,
String leftLevel, int axisType, String rightDimension,
String rightLevel, List measures,
List functions ) throws SemanticException
{
if ( crosstab == null
|| !CrosstabModelUtil.isValidAxisType( axisType )
|| measures == null )
return;
if ( functions == null || functions.size( ) != measures.size( ) )
return;
String rowDimension = null;
String rowLevel = null;
String colDimension = null;
String colLevel = null;
if ( axisType == ROW_AXIS_TYPE )
{
rowDimension = leftDimension;
rowLevel = leftLevel;
colDimension = rightDimension;
colLevel = rightLevel;
}
else if ( axisType == COLUMN_AXIS_TYPE )
{
rowDimension = rightDimension;
rowLevel = rightLevel;
colDimension = leftDimension;
colLevel = leftLevel;
}
for ( int i = 0; i < measures.size( ); i++ )
{
MeasureViewHandle measureView = measures.get( i );
if ( measureView.getCrosstab( ) != crosstab )
continue;
validateSingleMeasureAggregation( crosstab,
measureView,
functions.get( i ),
rowDimension,
rowLevel,
colDimension,
colLevel );
}
}
/**
*
* @param levelView
* @param axisType
* @throws SemanticException
*/
private void addAggregationForLevel( LevelViewHandle levelView, int axisType )
throws SemanticException
{
assert CrosstabModelUtil.isValidAxisType( axisType );
if ( levelView != null && levelView.getAxisType( ) != axisType )
return;
int counterAxisType = CrosstabModelUtil.getOppositeAxisType( axisType );
// first add all aggregation for the added level view, for it is
// innermost
for ( int dimension = 0; dimension < crosstab.getDimensionCount( counterAxisType ); dimension++ )
{
DimensionViewHandle tempDimensionView = crosstab.getDimension( counterAxisType,
dimension );
for ( int level = 0; level < tempDimensionView.getLevelCount( ); level++ )
{
LevelViewHandle tempLevelView = tempDimensionView.getLevel( level );
// if level view is not null, that is not grand-total
if ( levelView != null )
{
boolean isInnerMost = levelView.isInnerMost( );
if ( isInnerMost && tempLevelView.isInnerMost( ) )
continue;
}
// if this level has no sub-total, do nothing
if ( tempLevelView.getAggregationHeader( ) == null )
continue;
List measureList = tempLevelView.getAggregationMeasures( );
AggregationInfo infor = getAggregationInfo( levelView,
tempLevelView );
for ( int i = 0; i < measureList.size( ); i++ )
{
MeasureViewHandle measureView = (MeasureViewHandle) measureList.get( i );
String function = tempLevelView.getAggregationFunction( measureView );
validateSingleMeasureAggregation( crosstab,
measureView,
function,
infor.getRowDimension( ),
infor.getRowLevel( ),
infor.getColDimension( ),
infor.getColLevel( ) );
}
}
}
// handle for grand-total
if ( crosstab.getGrandTotal( counterAxisType ) != null
|| CrosstabModelUtil.getAllLevelCount( crosstab,
counterAxisType ) == 0 )
{
List measureList = crosstab.getAggregationMeasures( counterAxisType );
AggregationInfo infor = getAggregationInfo( levelView, null );
for ( int i = 0; i < measureList.size( ); i++ )
{
MeasureViewHandle measureView = (MeasureViewHandle) measureList.get( i );
String function = crosstab.getAggregationFunction( counterAxisType,
measureView );
validateSingleMeasureAggregation( crosstab,
measureView,
function,
infor.getRowDimension( ),
infor.getRowLevel( ),
infor.getColDimension( ),
infor.getColLevel( ) );
}
}
}
/**
* Removes a level view that refers a cube level element with the given
* name.
*
* @param name
* name of the cube level element to remove
* @throws SemanticException
*/
public void removeLevel( String name ) throws SemanticException
{
LevelViewHandle levelView = dimensionView.getLevel( name );
if ( levelView != null )
{
removeLevel( levelView, true );
}
}
/**
*
* @param levelView
* @throws SemanticException
*/
void removeLevel( LevelViewHandle levelView, boolean needTransaction )
throws SemanticException
{
assert levelView != null;
CommandStack stack = null;
if ( needTransaction )
{
stack = dimensionView.getCommandStack( );
stack.startTrans( Messages.getString( "DimensionViewTask.msg.remove.level" ) ); //$NON-NLS-1$
}
try
{
// adjust measure aggregations and then remove level view from
// the design tree, the order can not reversed
if ( crosstab != null )
{
doPreRemove( levelView );
}
int count = CrosstabModelUtil.findPriorLevelCount( dimensionView );
// for (int i=0; i validatedLevelList = CrosstabUtil.getReferencedLevels( levelView,
expression );
MemberValueHandle oldMemberValue = (MemberValueHandle) item.getContent( memberValuePropName,
0 );
// if member value is not null originally, then build the
// levelName/levelValue pair from it
Map levelValueMap = new HashMap( );
MemberValueHandle tempMember = oldMemberValue;
while ( tempMember != null )
{
String levelName = tempMember.getCubeLevelName( );
String levelValue = tempMember.getValue( );
levelValueMap.put( levelName, levelValue );
tempMember = (MemberValueHandle) tempMember.getContent( MemberValueHandle.MEMBER_VALUES_PROP,
0 );
}
ElementFactory factory = dimensionView.getModuleHandle( )
.getElementFactory( );
MemberValueHandle newMemberValue = factory.newMemberValue( );
tempMember = newMemberValue;
MemberValueHandle parentMember = null;
if ( validatedLevelList != null )
{
for ( int i = 0; i < validatedLevelList.size( ); i++ )
{
IDimensionLevel levelDefn = validatedLevelList.get( i );
String levelName = getLevelHandle( levelDefn );
tempMember.setStringProperty( MemberValueHandle.LEVEL_PROP,
levelName );
Object levelValue = levelValueMap.get( levelName );
if ( levelValue == null )
continue;
tempMember.setProperty( MemberValueHandle.VALUE_PROP,
levelValue );
if ( parentMember != null )
{
parentMember.add( MemberValueHandle.MEMBER_VALUES_PROP,
tempMember,
0 );
}
parentMember = tempMember;
tempMember = factory.newMemberValue( );
}
}
// clear the old member value and add the new one
item.clearProperty( memberValuePropName );
if ( !isEmptyMemberValue( newMemberValue ) )
item.add( memberValuePropName, newMemberValue );
}
private boolean isEmptyMemberValue( MemberValueHandle memberValue )
{
assert memberValue != null;
String levelName = memberValue.getStringProperty( MemberValueHandle.LEVEL_PROP );
if ( levelName != null && levelName.length( ) > 0 )
return false;
MemberValueHandle tempMember = (MemberValueHandle) memberValue.getContent( MemberValueHandle.MEMBER_VALUES_PROP,
0 );
if ( tempMember != null && !isEmptyMemberValue( tempMember ) )
return false;
return true;
}
private String getLevelHandle( IDimensionLevel levelDefn )
{
assert crosstab != null;
String levelName = levelDefn.getLevelName( );
String dimensionName = levelDefn.getDimensionName( );
DimensionViewHandle dimension = crosstab.getDimension( dimensionName );
assert dimension != null;
LevelViewHandle level = dimension.findLevel( levelName );
return level.getCubeLevelName( );
}
}