Package ch.entwine.weblounge.common.impl.content.image

Source Code of ch.entwine.weblounge.common.impl.content.image.ImageStyleImpl$Context

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  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.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.common.impl.content.image;

import static ch.entwine.weblounge.common.site.ImageScalingMode.Box;
import static ch.entwine.weblounge.common.site.ImageScalingMode.Cover;
import static ch.entwine.weblounge.common.site.ImageScalingMode.Fill;
import static ch.entwine.weblounge.common.site.ImageScalingMode.Height;
import static ch.entwine.weblounge.common.site.ImageScalingMode.None;
import static ch.entwine.weblounge.common.site.ImageScalingMode.Width;

import ch.entwine.weblounge.common.content.image.ImageStyle;
import ch.entwine.weblounge.common.impl.content.GeneralComposeable;
import ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils;
import ch.entwine.weblounge.common.impl.util.xml.XPathHelper;
import ch.entwine.weblounge.common.impl.util.xml.XPathNamespaceContext;
import ch.entwine.weblounge.common.site.ImageScalingMode;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

/**
* The <code>ImageStyleImpl</code> class defines a presentation style for images
* of a certain size as well as the method to get from the original image
* version to scaled ones.
*/
public class ImageStyleImpl extends GeneralComposeable implements ImageStyle {

  /** Identifier for the global context */
  public static final String GLOBAL_CONTEXT = "all";

  /** the image width */
  protected int width = -1;

  /** the image height */
  protected int height = -1;

  /** the scaling mode */
  protected ImageScalingMode scalingMode = null;

  /** The styling context */
  protected List<Context> contexts = null;

  /**
   * Creates a new image style with the name as its identifier, width and
   * height, the indicated scaling behavior. If <code>composeable</code> is set
   * to <code>true</code>, the image style will be available to the user when it
   * comes to adding scaled images to a page.
   *
   * @param id
   *          the style identifier
   * @param width
   *          the image width
   * @param height
   *          the image height
   * @param scaling
   *          the scaling mode
   * @param composeable
   *          <code>true</code> if the image style is composeable
   * @param preview
   *          <code>true</code> if the image style is automatically created
   * @throws IllegalArgumentException
   *           if id parameter is blank
   * @throws IllegalArgumentException
   *           if width and height parameter are zero or negative
   */
  public ImageStyleImpl(String id, int width, int height,
      ImageScalingMode scaling, boolean composeable, boolean preview)
      throws IllegalArgumentException {
    if (StringUtils.isBlank(id))
      throw new IllegalArgumentException("Identifier cannot be null");
    this.identifier = id;
    this.width = width;
    this.height = height;
    this.scalingMode = scaling;
    this.composeable = composeable;
    switch (scaling) {
      case Box:
      case Cover:
      case Fill:
        if (width <= 0)
          throw new IllegalArgumentException("Image width (" + width + ") must be a positive, non-zero number");
        if (height <= 0)
          throw new IllegalArgumentException("Image height (" + height + ") must be a positive, non-zero number");
        break;
      case Width:
        if (width <= 0)
          throw new IllegalArgumentException("Image width (" + width + ") must be a positive, non-zero number");
        break;
      case Height:
        if (height <= 0)
          throw new IllegalArgumentException("Image height (" + height + ") must be a positive, non-zero number");
        break;
      case None:
        break;
      default:
        throw new IllegalArgumentException("Scaling mode '" + scaling.toString().toLowerCase() + "' is unsupported");
    }
  }

  /**
   * Creates a new composeable image style with width, height and a default
   * scaling mode of {@link ImageScalingMode#None}.
   *
   * @param id
   *          the style identifier
   * @param width
   *          the image width
   * @param height
   *          the image height
   */
  public ImageStyleImpl(String id, int width, int height) {
    this(id, width, height, None, true, false);
  }

  /**
   * Creates a new composeable image style.
   *
   * @param id
   *          the style identifier
   * @param mode
   *          the scaling mode
   */
  public ImageStyleImpl(String id, ImageScalingMode mode) {
    this(id, -1, -1, mode, true, false);
  }

  /**
   * Creates a new composeable image style.
   *
   * @param id
   *          the style identifier
   */
  public ImageStyleImpl(String id) {
    this(id, -1, -1, None, true, false);
  }

  /**
   * Adds a new context to this image style.
   *
   * @param type
   *          the context
   * @param preview
   *          <code>true</code> to create previews
   * @throws IllegalArgumentException
   *           if <code>type</code> is blank
   */
  public void addContext(String type, boolean preview)
      throws IllegalArgumentException {
    if (StringUtils.isBlank(type))
      throw new IllegalArgumentException("Type must not be blank");
    if (contexts == null)
      contexts = new ArrayList<Context>();
    if (GLOBAL_CONTEXT.equals(type))
      contexts.clear();
    contexts.add(new Context(type, preview));
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#getContexts()
   */
  @Override
  public List<String> getContexts() {
    if (contexts == null || contexts.isEmpty())
      return Collections.emptyList();
    if (GLOBAL_CONTEXT.equals(contexts.get(0).getResource()))
      return Collections.emptyList();
    List<String> result = new ArrayList<String>(contexts.size());
    for (Context ctx : contexts) {
      result.add(ctx.getResource());
    }
    return result;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#createPreview(java.lang.String)
   */
  @Override
  public boolean createPreview(String context) throws IllegalArgumentException {
    if (StringUtils.isBlank(context))
      throw new IllegalArgumentException("Context must not be blank");
    if (contexts == null || contexts.isEmpty())
      return false;
    if ("all".equals(contexts.get(0).getResource()))
      return contexts.get(0).createPreview();
    for (Context ctx : contexts) {
      if (context.equals(ctx.getResource()))
        return ctx.createPreview();
    }
    return false;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#scale(int, int)
   */
  public float scale(int width, int height) {
    float scaleX = 1.0f;
    float scaleY = 1.0f;
    float scale = 1.0f;
    switch (scalingMode) {
      case Box:
        scaleX = this.width / width;
        scaleY = this.height / height;
        if (scaleX < 1.0f || scaleY < 1.0f) {
          scale = Math.min(scaleX, scaleY);
        } else {
          scale = Math.max(scaleX, scaleY);
        }
        break;
      case Cover:
        scaleX = this.width / width;
        scaleY = this.height / height;
        if (scaleX > 1.0f || scaleY > 1.0f) {
          scale = Math.max(scaleX, scaleY);
        } else {
          scale = Math.min(scaleX, scaleY);
        }
        break;
      case Fill:
        // TODO: Implement
        break;
      case Height:
        if (height != this.height) {
          scale = this.height / height;
        }
        break;
      case Width:
        if (width != this.width) {
          scale = this.width / width;
        }
        break;
      default:
        scale = 1.0f;
        break;
    }
    return scale;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#setScalingMode(ch.entwine.weblounge.common.site.ImageScalingMode)
   */
  public void setScalingMode(ImageScalingMode mode) {
    this.scalingMode = mode;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#getScalingMode()
   */
  public ImageScalingMode getScalingMode() {
    return scalingMode;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#setHeight(int)
   */
  public void setHeight(int height) {
    this.height = height;
  }

  /**
   * Returns the image height.
   *
   * @return the image height
   */
  public int getHeight() {
    return height;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#setWidth(int)
   */
  public void setWidth(int width) {
    this.width = width;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#getWidth()
   */
  public int getWidth() {
    return width;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#hashCode()
   */
  @Override
  public int hashCode() {
    return super.hashCode();
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object o) {
    // This is to indicate that using the super implementation is sufficient
    return super.equals(o);
  }

  /**
   * Initializes this image style from an XML node that was generated using
   * {@link #toXml()}.
   * <p>
   * To speed things up, you might consider using the second signature that uses
   * an existing <code>XPath</code> instance instead of creating a new one.
   *
   * @param node
   *          the image style node
   * @throws IllegalStateException
   *           if the image style cannot be parsed
   * @see #fromXml(Node, XPath)
   * @see #toXml()
   */
  public static ImageStyleImpl fromXml(Node node) throws IllegalStateException {
    XPath xpath = XPathFactory.newInstance().newXPath();
    xpath.setNamespaceContext(new XPathNamespaceContext(true));
    return fromXml(node, xpath);
  }

  /**
   * Initializes this image style from an XML node that was generated using
   * {@link #toXml()}.
   *
   * @param node
   *          the image style node
   * @param xpath
   *          the xpath processor
   * @throws IllegalStateException
   *           if the image style cannot be parsed
   * @see #fromXml(Node)
   * @see #toXml()
   */
  public static ImageStyleImpl fromXml(Node node, XPath xpath)
      throws IllegalStateException {

    // Identifier
    String id = XPathHelper.valueOf(node, "@id", xpath);
    if (id == null)
      throw new IllegalStateException("Missing id in image style definition");

    // Width
    int width = -1;
    try {
      if (XPathHelper.valueOf(node, "m:width", xpath) != null)
        width = Integer.parseInt(XPathHelper.valueOf(node, "m:width", xpath));
    } catch (NumberFormatException e) {
      throw new IllegalStateException("Missing width in image style definition");
    }

    // Height
    int height = -1;
    try {
      if (XPathHelper.valueOf(node, "m:height", xpath) != null)
        height = Integer.parseInt(XPathHelper.valueOf(node, "m:height", xpath));
    } catch (NumberFormatException e) {
      throw new IllegalStateException("Missing height in image style definition");
    }

    // Composeable
    boolean composeable = ConfigurationUtils.isTrue(XPathHelper.valueOf(node, "@composeable", xpath), true);

    // Preview
    boolean preview = ConfigurationUtils.isTrue(XPathHelper.valueOf(node, "@preview", xpath), false);

    // Scaling mode
    String mode = XPathHelper.valueOf(node, "m:scalingmode", xpath);
    ImageScalingMode scalingMode = mode == null ? None : ImageScalingMode.parseString(mode);

    if (Width.equals(scalingMode) && width <= 0)
      throw new IllegalStateException("Width scaling needs positive width");
    if (Height.equals(scalingMode) && height <= 0)
      throw new IllegalStateException("Height scaling needs positive height");
    if (Box.equals(scalingMode) && (height <= 0 || width <= 0))
      throw new IllegalStateException("Box scaling needs positive width and height");
    if (Cover.equals(scalingMode) && (width <= 0 || height <= 0))
      throw new IllegalStateException("Cover scaling needs positive width and height");
    if (Fill.equals(scalingMode) && (width <= 0 || height <= 0))
      throw new IllegalStateException("Fill scaling needs positive width and height");

    // Create the image style
    ImageStyleImpl imageStyle = new ImageStyleImpl(id, width, height, scalingMode, composeable, preview);

    // Names
    String name = XPathHelper.valueOf(node, "m:name", xpath);
    imageStyle.setName(name);

    // Contexts
    NodeList contexts = XPathHelper.selectList(node, "m:context/m:resource", xpath);
    if (contexts != null) {
      for (int i = 0; i < contexts.getLength(); i++) {
        Node n = contexts.item(i);
        boolean createPreviews = ConfigurationUtils.isTrue(n.getAttributes().getNamedItem("preview"));
        String resource = n.getFirstChild().getNodeValue();
        imageStyle.addContext(resource, createPreviews);
      }
    }

    return imageStyle;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.image.ImageStyle#toXml()
   */
  public String toXml() {
    StringBuffer buf = new StringBuffer();
    buf.append("<imagestyle");

    // id
    buf.append(" id=\"").append(identifier).append("\"");

    // composeable
    buf.append(" composeable=\"").append(composeable).append("\"");

    buf.append(">");

    // name
    if (StringUtils.isNotBlank(name)) {
      buf.append("<name><![CDATA[");
      buf.append(name);
      buf.append("]]></name>");
    }

    // scaling mode
    buf.append("<scalingmode>");
    buf.append(scalingMode.toString().toLowerCase());
    buf.append("</scalingmode>");

    // width
    if (width > 0)
      buf.append("<width>").append(width).append("</width>");

    // height
    if (height > 0)
      buf.append("<height>").append(height).append("</height>");

    // contexts
    if (contexts != null) {
      buf.append("<context>");
      for (Context ctx : contexts) {
        buf.append("<resource");
        if (ctx.createPreview())
          buf.append(" preview=\"true\"");
        buf.append(">").append(ctx.getResource());
        buf.append("</resource>");
      }
      buf.append("</context>");
    }

    buf.append("</imagestyle>");
    return buf.toString();
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.language.LocalizableObject#toString()
   */
  @Override
  public String toString() {
    StringBuffer buf = new StringBuffer(identifier);
    buf.append(" [scaling=");
    buf.append(scalingMode.toString());
    if (width > 0) {
      buf.append(";width=");
      buf.append(width);
    }
    if (height > 0) {
      buf.append(";height=");
      buf.append(height);
    }
    buf.append("]");
    return buf.toString();
  }

  /**
   * The image style context.
   */
  private static final class Context {

    /** The resource type */
    private String resource = null;

    /** Whether to render previews for the resource */
    private boolean preview = false;

    /**
     * Creates a new context for the given resource and defines whether previews
     * should be created automatically for this resource.
     *
     * @param resource
     *          the resource
     * @param preview
     *          <code>true</code> to automatically render previews
     */
    public Context(String resource, boolean preview) {
      this.resource = resource;
      this.preview = preview;
    }

    /**
     * Returns the resource type.
     *
     * @return the resource
     */
    public String getResource() {
      return resource;
    }

    /**
     * Returns <code>true</code> if previews need to be created for the
     * resource.
     *
     * @return the preview the preview
     */
    public boolean createPreview() {
      return preview;
    }

  }

}
TOP

Related Classes of ch.entwine.weblounge.common.impl.content.image.ImageStyleImpl$Context

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.