/**
  * Sets the data source for this Element. The data source is used to produce or query the
  * element's display value.
  *
  * @param ds the datasource (<code>null</code> not permitted).
  * @throws NullPointerException if the given data source is null.
  * @deprecated The data-source should not be used anymore. Use ElementType implementations
  *     instead. This method only exists to let old reports run.
  */
 public void setDataSource(final DataSource ds) {
   if (ds == null) {
     throw new NullPointerException("Element.setDataSource(...) : null data source.");
   }
   this.datasource = ds;
   notifyNodePropertiesChanged();
 }
  public void setAttribute(
      final String namespace, final String name, final Object value, final boolean notifyChange) {
    if (copyOnWrite) {
      this.attributes = attributes.clone();
      this.copyOnWrite = false;
    }

    final Object oldValue = attributes.setAttribute(namespace, name, value);
    if (cachedAttributes != null) {
      if (cachedAttributes.getChangeTracker() != attributes.getChangeTracker()) {
        cachedAttributes = null;
      }
    }
    if (AttributeNames.Core.NAMESPACE.equals(namespace)
        && AttributeNames.Core.ELEMENT_TYPE.equals(name)) {
      if (value instanceof ElementType) {
        this.elementType = (ElementType) value;
      } else {
        this.elementType = LegacyType.INSTANCE;
      }
    }

    if (notifyChange) {
      notifyNodePropertiesChanged(new AttributeChange(namespace, name, oldValue, value));
    }
  }
  /** Invoked when an action occurs. */
  public void actionPerformed(final ActionEvent e) {
    final Object o = comboBox.getSelectedItem();
    if (o != null && o instanceof String == false) {
      return;
    }
    final String font = (String) o;
    final ReportRenderContext activeContext = getActiveContext();
    if (activeContext == null) {
      return;
    }

    final ReportSelectionModel selectionModel1 = getSelectionModel();
    if (selectionModel1 == null) {
      return;
    }
    final Element[] visualElements = selectionModel1.getSelectedVisualElements();
    final ArrayList<UndoEntry> undos = new ArrayList<UndoEntry>();
    for (int i = 0; i < visualElements.length; i++) {
      final Element visualElement = visualElements[i];
      undos.add(StyleEditUndoEntry.createConditional(visualElement, TextStyleKeys.FONT, font));
      visualElement.getStyle().setStyleProperty(TextStyleKeys.FONT, font);
      visualElement.notifyNodePropertiesChanged();
    }
    getActiveContext()
        .getUndo()
        .addChange(
            ActionMessages.getString("ApplyFontFamilyAction.UndoName"),
            new CompoundUndoEntry(undos.toArray(new UndoEntry[undos.size()])));
  }
  public void setAttributeExpression(
      final String namespace, final String name, final Expression value) {
    if (attributeExpressions == null) {
      attributeExpressions = new ReportAttributeMap<Expression>();
    }

    final Expression oldExpression = this.attributeExpressions.setAttribute(namespace, name, value);
    notifyNodePropertiesChanged(
        new AttributeExpressionChange(namespace, name, oldExpression, value));
  }
    public void setStyleProperty(final StyleKey key, final Object value) {
      final long l = getChangeTracker();
      final Object oldValue;
      if (super.isLocalKey(key)) {
        oldValue = super.getStyleProperty(key);
      } else {
        oldValue = null;
      }

      super.setStyleProperty(key, value);
      if (l != getChangeTracker()) {
        element.notifyNodePropertiesChanged(new StyleChange(key, oldValue, value));
      }
    }
  /**
   * Adds a function to the report's collection of expressions.
   *
   * @param property the stylekey that will be modified by this element.
   * @param function the function.
   */
  public void setStyleExpression(final StyleKey property, final Expression function) {
    if (styleExpressions == null) {
      if (function == null) {
        return;
      }

      styleExpressions = new HashMap<StyleKey, Expression>();
    }
    final Object oldValue;
    if (function == null) {
      oldValue = styleExpressions.remove(property);
    } else {
      oldValue = styleExpressions.put(property, function);
    }
    notifyNodePropertiesChanged(
        new StyleExpressionChange(property, (Expression) oldValue, function));
  }
  /** Invoked when an action occurs. */
  public void actionPerformed(final ActionEvent e) {
    final ReportSelectionModel selectionModel = getSelectionModel();
    if (selectionModel == null) {
      return;
    }
    final Element[] visualElements = selectionModel.getSelectedVisualElements();
    if (visualElements.length == 0) {
      return;
    }
    final ReportRenderContext activeContext = getActiveContext();
    if (activeContext == null) {
      return;
    }

    Boolean value = Boolean.FALSE;
    final ArrayList<UndoEntry> undos = new ArrayList<UndoEntry>();
    for (int i = 0; i < visualElements.length; i++) {
      final Element element = visualElements[i];
      final ElementStyleSheet styleSheet = element.getStyle();
      if (i == 0) {
        if (styleSheet.getBooleanStyleProperty(TextStyleKeys.ITALIC)) {
          value = Boolean.FALSE;
        } else {
          value = Boolean.TRUE;
        }
      }
      undos.add(StyleEditUndoEntry.createConditional(element, TextStyleKeys.ITALIC, value));
      styleSheet.setStyleProperty(TextStyleKeys.ITALIC, value);
      element.notifyNodePropertiesChanged();
    }
    getActiveContext()
        .getUndo()
        .addChange(
            ActionMessages.getString("ItalicsAction.UndoName"),
            new CompoundUndoEntry(undos.toArray(new UndoEntry[undos.size()])));
  }
  public void update(final Point2D normalizedPoint, final double zoomFactor) {
    final SnapPositionsModel horizontalSnapModel = getHorizontalSnapModel();
    final Element[] selectedVisualElements = getSelectedVisualElements();
    final long originPointX = getOriginPointX();
    final long[] elementWidth = getElementWidth();
    final long px = StrictGeomUtility.toInternalValue(normalizedPoint.getX());
    final long dx = px - originPointX;

    for (int i = 0; i < selectedVisualElements.length; i++) {
      final Element element = selectedVisualElements[i];
      if (element instanceof RootLevelBand) {
        continue;
      }
      final ElementStyleSheet styleSheet = element.getStyle();
      final double elementMinWidth =
          styleSheet.getDoubleStyleProperty(ElementStyleKeys.MIN_WIDTH, 0);

      // this is where I want the element on a global scale...
      final long targetWidth = elementWidth[i] + dx;
      final CachedLayoutData data = ModelUtility.getCachedLayoutData(element);
      final long elementX = data.getX();
      final long targetX2 = elementX + targetWidth;

      if (elementMinWidth >= 0) {
        // absolute position; resolving is easy here
        final long snapPosition =
            horizontalSnapModel.getNearestSnapPosition(targetX2, element.getObjectID());
        if (Math.abs(snapPosition - targetX2) > snapThreshold) {
          final long localWidth = Math.max(0, targetX2 - elementX);
          final float position = (float) StrictGeomUtility.toExternalValue(localWidth);
          styleSheet.setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(position));
        } else {
          final long localWidth = Math.max(0, snapPosition - elementX);
          final float position = (float) StrictGeomUtility.toExternalValue(localWidth);
          styleSheet.setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(position));
        }
      } else {
        final Element parent = element.getParentSection();
        final CachedLayoutData parentData = ModelUtility.getCachedLayoutData(parent);

        final long parentBase = parentData.getWidth();
        if (parentBase > 0) {
          // relative position; resolve the percentage against the height of the parent.
          final long snapPosition =
              horizontalSnapModel.getNearestSnapPosition(targetX2, element.getObjectID());
          if (Math.abs(snapPosition - targetX2) > snapThreshold) {
            final long localWidth = Math.max(0, targetX2 - elementX);
            // strict geometry: all values are multiplied by 1000
            // percentages in the engine are represented by floats betwen 0 and 100.
            final long percentage =
                StrictGeomUtility.toInternalValue(localWidth * 100 / parentBase);
            styleSheet.setStyleProperty(
                ElementStyleKeys.MIN_WIDTH,
                new Float(StrictGeomUtility.toExternalValue(-percentage)));
          } else {
            final long localWidth = Math.max(0, snapPosition - elementX);
            // strict geometry: all values are multiplied by 1000
            // percentages in the engine are represented by floats betwen 0 and 100.
            final long percentage =
                StrictGeomUtility.toInternalValue(localWidth * 100 / parentBase);
            styleSheet.setStyleProperty(
                ElementStyleKeys.MIN_WIDTH,
                new Float(StrictGeomUtility.toExternalValue(-percentage)));
          }
        }
      }

      element.notifyNodePropertiesChanged();
    }
  }