/*! * 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-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.reporting.designer.core.editor.drilldown.model; import org.pentaho.reporting.libraries.base.util.DebugLog; import org.pentaho.reporting.libraries.base.util.StringUtils; import org.pentaho.reporting.libraries.formula.lvalues.DataTable; import org.pentaho.reporting.libraries.formula.lvalues.FormulaFunction; import org.pentaho.reporting.libraries.formula.lvalues.LValue; import org.pentaho.reporting.libraries.formula.lvalues.StaticValue; import org.pentaho.reporting.libraries.formula.parser.FormulaParser; import org.pentaho.reporting.libraries.formula.util.FormulaUtil; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; public class DrillDownModel { public static final String DRILL_DOWN_CONFIG_PROPERTY = "drillDownConfig"; public static final String DRILL_DOWN_PATH_PROPERTY = "drillDownPath"; public static final String DRILL_DOWN_PARAMETER_PROPERTY = "drillDownParameter"; public static final String TOOLTIP_FORMULA_PROPERTY = "tooltipFormula"; public static final String TARGET_FORMULA_PROPERTY = "targetFormula"; private static final DrillDownParameter[] EMPTY_PARAMS = new DrillDownParameter[ 0 ]; private PropertyChangeSupport propertyChangeSupport; private String drillDownConfig; private String drillDownPath; private DrillDownParameter[] drillDownParameters; private String tooltipFormula; private String targetFormula; private boolean limitedEditor; public DrillDownModel() { this.propertyChangeSupport = new PropertyChangeSupport( this ); this.drillDownParameters = new DrillDownParameter[ 0 ]; } public void addPropertyChangeListener( final PropertyChangeListener listener ) { propertyChangeSupport.addPropertyChangeListener( listener ); } public void removePropertyChangeListener( final PropertyChangeListener listener ) { propertyChangeSupport.removePropertyChangeListener( listener ); } public void addPropertyChangeListener( final String propertyName, final PropertyChangeListener listener ) { propertyChangeSupport.addPropertyChangeListener( propertyName, listener ); } public void removePropertyChangeListener( final String propertyName, final PropertyChangeListener listener ) { propertyChangeSupport.removePropertyChangeListener( propertyName, listener ); } public void firePropertyChange( final String propertyName, final Object oldValue, final Object newValue ) { propertyChangeSupport.firePropertyChange( propertyName, oldValue, newValue ); } public boolean isLimitedEditor() { return limitedEditor; } public void setLimitedEditor( final boolean limitedEditor ) { final boolean oldLimitedEditor = this.limitedEditor; this.limitedEditor = limitedEditor; firePropertyChange( "limitedEditor", oldLimitedEditor, limitedEditor ); } public void setDrillDownConfig( final String drillDownConfig ) { final String oldValue = this.drillDownConfig; this.drillDownConfig = drillDownConfig; firePropertyChange( DRILL_DOWN_CONFIG_PROPERTY, oldValue, drillDownConfig ); } public String getDrillDownConfig() { return drillDownConfig; } public String getDrillDownPath() { return drillDownPath; } public void setDrillDownPath( final String drillDownPath ) { final String oldValue = this.drillDownPath; this.drillDownPath = drillDownPath; firePropertyChange( DRILL_DOWN_PATH_PROPERTY, oldValue, drillDownPath ); } public DrillDownParameter[] getDrillDownParameter() { return drillDownParameters; } public void setDrillDownParameter( final DrillDownParameter[] drillDownParameters ) { final DrillDownParameter[] oldValue = this.drillDownParameters; this.drillDownParameters = drillDownParameters.clone(); firePropertyChange( DRILL_DOWN_PARAMETER_PROPERTY, oldValue, drillDownParameters ); } public String getTooltipFormula() { return tooltipFormula; } public void setTooltipFormula( final String tooltipFormula ) { final String oldTooltip = this.tooltipFormula; this.tooltipFormula = tooltipFormula; firePropertyChange( TOOLTIP_FORMULA_PROPERTY, oldTooltip, tooltipFormula ); } public String getTargetFormula() { return targetFormula; } public void setTargetFormula( final String targetFormula ) { final String oldTarget = this.targetFormula; this.targetFormula = targetFormula; firePropertyChange( TARGET_FORMULA_PROPERTY, oldTarget, targetFormula ); } public void refresh() { firePropertyChange( DRILL_DOWN_PATH_PROPERTY, null, drillDownPath ); firePropertyChange( DRILL_DOWN_CONFIG_PROPERTY, null, drillDownConfig ); firePropertyChange( DRILL_DOWN_PARAMETER_PROPERTY, null, drillDownParameters ); firePropertyChange( TOOLTIP_FORMULA_PROPERTY, null, tooltipFormula ); firePropertyChange( TARGET_FORMULA_PROPERTY, null, targetFormula ); } public void clear() { setDrillDownConfig( null ); setDrillDownPath( null ); setDrillDownParameter( new DrillDownParameter[ 0 ] ); } public boolean initializeFromFormula( final String formulaWithPrefix, final boolean formulaFragment ) { clear(); if ( StringUtils.isEmpty( formulaWithPrefix, true ) == false ) { final String formula; if ( formulaFragment ) { formula = formulaWithPrefix; } else { formula = FormulaUtil.extractFormula( formulaWithPrefix ); } try { final FormulaParser parser = new FormulaParser(); final LValue value = parser.parse( formula ); if ( value instanceof FormulaFunction ) { final FormulaFunction function = (FormulaFunction) value; if ( "DRILLDOWN".equals( function.getFunctionName() ) ) // NON-NLS { updateModelFromFunction( function ); return true; } } DebugLog.log( "Fall through on formula " + formula );//NON-NLS } catch ( Exception e ) { // plain value .. DebugLog.log( "Failed with formula " + formulaWithPrefix, e );//NON-NLS } } else { DebugLog.log( "formula is empty " + formulaWithPrefix );//NON-NLS } return false; } public String getResultDrillDownFormula( final boolean formulaFragment ) { final String formula = getDrillDownFormula(); if ( formula == null ) { return null; } if ( formulaFragment ) { return formula.substring( 1 ); } return formula; } public String getDrillDownFormula() { if ( StringUtils.isEmpty( getDrillDownConfig() ) ) { return null; } final DrillDownParameter[] downParameters = getDrillDownParameter(); if ( StringUtils.isEmpty( getDrillDownPath() ) && downParameters.length == 0 ) { return null; } final StringBuilder builder = new StringBuilder(); builder.append( "=DRILLDOWN(" ); // NON-NLS builder.append( FormulaUtil.quoteString( getDrillDownConfig() ) ); builder.append( "; " ); // NON-NLS if ( StringUtils.isEmpty( getDrillDownPath() ) ) { builder.append( "NA()" ); // NON-NLS } else { builder.append( FormulaUtil.quoteString( getDrillDownPath() ) ); } builder.append( "; {" ); // NON-NLS for ( int i = 0; i < downParameters.length; i++ ) { if ( i > 0 ) { builder.append( " | " ); // NON-NLS } final DrillDownParameter downParameter = downParameters[ i ]; final String paramName = downParameter.getName(); if ( StringUtils.isEmpty( paramName ) ) { builder.append( "NA()" ); // NON-NLS } else { builder.append( FormulaUtil.quoteString( paramName ) ); } builder.append( "; " ); // NON-NLS final String formulaFragment = downParameter.getFormulaFragment(); if ( StringUtils.isEmpty( formulaFragment ) ) { continue; } builder.append( formulaFragment ); } builder.append( "})" ); // NON-NLS return builder.toString(); } private void updateModelFromFunction( final FormulaFunction function ) { final LValue[] lValues = function.getChildValues(); if ( lValues.length == 0 ) { return; } final LValue configValue = lValues[ 0 ]; final String configText = extractStringValue( configValue ); final String pathText; if ( lValues.length > 1 ) { final LValue pathValue = lValues[ 1 ]; pathText = extractStringValue( pathValue ); } else { pathText = null; } final DrillDownParameter[] parameters; if ( lValues.length == 3 ) { final LValue dataValue = lValues[ 2 ]; if ( dataValue instanceof DataTable ) { final ArrayList<DrillDownParameter> values = new ArrayList<DrillDownParameter>(); final DataTable paramsStaticValue = (DataTable) dataValue; final int colCount = paramsStaticValue.getColumnCount(); final int rowCount = paramsStaticValue.getRowCount(); for ( int row = 0; row < rowCount; row++ ) { if ( colCount == 0 ) { continue; } final LValue parameterNameValue = paramsStaticValue.getValueAt( row, 0 ); final String parameterName = extractStringValue( parameterNameValue ); final String parameterText; if ( colCount > 1 ) { final LValue parameterTextValue = paramsStaticValue.getValueAt( row, 1 ); if ( parameterTextValue != null ) { parameterText = parameterTextValue.toString(); } else { parameterText = null; } } else { parameterText = null; } if ( parameterName != null ) { values.add( new DrillDownParameter( parameterName, parameterText ) ); } } parameters = values.toArray( new DrillDownParameter[ values.size() ] ); } else { parameters = EMPTY_PARAMS; } } else { parameters = EMPTY_PARAMS; } setDrillDownConfig( configText ); setDrillDownPath( pathText ); setDrillDownParameter( parameters ); } private String extractStringValue( final LValue pathValue ) { final String pathText; if ( pathValue instanceof StaticValue ) { // the configuration cannot be computed, if we are expected to successfully edit it. final StaticValue pathStaticValue = (StaticValue) pathValue; pathText = String.valueOf( pathStaticValue.getValue() ); } else { pathText = null; } return pathText; } }