Package org.pentaho.reporting.engine.classic.wizard

Source Code of org.pentaho.reporting.engine.classic.wizard.WizardProcessor

/*
* 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) 2009 Pentaho Corporation.  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.wizard;

import java.awt.Color;
import java.awt.Image;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.AbstractReportDefinition;
import org.pentaho.reporting.engine.classic.core.AttributeNames;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.CrosstabColumnGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabColumnGroupBody;
import org.pentaho.reporting.engine.classic.core.CrosstabGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabOtherGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabOtherGroupBody;
import org.pentaho.reporting.engine.classic.core.CrosstabRowGroup;
import org.pentaho.reporting.engine.classic.core.CrosstabRowGroupBody;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.Group;
import org.pentaho.reporting.engine.classic.core.GroupBody;
import org.pentaho.reporting.engine.classic.core.GroupFooter;
import org.pentaho.reporting.engine.classic.core.GroupHeader;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.MetaAttributeNames;
import org.pentaho.reporting.engine.classic.core.RelationalGroup;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.ReportPreProcessor;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.SubGroupBody;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.Watermark;
import org.pentaho.reporting.engine.classic.core.filter.types.ContentFieldType;
import org.pentaho.reporting.engine.classic.core.filter.types.ContentType;
import org.pentaho.reporting.engine.classic.core.filter.types.DateFieldType;
import org.pentaho.reporting.engine.classic.core.filter.types.LabelType;
import org.pentaho.reporting.engine.classic.core.filter.types.NumberFieldType;
import org.pentaho.reporting.engine.classic.core.filter.types.TextFieldType;
import org.pentaho.reporting.engine.classic.core.function.ProcessingContext;
import org.pentaho.reporting.engine.classic.core.function.StructureFunction;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.states.datarow.DefaultFlowController;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.BorderStyle;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.wizard.AutoGeneratorUtility;
import org.pentaho.reporting.engine.classic.core.wizard.DataAttributes;
import org.pentaho.reporting.engine.classic.core.wizard.DefaultDataAttributeContext;
import org.pentaho.reporting.engine.classic.core.wizard.RelationalAutoGeneratorPreProcessor;
import org.pentaho.reporting.engine.classic.wizard.model.DetailFieldDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.FieldDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.GroupDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.GroupType;
import org.pentaho.reporting.engine.classic.wizard.model.Length;
import org.pentaho.reporting.engine.classic.wizard.model.RootBandDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.WatermarkDefinition;
import org.pentaho.reporting.engine.classic.wizard.model.WizardSpecification;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;

/**
* Todo: Document Me
*
* @author Thomas Morgner
*/
public class WizardProcessor implements ReportPreProcessor
{
  private static final Log logger = LogFactory.getLog(WizardProcessor.class);

  private DefaultDataAttributeContext attributeContext;
  private AbstractReportDefinition definition;
  private DefaultFlowController flowController;
  private WizardSpecification wizardSpecification;

  public WizardProcessor()
  {
  }

  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }

  public MasterReport performPreProcessing(final MasterReport definition,
                                           final DefaultFlowController flowController)
      throws ReportProcessingException
  {
    return (MasterReport) performCommonPreProcessing(definition, flowController, definition.getResourceManager());
  }

  public SubReport performPreProcessing(final SubReport definition,
                                        final DefaultFlowController flowController)
      throws ReportProcessingException
  {
    return (SubReport) performCommonPreProcessing(definition, flowController, definition.getResourceManager());
  }

  protected AbstractReportDefinition performCommonPreProcessing(final AbstractReportDefinition definition,
                                                                final DefaultFlowController flowController,
                                                                final ResourceManager resourceManager)
      throws ReportProcessingException
  {
    try
    {
      this.wizardSpecification = WizardProcessorUtil.loadWizardSpecification(definition, resourceManager);
      if (wizardSpecification == null)
      {
        return definition;
      }

      final StructureFunction[] functions = definition.getStructureFunctions();
      boolean hasOverrideFunction = false;
      for (int i = 0; i < functions.length; i++)
      {
        final StructureFunction function = functions[i];
        if (function instanceof WizardOverrideFormattingFunction)
        {
          hasOverrideFunction = true;
          break;
        }
      }
      if (hasOverrideFunction == false)
      {
        definition.addStructureFunction(new WizardOverrideFormattingFunction());
      }

      final ProcessingContext reportContext = flowController.getReportContext();
      this.definition = definition;
      this.flowController = flowController;
      this.attributeContext = new DefaultDataAttributeContext(reportContext.getOutputProcessorMetaData(),
          reportContext.getResourceBundleFactory().getLocale());

      final Object o = definition.getAttribute(AttributeNames.Wizard.NAMESPACE, "enable");
      if (Boolean.TRUE.equals(o) == false)
      {
        return performRefreshPreProcessing();
      }
      else
      {
        return performGenerationPreProcessing();
      }
    }
    finally
    {
      this.wizardSpecification = null;
      this.definition = null;
      this.flowController = null;
      this.attributeContext = null;
    }

  }

  private AbstractReportDefinition performRefreshPreProcessing()
      throws ReportProcessingException
  {
    final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
    final int wizardCount = groupDefinitions.length;   // 1  5   5
    final int groupCount = definition.getGroupCount(); // 5  1   5
    final int count = Math.min(groupCount, wizardCount);
    for (int i = 0; i < count; i++)
    {
      final int groupIdx = groupCount - i - 1;
      final int wizGroupIdx = wizardCount - i - 1;
      final GroupDefinition gd = groupDefinitions[wizGroupIdx];
      final Group g = definition.getGroup(groupIdx);
      final Band groupHeader = g.getHeader();
      final Band groupFooter = g.getFooter();

      iterateSection(groupHeader, new UpdateHeaderTask(gd));
      iterateSection(groupFooter, new UpdateFooterTask(gd));
    }

    final Band itemband = definition.getItemBand();
    final Band detailsHeader = definition.getDetailsHeader();
    final Band detailsFooter = definition.getDetailsFooter();

    final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
    for (int i = 0; i < detailFieldDefinitions.length; i++)
    {
      final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
      final UpdateDetailsTask updateTask = new UpdateDetailsTask(fieldDefinition);
      iterateSection(itemband, updateTask);
      iterateSection(detailsHeader, updateTask);
      iterateSection(detailsFooter, updateTask);
    }

    return definition;
  }


  private static interface UpdateTask
  {
    public void processElement(ReportElement e);
  }

  private static class UpdateHeaderTask implements UpdateTask
  {
    private GroupDefinition groupDefinition;

    private UpdateHeaderTask(final GroupDefinition groupDefinition)
    {
      this.groupDefinition = groupDefinition;
    }

    public void processElement(final ReportElement e)
    {
      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", groupDefinition.getHeader());
      }
      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", groupDefinition);
      }
    }
  }

  private static class UpdateFooterTask implements UpdateTask
  {
    private GroupDefinition groupDefinition;

    private UpdateFooterTask(final GroupDefinition groupDefinition)
    {
      this.groupDefinition = groupDefinition;
    }

    public void processElement(final ReportElement e)
    {
      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", groupDefinition.getFooter());
      }
      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", groupDefinition);
      }
    }
  }

  private static class UpdateDetailsTask implements UpdateTask
  {
    private FieldDefinition fieldDefinition;

    private UpdateDetailsTask(final FieldDefinition groupDefinition)
    {
      this.fieldDefinition = groupDefinition;
    }

    public void processElement(final ReportElement e)
    {
      final String field = fieldDefinition.getField();
      final Object labelFor = e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR);
      if (labelFor != null)
      {
        if (ObjectUtilities.equal(field, labelFor) == false)
        {
          return;
        }
      }
      else
      {
        final Object fieldName = e.getAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.FIELD);
        if (ObjectUtilities.equal(field, fieldName) == false)
        {
          return;
        }
      }

      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", fieldDefinition);
      }
      if (Boolean.TRUE.equals
          (e.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
      {
        e.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", fieldDefinition);
      }
    }
  }

  private void iterateSection(final Section s, final UpdateTask task)
  {
    final int count = s.getElementCount();
    for (int i = 0; i < count; i++)
    {
      final ReportElement element = s.getElement(i);
      task.processElement(element);
      if (element instanceof SubReport)
      {
        continue;
      }
      if (element instanceof Section)
      {
        iterateSection((Section) element, task);
      }
    }
  }

  protected AbstractReportDefinition performGenerationPreProcessing()
      throws ReportProcessingException
  {
    setupWatermark();
    setupRelationalGroups();
/** remove check on data source to display to use cross-tab
if (isCrosstab())
{
setupCrosstab();
}
else
{
clearCrosstab();

}
*/
    setupDetails();
    return definition;
  }

  private void clearCrosstab()
  {
    final CrosstabGroup crosstabGroup = lookupCrosstab();
    if (crosstabGroup != null)
    {
      if (definition.getRootGroup() == crosstabGroup)
      {
        definition.setRootGroup(new RelationalGroup());
      }
      else
      {
        final Section parentSection = crosstabGroup.getParentSection();
        if (parentSection instanceof SubGroupBody)
        {
          final SubGroupBody sgb = (SubGroupBody) parentSection;
          sgb.setGroup(new RelationalGroup());
        }
      }
    }

  }

  /**
   * Creating a crosstab report deletes all sub-definitions and the itemband.
   *
   * @throws ReportProcessingException if an error occurs.
   */
  private void setupCrosstab() throws ReportProcessingException
  {
    CrosstabGroup crosstab = lookupCrosstab();
    if (crosstab == null)
    {
      crosstab = new CrosstabGroup();
      insertCrosstab(crosstab);
    }

    Group insertGroup = crosstab;
    final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
    for (int i = 0; i < groupDefinitions.length; i++)
    {
      final GroupDefinition groupDefinition = groupDefinitions[i];
      if (GroupType.CT_OTHER.equals(groupDefinition.getGroupType()) == false)
      {
        continue;
      }

      // create a new group and insert it at the end
      final CrosstabOtherGroup relationalGroup = new CrosstabOtherGroup();
      if (groupDefinition.getGroupName() != null)
      {
        relationalGroup.setName(groupDefinition.getGroupName());
      }
      configureCrosstabOtherGroup(relationalGroup, groupDefinition);
      insertGroup.setBody(new CrosstabOtherGroupBody(relationalGroup));
      insertGroup = relationalGroup;
    }

    for (int i = 0; i < groupDefinitions.length; i++)
    {
      final GroupDefinition groupDefinition = groupDefinitions[i];
      if (GroupType.CT_ROW.equals(groupDefinition.getGroupType()) == false)
      {
        continue;
      }

      // create a new group and insert it at the end
      final CrosstabRowGroup relationalGroup = new CrosstabRowGroup();
      if (groupDefinition.getGroupName() != null)
      {
        relationalGroup.setName(groupDefinition.getGroupName());
      }
      configureCrosstabRowGroup(relationalGroup, groupDefinition);
      insertGroup.setBody(new CrosstabRowGroupBody(relationalGroup));
      insertGroup = relationalGroup;
    }

    for (int i = 0; i < groupDefinitions.length; i++)
    {
      final GroupDefinition groupDefinition = groupDefinitions[i];
      if (GroupType.CT_COLUMN.equals(groupDefinition.getGroupType()) == false)
      {
        continue;
      }

      // create a new group and insert it at the end
      final CrosstabColumnGroup relationalGroup = new CrosstabColumnGroup();
      if (groupDefinition.getGroupName() != null)
      {
        relationalGroup.setName(groupDefinition.getGroupName());
      }
      configureCrosstabColumnGroup(relationalGroup, groupDefinition);
      insertGroup.setBody(new CrosstabColumnGroupBody(relationalGroup));
      insertGroup = relationalGroup;
    }

    final Band itemBand = AutoGeneratorUtility.findGeneratedContent(definition.getItemBand());
    if (itemBand == null)
    {
      return;
    }
    final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
    if (detailFieldDefinitions.length == 0)
    {
      return;
    }

    final Float[] widthSpecs = new Float[detailFieldDefinitions.length];
    for (int i = 0; i < detailFieldDefinitions.length; i++)
    {
      final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
      final Length length = fieldDefinition.getWidth();
      if (length == null)
      {
        continue;
      }
      widthSpecs[i] = length.getNormalizedValue();
    }
    final float[] computedWidth =
        AutoGeneratorUtility.computeFieldWidths(widthSpecs, definition.getPageDefinition().getWidth());


    itemBand.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
    for (int i = 0; i < detailFieldDefinitions.length; i++)
    {
      final DetailFieldDefinition detailFieldDefinition = detailFieldDefinitions[i];
      setupField(null, null, itemBand, detailFieldDefinition, computedWidth[i]);
    }

  }

  private void setupDetails() throws ReportProcessingException
  {
    final DetailFieldDefinition[] detailFieldDefinitions = wizardSpecification.getDetailFieldDefinitions();
    if (detailFieldDefinitions.length == 0)
    {
      if (wizardSpecification.isAutoGenerateDetails())
      {
        final RelationalAutoGeneratorPreProcessor generatorPreProcessor = new RelationalAutoGeneratorPreProcessor();
        if (definition instanceof MasterReport)
        {
          generatorPreProcessor.performPreProcessing((MasterReport) definition, flowController);
        }
        else if (definition instanceof SubReport)
        {
          generatorPreProcessor.performPreProcessing((SubReport) definition, flowController);
        }
      }
      return;
    }

    definition.getDetailsHeader().setRepeat(true);
    definition.getDetailsFooter().setRepeat(true);

    final Band detailsHeader = AutoGeneratorUtility.findGeneratedContent(definition.getDetailsHeader());
    final Band detailsFooter = AutoGeneratorUtility.findGeneratedContent(definition.getDetailsFooter());
    final Band itemBand = AutoGeneratorUtility.findGeneratedContent(definition.getItemBand());

    if (itemBand == null)
    {
      return;
    }

    final Float[] widthSpecs = new Float[detailFieldDefinitions.length];
    for (int i = 0; i < detailFieldDefinitions.length; i++)
    {
      final DetailFieldDefinition fieldDefinition = detailFieldDefinitions[i];
      final Length length = fieldDefinition.getWidth();
      if (length == null)
      {
        continue;
      }
      widthSpecs[i] = length.getNormalizedValue();
    }
    final float[] computedWidth =
        AutoGeneratorUtility.computeFieldWidths(widthSpecs, definition.getPageDefinition().getWidth());

    itemBand.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
    if (detailsHeader != null)
    {
      detailsHeader.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
    }
    if (detailsFooter != null)
    {
      detailsFooter.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "row");
    }

    for (int i = 0; i < detailFieldDefinitions.length; i++)
    {
      final DetailFieldDefinition detailFieldDefinition = detailFieldDefinitions[i];
      setupField(detailsHeader, detailsFooter, itemBand, detailFieldDefinition, computedWidth[i]);
    }

    if (detailsFooter != null)
    {
      final Element[] elements = detailsFooter.getElementArray();
      boolean footerEmpty = true;
      for (int i = 0; i < elements.length; i++)
      {
        final Element element = elements[i];
        if ("label".equals(element.getElementTypeName()) == false)
        {
          footerEmpty = false;
          break;
        }
      }
      if (footerEmpty)
      {
        detailsFooter.clear();
      }
    }
  }

  private void setupDefaultPadding(final Band band, final Element detailElement)
  {
    final Object maybePaddingTop = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.PADDING_TOP);
    final Object maybePaddingLeft = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.PADDING_LEFT);
    final Object maybePaddingBottom = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.PADDING_BOTTOM);
    final Object maybePaddingRight = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.PADDING_RIGHT);

    if (maybePaddingTop instanceof Number == false ||
        maybePaddingLeft instanceof Number == false ||
        maybePaddingBottom instanceof Number == false ||
        maybePaddingRight instanceof Number == false)
    {
      return;
    }

    final Number paddingTop = (Number) maybePaddingTop;
    final Number paddingLeft = (Number) maybePaddingLeft;
    final Number paddingBottom = (Number) maybePaddingBottom;
    final Number paddingRight = (Number) maybePaddingRight;

    final ElementStyleSheet styleSheet = detailElement.getStyle();
    styleSheet.setStyleProperty(ElementStyleKeys.PADDING_TOP, new Float(paddingTop.floatValue()));
    styleSheet.setStyleProperty(ElementStyleKeys.PADDING_LEFT, new Float(paddingLeft.floatValue()));
    styleSheet.setStyleProperty(ElementStyleKeys.PADDING_BOTTOM, new Float(paddingBottom.floatValue()));
    styleSheet.setStyleProperty(ElementStyleKeys.PADDING_RIGHT, new Float(paddingRight.floatValue()));
  }

  private void setupDefaultGrid(final Band band, final Element detailElement)
  {
    setupDefaultPadding(band, detailElement);
    final ElementStyleSheet styleSheet = detailElement.getStyle();
    // Always make the height of the detailElement dynamic to the band
    // According to thomas negative numbers equate to percentages
    styleSheet.setStyleProperty(ElementStyleKeys.MIN_HEIGHT, new Float(-100));

    final Object maybeBorderStyle = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.GRID_STYLE);
    final Object maybeBorderWidth = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.GRID_WIDTH);
    final Object maybeBorderColor = band.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.GRID_COLOR);

    if (maybeBorderColor instanceof Color == false ||
        maybeBorderStyle instanceof BorderStyle == false ||
        maybeBorderWidth instanceof Number == false)
    {
      return;
    }

    final BorderStyle style = (BorderStyle) maybeBorderStyle;
    final Color color = (Color) maybeBorderColor;
    final Number number = (Number) maybeBorderWidth;
    final Float width = new Float(number.floatValue());

    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_WIDTH, width);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_COLOR, color);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_TOP_STYLE, style);

    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_WIDTH, width);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_COLOR, color);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_LEFT_STYLE, style);

    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_WIDTH, width);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_COLOR, color);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_BOTTOM_STYLE, style);

    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_WIDTH, width);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_COLOR, color);
    styleSheet.setStyleProperty(ElementStyleKeys.BORDER_RIGHT_STYLE, style);
  }

  private void setupField(final Band detailsHeader,
                          final Band detailsFooter,
                          final Band itemBand,
                          final DetailFieldDefinition field,
                          final float width) throws ReportProcessingException
  {
    if (StringUtils.isEmpty(field.getField()))
    {
      return;
    }

    final Element detailElement =
        AutoGeneratorUtility.generateDetailsElement(field.getField(), computeElementType(field));
    setupDefaultGrid(itemBand, detailElement);

    final String id = "wizard::details-" + field.getField();
    detailElement.setName(id);
    detailElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
    if (Boolean.TRUE.equals
        (detailElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
    {
      detailElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", field);
    }
    if (Boolean.TRUE.equals
        (detailElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
    {
      detailElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", field);
    }
    itemBand.addElement(detailElement);

    if (Boolean.TRUE.equals(field.getOnlyShowChangingValues()))
    {
      detailElement.setAttribute
          (AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ONLY_SHOW_CHANGING_VALUES, Boolean.TRUE);
    }

    if (detailsHeader != null)
    {
      final Element headerElement = AutoGeneratorUtility.generateHeaderElement(field.getField());
      setupDefaultGrid(detailsHeader, headerElement);
      headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
      if (Boolean.TRUE.equals
          (headerElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
      {
        headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", field);
      }
      if (Boolean.TRUE.equals
          (headerElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
      {
        headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", field);
      }
      headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
          MetaAttributeNames.Style.HORIZONTAL_ALIGNMENT, field.getHorizontalAlignment());

      detailsHeader.addElement(headerElement);
    }

    if (detailsFooter != null)
    {
      final Class aggFunctionClass = field.getAggregationFunction();
      final Element footerElement = AutoGeneratorUtility.generateFooterElement
          (aggFunctionClass, computeElementType(field), null, field.getField());

      setupDefaultGrid(detailsFooter, footerElement);

      footerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(width));
      if (Boolean.TRUE.equals
          (footerElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING)))
      {
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", field);
      }
      if (Boolean.TRUE.equals
          (footerElement.getAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES)))
      {
        footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", field);
      }

      detailsFooter.addElement(footerElement);
    }
  }


  /**
   * Removes the unusedTemplateGroups based on the assumption that if a group doesn't have any
   * fields assigned to it that it is empty.
   */
  private void removedUnusedTemplateGroups(final int groupsDefined)
  {
    final RelationalGroup[] templateRelationalGroups = getTemplateRelationalGroups();
    final int templateRelationalGroupCount = templateRelationalGroups.length;
    for (int i = groupsDefined; i < templateRelationalGroupCount; i++)
    {
      RelationalGroup templateRelationalGroup = templateRelationalGroups[i];
      definition.removeGroup(templateRelationalGroup);
    }
  }

  /**
   * @return the relational groups in the templates in a flattened array.
   */
  private RelationalGroup[] getTemplateRelationalGroups()
  {
    ArrayList relationalGroups = new ArrayList();
    Group group = definition.getRootGroup();
    while (group != null && group instanceof RelationalGroup)
    {
      relationalGroups.add(group);
      final GroupBody body = group.getBody();
      if (body instanceof SubGroupBody)
      {
        final SubGroupBody sgBody = (SubGroupBody) body;
        if (sgBody.getGroup() instanceof RelationalGroup)
        {
          group = sgBody.getGroup();
        }
        else
        {
          group = null;
        }
      }
      else
      {
        group = null;
      }
    }

    return (RelationalGroup[]) relationalGroups.toArray(new RelationalGroup[relationalGroups.size()]);
  }

  private void setupRelationalGroups() throws ReportProcessingException
  {
    final Group rootgroup = definition.getRootGroup();
    RelationalGroup group;
    if (rootgroup instanceof RelationalGroup == false)
    {
      group = null;
    }
    else
    {
      group = (RelationalGroup) rootgroup;
    }

    final RelationalGroup template = findInnermostRelationalGroup(definition);

    final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
    for (int i = 0; i < groupDefinitions.length; i++)
    {
      final GroupDefinition groupDefinition = groupDefinitions[i];
      final GroupType type = groupDefinition.getGroupType();
      if (type != null && GroupType.RELATIONAL.equals(type) == false)
      {
        continue;
      }

      if (group == null)
      {
        // create a new group and insert it at the end
        RelationalGroup relationalGroup;
        if (template != null)
        {
          try
          {
            relationalGroup = (RelationalGroup) template.derive();
          }
          catch (CloneNotSupportedException e)
          {
            relationalGroup = new RelationalGroup();
          }
        }
        else
        {
          relationalGroup = new RelationalGroup();
        }

        if (groupDefinition.getGroupName() != null)
        {
          relationalGroup.setName(groupDefinition.getGroupName());
        }
        configureRelationalGroup(relationalGroup, groupDefinition);
        insertGroup(relationalGroup);
      }
      else
      {
        // modify the existing group
        configureRelationalGroup(group, groupDefinition);

        final GroupBody body = group.getBody();
        if (body instanceof SubGroupBody)
        {
          final SubGroupBody sgBody = (SubGroupBody) body;
          if (sgBody.getGroup() instanceof RelationalGroup)
          {
            group = (RelationalGroup) sgBody.getGroup();
          }
          else
          {
            group = null;
          }
        }
        else
        {
          group = null;
        }
      }
    }
    // Remove any group bands are not being used ie. groups with no fields
    removedUnusedTemplateGroups(groupDefinitions.length);
  }

  private RelationalGroup findInnermostRelationalGroup(final AbstractReportDefinition definition)
  {
    RelationalGroup retval = null;
    Group existingGroup = definition.getRootGroup();
    while (existingGroup instanceof RelationalGroup)
    {
      retval = (RelationalGroup) existingGroup;
      final GroupBody body = existingGroup.getBody();
      if (body instanceof SubGroupBody == false)
      {
        return retval;
      }
      final SubGroupBody sgb = (SubGroupBody) body;
      existingGroup = sgb.getGroup();
    }

    return retval;
  }

  /**
   * Inserts the crosstab into the report as innermost group. This method will fail if there is already a crosstab
   * active.
   *
   * @param crosstabGroup
   */
  private void insertCrosstab(final CrosstabGroup crosstabGroup)
  {
    Group existingGroup = definition.getRootGroup();
    GroupBody gb = existingGroup.getBody();
    while (gb instanceof SubGroupBody)
    {
      final SubGroupBody sgb = (SubGroupBody) gb;
      existingGroup = sgb.getGroup();
      gb = existingGroup.getBody();
    }
    existingGroup.setBody(new SubGroupBody(crosstabGroup));
  }

  private CrosstabGroup lookupCrosstab()
  {
    Group existingGroup = definition.getRootGroup();
    if (existingGroup instanceof CrosstabGroup)
    {
      return (CrosstabGroup) existingGroup;
    }

    GroupBody gb = existingGroup.getBody();
    while (gb instanceof SubGroupBody)
    {
      final SubGroupBody sgb = (SubGroupBody) gb;
      existingGroup = sgb.getGroup();
      if (existingGroup instanceof CrosstabGroup)
      {
        return (CrosstabGroup) existingGroup;
      }
      gb = existingGroup.getBody();
    }

    return null;
  }

  private void insertGroup(final RelationalGroup group)
  {
    Group lastGroup = null;
    Group insertGroup = definition.getRootGroup();
    while (true)
    {
      if (insertGroup instanceof RelationalGroup == false)
      {
        if (lastGroup == null)
        {
          definition.setRootGroup(group);
          group.setBody(new SubGroupBody(insertGroup));
          return;
        }

        final GroupBody body = lastGroup.getBody();
        final SubGroupBody sgb = new SubGroupBody(group);
        lastGroup.setBody(sgb);
        group.setBody(body);
        return;
      }

      final GroupBody body = insertGroup.getBody();
      if (body instanceof SubGroupBody == false)
      {
        final SubGroupBody sgb = new SubGroupBody(group);
        insertGroup.setBody(sgb);
        group.setBody(body);
        return;
      }

      lastGroup = insertGroup;
      final SubGroupBody sgb = (SubGroupBody) body;
      insertGroup = sgb.getGroup();
    }
  }

  private void configureCrosstabOtherGroup(final CrosstabOtherGroup group,
                                           final GroupDefinition groupDefinition) throws ReportProcessingException
  {
    final String groupField = groupDefinition.getField();
    group.setField(groupField);

    configureCrosstabGroupHeader(group, groupDefinition);
    configureCrosstabGroupFooter(group, groupDefinition);
  }

  private void configureCrosstabRowGroup(final CrosstabRowGroup group,
                                         final GroupDefinition groupDefinition) throws ReportProcessingException
  {
    final String groupField = groupDefinition.getField();
    group.setField(groupField);

    configureCrosstabGroupHeader(group, groupDefinition);
    configureCrosstabGroupFooter(group, groupDefinition);
  }

  private void configureCrosstabColumnGroup(final CrosstabColumnGroup group,
                                            final GroupDefinition groupDefinition) throws ReportProcessingException
  {
    final String groupField = groupDefinition.getField();
    group.setField(groupField);

    configureCrosstabGroupHeader(group, groupDefinition);
    configureCrosstabGroupFooter(group, groupDefinition);
  }


  private void configureRelationalGroup(final RelationalGroup group,
                                        final GroupDefinition groupDefinition) throws ReportProcessingException
  {
    final String groupField = groupDefinition.getField();
    if (groupField != null)
    {
      group.setFieldsArray(new String[]{groupField});
    }

    configureRelationalGroupFooter(group, groupDefinition);
    configureRelationalGroupHeader(group, groupDefinition);
  }

  private void configureCrosstabGroupHeader(final Group group,
                                            final GroupDefinition groupDefinition)
  {
    final RootBandDefinition headerDefinition = groupDefinition.getHeader();
    if (headerDefinition.isVisible())
    {
      final GroupHeader header = group.getHeader();
      final Boolean repeat = headerDefinition.getRepeat();
      if (repeat != null)
      {
        header.setRepeat(repeat.booleanValue());
      }

      final Band content = AutoGeneratorUtility.findGeneratedContent(header);
      if (content == null)
      {
        return;
      }

      final Element headerElement = AutoGeneratorUtility.generateDetailsElement
          (groupDefinition.getField(), computeElementType(groupDefinition));
      final Length length = groupDefinition.getWidth();
      if (length != null)
      {
        headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, length.getNormalizedValue());
      }
      headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", headerDefinition);
      headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", groupDefinition);

      content.clear();
      content.addElement(headerElement);
    }
  }

  private void configureRelationalGroupHeader(final Group group,
                                              final GroupDefinition groupDefinition)
  {
    final RootBandDefinition headerDefinition = groupDefinition.getHeader();
    if (headerDefinition.isVisible())
    {
      final GroupHeader header = group.getHeader();
      final Boolean repeat = headerDefinition.getRepeat();
      if (repeat != null)
      {
        header.setRepeat(repeat.booleanValue());
      }

      final Band content = AutoGeneratorUtility.findGeneratedContent(header);
      if (content == null)
      {
        return;
      }

      final Element headerLabelElement = new Element();
      headerLabelElement.setElementType(new LabelType());
      if (groupDefinition.getDisplayName() != null)
      {
        headerLabelElement.setAttribute
            (AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, groupDefinition.getDisplayName());
      }
      else
      {
        headerLabelElement.setAttribute
            (AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, groupDefinition.getField());
        headerLabelElement.setAttribute
            (AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR, groupDefinition.getField());
        headerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
          AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES, Boolean.TRUE);
      }

      final Element headerValueElement =
          AutoGeneratorUtility.generateDetailsElement(groupDefinition.getField(), computeElementType(groupDefinition));
      headerValueElement.setAttribute(AttributeNames.Core.NAMESPACE, AttributeNames.Core.NULL_VALUE, "-");
     
      final Band headerElement = new Band();
      headerElement.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
      headerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
      headerElement.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
      headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
          AttributeNames.Wizard.ALLOW_METADATA_STYLING, Boolean.TRUE);
      headerElement.setAttribute
          (AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR, groupDefinition.getField());
      headerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", headerDefinition);
      headerElement.addElement(headerLabelElement);
      headerElement.addElement(headerValueElement);
      content.clear();
      content.addElement(headerElement);
    }
  }

  private void configureRelationalGroupFooter(final Group group, final GroupDefinition groupDefinition)
      throws ReportProcessingException
  {
    final RootBandDefinition footerDefinition = groupDefinition.getFooter();
    if (footerDefinition.isVisible() == false)
    {
      return;
    }

    if (groupDefinition.getAggregationFunction() == null && (groupDefinition.getGroupTotalsLabel() == null || groupDefinition.getGroupTotalsLabel().length() == 0))
    {
      return;
    }

    final GroupFooter footer = group.getFooter();
    final Boolean repeat = footerDefinition.getRepeat();
    if (repeat != null)
    {
      footer.setRepeat(repeat.booleanValue());
    }

    final Band content = AutoGeneratorUtility.findGeneratedContent(footer);
    if (content == null)
    {
      return;
    }

    final Class aggFunctionClass = groupDefinition.getAggregationFunction();
    final Element footerValueElement = AutoGeneratorUtility.generateFooterElement
        (aggFunctionClass, computeElementType(groupDefinition),
            groupDefinition.getGroupName(), groupDefinition.getField());

    final Element footerLabelElement = new Element();
    footerLabelElement.setElementType(new LabelType());
    if (groupDefinition.getGroupTotalsLabel() != null)
    {
      footerLabelElement.setAttribute
          (AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, groupDefinition.getGroupTotalsLabel());
    }
    else
    {
      footerLabelElement.setAttribute
          (AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, groupDefinition.getField());
      footerLabelElement.setAttribute
          (AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR, groupDefinition.getField());
      footerLabelElement.setAttribute(AttributeNames.Wizard.NAMESPACE,
        AttributeNames.Wizard.ALLOW_METADATA_ATTRIBUTES, Boolean.TRUE);
    }

    final Band footerElement = new Band();
    footerElement.getStyle().setStyleProperty(BandStyleKeys.LAYOUT, "inline");
    footerElement.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(-100));
    footerElement.getStyle().setStyleProperty(ElementStyleKeys.DYNAMIC_HEIGHT, Boolean.TRUE);
    footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.ALLOW_METADATA_STYLING,
        Boolean.TRUE);
    footerElement.setAttribute
        (AttributeNames.Wizard.NAMESPACE, AttributeNames.Wizard.LABEL_FOR, groupDefinition.getField());
    footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", footerDefinition);
    footerElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", groupDefinition);
    footerElement.addElement(footerLabelElement);
    footerElement.addElement(footerValueElement);

    content.clear();
    content.addElement(footerElement);
  }

  private void configureCrosstabGroupFooter(final Group group, final GroupDefinition groupDefinition)
      throws ReportProcessingException
  {
    final RootBandDefinition footerDefinition = groupDefinition.getFooter();
    if (footerDefinition.isVisible() == false)
    {
      return;
    }

    if (groupDefinition.getAggregationFunction() == null)
    {
      return;
    }

    final GroupFooter footer = group.getFooter();
    final Boolean repeat = footerDefinition.getRepeat();
    if (repeat != null)
    {
      footer.setRepeat(repeat.booleanValue());
    }

    final Band content = AutoGeneratorUtility.findGeneratedContent(footer);
    if (content == null)
    {
      return;
    }

    final Class aggFunctionClass = groupDefinition.getAggregationFunction();
    final Element footerValueElement = AutoGeneratorUtility.generateFooterElement
        (aggFunctionClass, computeElementType(groupDefinition),
            groupDefinition.getGroupName(), groupDefinition.getField());
    footerValueElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFormatData", footer);
    footerValueElement.setAttribute(AttributeNames.Wizard.NAMESPACE, "CachedWizardFieldData", groupDefinition);

    content.clear();
    content.addElement(footerValueElement);

  }

  private ElementType computeElementType(final FieldDefinition fieldDefinition)
  {
    // todo: Make this configurable or even better: drop it into the element metadata.

    final String field = fieldDefinition.getField();
    final DataAttributes attributes = flowController.getDataSchema().getAttributes(field);
    if (attributes == null)
    {
      logger.warn("Field '" + field + "' is declared in the wizard-specification, " +
          "but not present in the data. Assuming defaults.");
      return new TextFieldType();
    }
    final Class fieldType = (Class) attributes.getMetaAttribute
        (MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.TYPE, Class.class, attributeContext);
    if (fieldType == null)
    {
      return new TextFieldType();
    }

    if (Number.class.isAssignableFrom(fieldType))
    {
      return new NumberFieldType();
    }
    if (Date.class.isAssignableFrom(fieldType))
    {
      return new DateFieldType();
    }
    if (byte[].class.isAssignableFrom(fieldType) ||
        Blob.class.isAssignableFrom(fieldType) ||
        Image.class.isAssignableFrom(fieldType))
    {
      return new ContentFieldType();
    }
    return new TextFieldType();
  }

  private boolean isCrosstab()
  {
    final GroupDefinition[] groupDefinitions = wizardSpecification.getGroupDefinitions();
    for (int i = 0; i < groupDefinitions.length; i++)
    {
      final GroupDefinition groupDefinition = groupDefinitions[i];
      final GroupType groupType = groupDefinition.getGroupType();
      if (GroupType.CT_COLUMN.equals(groupType) ||
          GroupType.CT_ROW.equals(groupType))
      {
        return true;
      }
    }

    final DataAttributes tableAttributes = flowController.getDataSchema().getTableAttributes();
    final Object crosstabMode = tableAttributes.getMetaAttribute
        (MetaAttributeNames.Core.NAMESPACE, MetaAttributeNames.Core.CROSSTAB_MODE, String.class, attributeContext);
    if (MetaAttributeNames.Core.CROSSTAB_VALUE_NORMALIZED.equals(crosstabMode))
    {
      // the data-source indicates a high probability that a crosstab is requested.
      return true;
    }
    return false;
  }

  private void setupWatermark()
  {
    final WatermarkDefinition watermarkDefinition = wizardSpecification.getWatermarkDefinition();
    if (watermarkDefinition.isVisible() == false)
    {
      return;
    }

    if (watermarkDefinition.getSource() == null)
    {
      return;
    }

    final Watermark watermark = definition.getWatermark();
    final Band content = AutoGeneratorUtility.findGeneratedContent(watermark);
    if (content == null)
    {
      // there is already some content, and we are not allowed to override it.
      return;
    }

    content.clear();

    final Element watermarkImage = new Element();
    watermarkImage.setElementType(new ContentType());
    watermarkImage.setAttribute
        (AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, watermarkDefinition.getSource());
    final ElementStyleSheet watermarkStyle = watermarkImage.getStyle();
    watermarkStyle.setStyleProperty(ElementStyleKeys.POS_X, convertLength(watermarkDefinition.getX()));
    watermarkStyle.setStyleProperty(ElementStyleKeys.POS_Y, convertLength(watermarkDefinition.getY()));
    watermarkStyle.setStyleProperty(ElementStyleKeys.MIN_WIDTH, convertLength(watermarkDefinition.getWidth()));
    watermarkStyle.setStyleProperty(ElementStyleKeys.MIN_HEIGHT, convertLength(watermarkDefinition.getHeight()));
    watermarkStyle.setStyleProperty(ElementStyleKeys.KEEP_ASPECT_RATIO, watermarkDefinition.getKeepAspectRatio());
    watermarkStyle.setStyleProperty(ElementStyleKeys.SCALE, watermarkDefinition.getScale());

    content.addElement(watermarkImage);
  }

  private Float convertLength(final Length length)
  {
    if (length == null)
    {
      return null;
    }
    return length.getNormalizedValue();
  }

}
TOP

Related Classes of org.pentaho.reporting.engine.classic.wizard.WizardProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.