Package org.pentaho.reporting.designer.core.editor.styles

Source Code of org.pentaho.reporting.designer.core.editor.styles.StyleTableModel$UpdateDataTask

/*!
* 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.styles;

import java.beans.PropertyEditor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.swing.SwingUtilities;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.designer.core.editor.ReportDocumentContext;
import org.pentaho.reporting.designer.core.settings.WorkspaceSettings;
import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel;
import org.pentaho.reporting.designer.core.util.table.GroupedName;
import org.pentaho.reporting.designer.core.util.table.GroupingHeader;
import org.pentaho.reporting.designer.core.util.table.TableStyle;
import org.pentaho.reporting.designer.core.util.undo.CompoundUndoEntry;
import org.pentaho.reporting.designer.core.util.undo.StyleEditUndoEntry;
import org.pentaho.reporting.designer.core.util.undo.StyleExpressionEditUndoEntry;
import org.pentaho.reporting.designer.core.util.undo.UndoEntry;
import org.pentaho.reporting.designer.core.util.undo.UndoManager;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.metadata.GroupedMetaDataComparator;
import org.pentaho.reporting.engine.classic.core.metadata.PlainMetaDataComparator;
import org.pentaho.reporting.engine.classic.core.metadata.StyleMetaData;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleSheet;
import org.pentaho.reporting.engine.classic.core.style.ResolverStyleSheet;
import org.pentaho.reporting.engine.classic.core.style.resolver.SimpleStyleResolver;
import org.pentaho.reporting.engine.classic.core.style.resolver.StyleResolver;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;

public class StyleTableModel extends AbstractStyleTableModel<StyleTableModel.DefaultStyleDataBackend>
{
  private static final Log logger = LogFactory.getLog(StyleTableModel.class);

  private static final Object NULL_INDICATOR = new Object();
  private static final Element[] EMPTY_ELEMENTS = new Element[0];
  private static final ElementType[] EMPTY_ELEMENT_TYPES = new ElementType[0];

  private static final Object[] EMPTY_VALUES = new Object[0];

  protected static class DefaultStyleDataBackend extends AbstractStyleDataBackend
  {
    private Element[] elements;
    private ElementType[] elementTypes;
    private Object[] inheritValues;
    private Object[] expressionValues;

    private DefaultStyleDataBackend()
    {
      this.elements = EMPTY_ELEMENTS;
      this.elementTypes = EMPTY_ELEMENT_TYPES;
      this.inheritValues = EMPTY_VALUES;
      this.expressionValues = EMPTY_VALUES;
    }

    private DefaultStyleDataBackend(final StyleMetaData[] metaData,
                                    final GroupingHeader[] groupings,
                                    final Element[] elements)
    {
      super(metaData, groupings);
      this.elements = elements;
      this.elementTypes = new ElementType[elements.length];

      for (int i = 0; i < elements.length; i++)
      {
        final Element element = elements[i];
        elementTypes[i] = element.getElementType();
      }

      final ResolverStyleSheet resolverStyleSheet = getResolvedStyle();
      if (elements.length > 0)
      {
        final StyleResolver resolver = new SimpleStyleResolver(true);
        resolver.resolve(elements[0], resolverStyleSheet);
      }

      this.inheritValues = new Object[metaData.length];
      this.expressionValues = new Object[metaData.length];
    }

    public void clearCache(final int rowIndex)
    {
      super.clearCache(rowIndex);
      inheritValues[rowIndex] = null;
    }

    public void resetCache()
    {
      super.resetCache();
      Arrays.fill(inheritValues, null);
      Arrays.fill(expressionValues, null);

      final ResolverStyleSheet resolverStyleSheet = getResolvedStyle();
      if (elements.length > 0)
      {
        final StyleResolver resolver = new SimpleStyleResolver(true);
        resolver.resolve(elements[0], resolverStyleSheet);
      }
      else
      {
        resolverStyleSheet.clear();
      }
    }

    public Element[] getData()
    {
      return elements;
    }

    public void clearExpressionsCache(final int rowIndex)
    {
      expressionValues[rowIndex] = null;
    }

    public Object[] getInheritValues()
    {
      return inheritValues;
    }

    public Object[] getExpressionValues()
    {
      return expressionValues;
    }

    public ElementType[] getElementTypes()
    {
      return elementTypes;
    }
  }

  private class UpdateDataTask implements Runnable
  {
    private Element[] elements;
    private boolean synchronous;

    private UpdateDataTask(final Element[] elements,
                           final boolean synchronous)
    {
      this.synchronous = synchronous;
      this.elements = elements.clone();
    }

    public void run()
    {
      try
      {
        final DefaultStyleDataBackend dataBackend = updateData(elements);
        if (synchronous || SwingUtilities.isEventDispatchThread())
        {
          setDataBackend(dataBackend);
          fireTableDataChanged();
        }
        else
        {
          SwingUtilities.invokeAndWait(new NotifyChangeTask(dataBackend));
        }
      }
      catch (Exception e)
      {
        UncaughtExceptionsModel.getInstance().addException(e);
      }
    }
  }

  private Executor pool;
  private DefaultStyleDataBackend oldDataBackend;
  private ReportDocumentContext reportRenderContext;

  public StyleTableModel()
  {
    this(Executors.newSingleThreadExecutor());
  }

  public StyleTableModel(final Executor pool)
  {
    if (pool == null)
    {
      throw new NullPointerException();
    }
    this.pool = pool;
    super.setDataBackend(new DefaultStyleDataBackend());

  }

  public void setTableStyle(final TableStyle tableStyle)
  {
    super.setTableStyle(tableStyle);
    pool.execute(new UpdateDataTask(getData(), isSynchronous()));
  }

  public synchronized void setDataBackend(final DefaultStyleDataBackend dataBackend)
  {
    this.oldDataBackend = getDataBackend();
    super.setDataBackend(dataBackend);
  }

  protected DefaultStyleDataBackend updateData(final Element[] elements)
  {
    final StyleMetaData[] metaData = selectCommonAttributes(elements);
    final TableStyle tableStyle = getTableStyle();
    if (tableStyle == TableStyle.ASCENDING)
    {
      Arrays.sort(metaData, new PlainMetaDataComparator());
      return (new DefaultStyleDataBackend(metaData, new GroupingHeader[metaData.length], elements));
    }
    else if (tableStyle == TableStyle.DESCENDING)
    {
      Arrays.sort(metaData, Collections.reverseOrder(new PlainMetaDataComparator()));
      return (new DefaultStyleDataBackend(metaData, new GroupingHeader[metaData.length], elements));
    }
    else
    {
      Arrays.sort(metaData, new GroupedMetaDataComparator());
      final Locale locale = Locale.getDefault();
      int groupCount = 0;
      int metaDataCount = 0;

      if (metaData.length > 0)
      {
        String oldValue = null;

        for (int i = 0; i < metaData.length; i++)
        {
          final StyleMetaData data = metaData[i];
          if (data.isHidden())
          {
            continue;
          }
          if (WorkspaceSettings.getInstance().isShowExpertItems() == false && data.isExpert())
          {
            continue;
          }
          if (WorkspaceSettings.getInstance().isShowDeprecatedItems() == false && data.isDeprecated())
          {
            continue;
          }

          metaDataCount += 1;

          if (groupCount == 0)
          {
            groupCount = 1;
            final StyleMetaData firstdata = metaData[i];
            oldValue = firstdata.getGrouping(locale);
            continue;
          }

          final String grouping = data.getGrouping(locale);
          if ((ObjectUtilities.equal(oldValue, grouping)) == false)
          {
            oldValue = grouping;
            groupCount += 1;
          }
        }
      }

      final StyleMetaData[] groupedMetaData = new StyleMetaData[metaDataCount + groupCount];
      int targetIdx = 0;
      GroupingHeader[] groupings = new GroupingHeader[groupedMetaData.length];
      GroupingHeader group = null;
      for (int sourceIdx = 0; sourceIdx < metaData.length; sourceIdx++)
      {
        final StyleMetaData data = metaData[sourceIdx];
        if (data.isHidden())
        {
          continue;
        }
        if (WorkspaceSettings.getInstance().isShowExpertItems() == false && data.isExpert())
        {
          continue;
        }
        if (WorkspaceSettings.getInstance().isShowDeprecatedItems() == false && data.isDeprecated())
        {
          continue;
        }

        if (targetIdx == 0)
        {
          group = new GroupingHeader(data.getGrouping(locale));
          groupings[targetIdx] = group;
          targetIdx += 1;
        }
        else
        {
          final String newgroup = data.getGrouping(locale);
          //noinspection ConstantConditions
          if ((ObjectUtilities.equal(newgroup, group.getHeaderText())) == false)
          {
            group = new GroupingHeader(newgroup);
            groupings[targetIdx] = group;
            targetIdx += 1;
          }
        }

        groupings[targetIdx] = group;
        groupedMetaData[targetIdx] = data;
        targetIdx += 1;
      }

      if (oldDataBackend != null)
      {
        groupings = reconcileState(groupings, oldDataBackend.getGroupings());
      }


      return new DefaultStyleDataBackend(groupedMetaData, groupings, elements);
    }
  }

  private static boolean isSameElements(final Element[] elements,
                                        final ElementType[] elementTypes,
                                        final Element[] oldElements)
  {
    if (elements.length != oldElements.length)
    {
      // that is easy!
      return false;
    }

    for (int i = 0; i < elements.length; i++)
    {
      final Element element = elements[i];
      if (oldElements[i].getObjectID() != element.getObjectID())
      {
        return false;
      }
      if (oldElements[i].getElementType() != elementTypes[i])
      {
        return false;
      }
    }
    return true;
  }

  protected static StyleMetaData[] selectCommonAttributes(final Element[] elements)
  {
    final HashMap<String, Boolean> attributes = new HashMap<String, Boolean>();
    final ArrayList<StyleMetaData> selectedArrays = new ArrayList<StyleMetaData>();
    for (int elementIdx = 0; elementIdx < elements.length; elementIdx++)
    {
      final Element element = elements[elementIdx];
      final StyleMetaData[] datas = element.getMetaData().getStyleDescriptions();
      for (int styleIdx = 0; styleIdx < datas.length; styleIdx++)
      {
        final StyleMetaData data = datas[styleIdx];
        final String name = data.getName();

        if (data.isHidden())
        {
          attributes.put(name, Boolean.FALSE);
          continue;
        }
        if (WorkspaceSettings.getInstance().isShowExpertItems() == false && data.isExpert())
        {
          attributes.put(name, Boolean.FALSE);
          continue;
        }
        if (WorkspaceSettings.getInstance().isShowDeprecatedItems() == false && data.isDeprecated())
        {
          attributes.put(name, Boolean.FALSE);
          continue;
        }

        final Object attribute = attributes.get(name);
        if (Boolean.TRUE.equals(attribute))
        {
          // fine, we already have a value for it.
        }
        else if (attribute == null)
        {
          // add it ..
          if (elementIdx == 0)
          {
            selectedArrays.add(data);
            attributes.put(name, Boolean.TRUE);
          }
          else
          {
            attributes.put(name, Boolean.FALSE);
          }
        }

      }
    }

    return selectedArrays.toArray(new StyleMetaData[selectedArrays.size()]);
  }

  public void setData(final Element[] elements)
  {
    final DefaultStyleDataBackend backend = this.getDataBackend();
    if (isSameElements(elements, backend.getElementTypes(), backend.getData()))
    {
      if (isSynchronous())
      {
        new SameElementsUpdateDataTask(backend, isSynchronous()).run();
      }
      else
      {
        SwingUtilities.invokeLater(new SameElementsUpdateDataTask(backend, isSynchronous()));
      }
      return;
    }

    pool.execute(new UpdateDataTask(elements, isSynchronous()));
  }

  public Element[] getData()
  {
    return getDataBackend().getData();
  }

  public int getColumnCount()
  {
    return 4;
  }

  public String getColumnName(final int column)
  {
    switch (column)
    {
      case 0:
        return Messages.getString("StyleTableModel.NameColumn");
      case 1:
        return Messages.getString("StyleTableModel.InheritColumn");
      case 2:
        return Messages.getString("StyleTableModel.ValueColumn");
      case 3:
        return Messages.getString("StyleTableModel.FormulaColumn");
      default:
        throw new IllegalArgumentException();
    }
  }

  public Object getValueAt(final int rowIndex, final int columnIndex)
  {
    final StyleMetaData metaData = getMetaData(rowIndex);
    if (metaData == null)
    {
      return getGroupings(rowIndex);
    }
    switch (columnIndex)
    {
      case 0:
        return new GroupedName(metaData);
      case 1:
        return computeInheritValue(metaData, rowIndex);
      case 2:
        return computeFullValue(metaData, rowIndex);
      case 3:
        return computeExpressionValue(metaData, rowIndex);
      default:
        throw new IndexOutOfBoundsException();
    }
  }

  public boolean isCellEditable(final int rowIndex, final int columnIndex)
  {
    final StyleMetaData metaData = getMetaData(rowIndex);
    if (metaData == null)
    {
      return false;
    }

    switch (columnIndex)
    {
      case 0:
        return false;
      case 1:
        return true;
      case 2:
        return true;
      case 3:
        return true;
      default:
        throw new IndexOutOfBoundsException();
    }
  }

  public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex)
  {
    final StyleMetaData metaData = getMetaData(rowIndex);
    if (metaData == null)
    {
      return;
    }

    switch (columnIndex)
    {
      case 0:
        return;
      case 1:
      {
        if (Boolean.TRUE.equals(aValue))
        {
          if (defineFullValue(metaData, null))
          {
            getDataBackend().clearCache(rowIndex);
            fireTableDataChanged();
          }
        }
        break;
      }
      case 2:
      {
        if (defineFullValue(metaData, aValue))
        {
          getDataBackend().clearCache(rowIndex);
          fireTableDataChanged();
        }
        break;
      }
      case 3:
      {
        if (aValue != null && aValue instanceof Expression == false)
        {
          return;
        }
        if (defineExpressionValue(metaData, (Expression) aValue))
        {
          getDataBackend().clearExpressionsCache(rowIndex);
          fireTableDataChanged();
        }
        break;
      }
      default:
        throw new IndexOutOfBoundsException();
    }
  }

  protected boolean defineFullValue(final StyleMetaData metaData,
                                    final Object value)
  {
    if (value != null && metaData.getTargetType().isInstance(value) == false)
    {
      // not the correct type
      logger.warn("Invalid type: " + value + "(" + value.getClass() + ") but expected " // NON-NLS
          metaData.getTargetType());
      return false;
    }

    boolean changed = false;
    final Element[] elements = getDataBackend().getData();
    for (int i = 0; i < elements.length; i++)
    {
      final Element element = elements[i];
      final ElementStyleSheet styleSheet = element.getStyle();
      final Object attribute = styleSheet.getStyleProperty(metaData.getStyleKey());
      if ((ObjectUtilities.equal(attribute, value)) == false)
      {
        changed = true;
      }
    }

    if (changed)
    {
      final ReportDocumentContext reportRenderContext = getReportRenderContext();
      if (reportRenderContext == null)
      {
        throw new IllegalStateException("No report render context? Thats bad.");
      }
      final UndoManager undo = reportRenderContext.getUndo();
      final ArrayList<UndoEntry> undos = new ArrayList<UndoEntry>();

      for (int i = 0; i < elements.length; i++)
      {
        final Element element = elements[i];
        final ElementStyleSheet styleSheet = element.getStyle();
        final Object attribute = styleSheet.getStyleProperty(metaData.getStyleKey());
        undos.add(new StyleEditUndoEntry
            (element.getObjectID(), metaData.getStyleKey(), attribute, value));
        styleSheet.setStyleProperty(metaData.getStyleKey(), value);
      }
      undo.addChange(Messages.getString("StyleChange"), new CompoundUndoEntry((UndoEntry[]) undos.toArray(new UndoEntry[undos.size()])));
    }
    return changed;
  }

  protected Object computeInheritValue(final StyleMetaData metaData,
                                       final int rowIndex)
  {
    final DefaultStyleDataBackend dataBackend1 = getDataBackend();
    final Object[] inheritValues = dataBackend1.getInheritValues();
    final Object o = inheritValues[rowIndex];
    if (o == StyleDataBackend.NULL_INDICATOR)
    {
      return null;
    }
    if (o != null)
    {
      return o;
    }

    boolean allLocalKeys = true;
    boolean allInheritedKeys = true;
    final Element[] elements = dataBackend1.getData();
    if (elements.length > 0)
    {
      final Element element = elements[0];
      final ElementStyleSheet styleSheet = element.getStyle();
      final boolean localKey = styleSheet.isLocalKey(metaData.getStyleKey());
      allLocalKeys = allLocalKeys & localKey;
      allInheritedKeys = (localKey == false);
    }
    final Object retval;
    if (allLocalKeys == true && allInheritedKeys == true)
    {
      retval = null;
    }
    else if (allInheritedKeys == true)
    {
      retval = Boolean.TRUE;
    }
    else if (allLocalKeys == true)
    {
      retval = Boolean.FALSE;
    }
    else
    {
      retval = null;
    }
    if (retval == null)
    {
      inheritValues[rowIndex] = StyleDataBackend.NULL_INDICATOR;
    }
    else
    {
      inheritValues[rowIndex] = retval;
    }
    return retval;
  }

  private boolean defineExpressionValue(final StyleMetaData metaData,
                                        final Expression value)
  {
    boolean changed = false;
    final Element[] elements = getDataBackend().getData();
    for (int i = 0; i < elements.length; i++)
    {
      final Element element = elements[i];
      final Expression attribute = element.getStyleExpression(metaData.getStyleKey());
      if ((ObjectUtilities.equal(attribute, value)) == false)
      {
        changed = true;
      }
    }

    if (changed)
    {
      final ReportDocumentContext reportRenderContext = getReportRenderContext();
      if (reportRenderContext == null)
      {
        throw new IllegalStateException("No report render context? Thats bad.");
      }
      final UndoManager undo = reportRenderContext.getUndo();
      final ArrayList<UndoEntry> undos = new ArrayList<UndoEntry>();

      for (int i = 0; i < elements.length; i++)
      {
        final Element element = elements[i];
        final Expression attribute = element.getStyleExpression(metaData.getStyleKey());
        if (value == null)
        {
          undos.add(new StyleExpressionEditUndoEntry
              (element.getObjectID(), metaData.getStyleKey(), attribute, null));
          element.setStyleExpression(metaData.getStyleKey(), null);
          element.notifyNodePropertiesChanged();
        }
        else
        {
          final Expression expression = value.getInstance();
          undos.add(new StyleExpressionEditUndoEntry
              (element.getObjectID(), metaData.getStyleKey(), attribute, expression));
          element.setStyleExpression(metaData.getStyleKey(), expression);
          element.notifyNodePropertiesChanged();
        }
      }
      undo.addChange(Messages.getString("StyleChange"), new CompoundUndoEntry((UndoEntry[]) undos.toArray(new UndoEntry[undos.size()])));

    }
    return changed;
  }

  private Expression computeExpressionValue(final StyleMetaData metaData,
                                            final int row)
  {
    final DefaultStyleDataBackend dataBackend1 = getDataBackend();
    final Object[] expressionValues = dataBackend1.getExpressionValues();
    final Object o = expressionValues[row];
    if (o == NULL_INDICATOR)
    {
      return null;
    }
    if (o != null)
    {
      return (Expression) o;
    }


    Expression lastElement = null;
    final Element[] elements = dataBackend1.getData();
    if (elements.length > 0)
    {
      final Element element = elements[0];
      lastElement = element.getStyleExpression(metaData.getStyleKey());
    }
    if (lastElement != null)
    {
      expressionValues[row] = lastElement;
    }
    else
    {
      expressionValues[row] = NULL_INDICATOR;
    }
    return lastElement;
  }

  public Class getClassForCell(final int rowIndex, final int columnIndex)
  {
    final StyleMetaData metaData = getMetaData(rowIndex);
    if (metaData == null)
    {
      return GroupingHeader.class;
    }

    switch (columnIndex)
    {
      case 0:
        return GroupedName.class;
      case 1:
        return Boolean.class;
      case 2:
        return metaData.getTargetType();
      case 3:
        return Expression.class;
      default:
        throw new IndexOutOfBoundsException();
    }
  }

  public PropertyEditor getEditorForCell(final int rowIndex, final int columnIndex)
  {
    final StyleMetaData metaData = getMetaData(rowIndex);
    if (metaData == null)
    {
      return null;
    }

    switch (columnIndex)
    {
      case 0:
        return null;
      case 1:
        return null;
      case 2:
        return computeEditor(metaData, rowIndex);
      case 3:
        return null;
      default:
        throw new IndexOutOfBoundsException();
    }
  }

  public ReportDocumentContext getReportRenderContext()
  {
    return reportRenderContext;
  }

  public void setReportRenderContext(final ReportDocumentContext reportRenderContext)
  {
    this.reportRenderContext = reportRenderContext;
  }
}
TOP

Related Classes of org.pentaho.reporting.designer.core.editor.styles.StyleTableModel$UpdateDataTask

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.