All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.phloc.css.decl.CSSMediaQuery Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2006-2014 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phloc.css.decl;

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

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;

import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.equals.EqualsUtils;
import com.phloc.commons.hash.HashCodeGenerator;
import com.phloc.commons.state.EChange;
import com.phloc.commons.string.ToStringGenerator;
import com.phloc.css.CSSSourceLocation;
import com.phloc.css.ICSSSourceLocationAware;
import com.phloc.css.ICSSWriteable;
import com.phloc.css.ICSSWriterSettings;

/**
 * Represents a single media query
 * 
 * @author Philip Helger
 */
@NotThreadSafe
public class CSSMediaQuery implements ICSSWriteable, ICSSSourceLocationAware
{
  /**
   * A global modifier that can be used in front of a single CSS media query.
   * 
   * @author Philip Helger
   */
  public static enum EModifier
  {
    NONE (""),
    NOT ("not "),
    ONLY ("only ");

    private final String m_sText;

    private EModifier (@Nonnull final String sText)
    {
      m_sText = sText;
    }

    @Nonnull
    public String getCSSText ()
    {
      return m_sText;
    }
  }

  private final EModifier m_eModifier;
  private final String m_sMedium;
  private final List  m_aMediaExpressions = new ArrayList  ();
  private CSSSourceLocation m_aSourceLocation;

  /**
   * Constructor without a modifier. This implicitly uses the modifier
   * {@link EModifier#NONE}.
   * 
   * @param sMedium
   *        The medium to use. May be null.
   */
  public CSSMediaQuery (@Nullable final String sMedium)
  {
    this (EModifier.NONE, sMedium);
  }

  /**
   * Constructor
   * 
   * @param eModifier
   *        The modifier to use. May not be null.
   * @param sMedium
   *        The medium to use. May be null.
   */
  public CSSMediaQuery (@Nonnull final EModifier eModifier, @Nullable final String sMedium)
  {
    ValueEnforcer.notNull (eModifier, "Modifier");
    m_eModifier = eModifier;
    m_sMedium = sMedium;
  }

  /**
   * @return The media query modifier that was used. Never null.
   */
  @Nonnull
  public EModifier getModifier ()
  {
    return m_eModifier;
  }

  /**
   * @return true if the modifier is {@link EModifier#NOT}.
   * @see #getModifier()
   */
  public boolean isNot ()
  {
    return m_eModifier == EModifier.NOT;
  }

  /**
   * @return true if the modifier is {@link EModifier#ONLY}.
   * @see #getModifier()
   */
  public boolean isOnly ()
  {
    return m_eModifier == EModifier.ONLY;
  }

  /**
   * @return The medium passed in the constructor.
   */
  @Nullable
  public String getMedium ()
  {
    return m_sMedium;
  }

  /**
   * @return true if at least a single media expression is present.
   */
  public boolean hasMediaExpressions ()
  {
    return !m_aMediaExpressions.isEmpty ();
  }

  /**
   * @return The number of contained media expressions. Always ≥ 0.
   */
  @Nonnegative
  public int getMediaExpressionCount ()
  {
    return m_aMediaExpressions.size ();
  }

  /**
   * Append a media expression to the list.
   * 
   * @param aMediaExpression
   *        The media expression to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CSSMediaQuery addMediaExpression (@Nonnull final CSSMediaExpression aMediaExpression)
  {
    ValueEnforcer.notNull (aMediaExpression, "MediaExpression");

    m_aMediaExpressions.add (aMediaExpression);
    return this;
  }

  /**
   * Add a media expression to the list at the specified index.
   * 
   * @param nIndex
   *        The index where the media expression should be added. Must be ≥
   *        0.
   * @param aMediaExpression
   *        The media expression to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CSSMediaQuery addMediaExpression (@Nonnegative final int nIndex,
                                           @Nonnull final CSSMediaExpression aMediaExpression)
  {
    ValueEnforcer.isGE0 (nIndex, "Index");
    ValueEnforcer.notNull (aMediaExpression, "MediaExpression");

    if (nIndex >= getMediaExpressionCount ())
      m_aMediaExpressions.add (aMediaExpression);
    else
      m_aMediaExpressions.add (nIndex, aMediaExpression);
    return this;
  }

  /**
   * Remove the specified media expression.
   * 
   * @param aMediaExpression
   *        The media expression to be removed. May be null.
   * @return {@link EChange#CHANGED} if removal succeeded,
   *         {@link EChange#UNCHANGED} otherwise.
   */
  @Nonnull
  public EChange removeMediaExpression (@Nullable final CSSMediaExpression aMediaExpression)
  {
    return EChange.valueOf (m_aMediaExpressions.remove (aMediaExpression));
  }

  /**
   * Remove the media expression at the specified index.
   * 
   * @param nExpressionIndex
   *        The index of the media expression to be removed.
   * @return {@link EChange#CHANGED} if removal succeeded,
   *         {@link EChange#UNCHANGED} otherwise.
   */
  @Nonnull
  public EChange removeMediaExpression (final int nExpressionIndex)
  {
    if (nExpressionIndex < 0 || nExpressionIndex >= m_aMediaExpressions.size ())
      return EChange.UNCHANGED;
    return EChange.valueOf (m_aMediaExpressions.remove (nExpressionIndex) != null);
  }

  /**
   * Remove all media expressions.
   * 
   * @return {@link EChange#CHANGED} if any media expression was removed,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   * @since 3.7.3
   */
  @Nonnull
  public EChange removeAllMediaExpressions ()
  {
    if (m_aMediaExpressions.isEmpty ())
      return EChange.UNCHANGED;
    m_aMediaExpressions.clear ();
    return EChange.CHANGED;
  }

  /**
   * Get the media expression at the specified index.
   * 
   * @param nExpressionIndex
   *        The index to be retrieved.
   * @return null if the index is < 0 or too large.
   */
  @Nullable
  public CSSMediaExpression getMediaExpression (@Nonnegative final int nExpressionIndex)
  {
    if (nExpressionIndex < 0 || nExpressionIndex >= m_aMediaExpressions.size ())
      return null;
    return m_aMediaExpressions.get (nExpressionIndex);
  }

  /**
   * @return A copy of all media expression. Never null but maybe
   *         empty.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllMediaExpressions ()
  {
    return ContainerHelper.newList (m_aMediaExpressions);
  }

  @Nonnull
  @Nonempty
  public String getAsCSSString (@Nonnull final ICSSWriterSettings aSettings, @Nonnegative final int nIndentLevel)
  {
    final StringBuilder aSB = new StringBuilder ();

    // The modifier already contains a trailing space if necessary!
    aSB.append (m_eModifier.getCSSText ());

    boolean bIsFirstExpression = true;
    if (m_sMedium != null)
    {
      // Medium is optional
      aSB.append (m_sMedium);
      bIsFirstExpression = false;
    }

    if (!m_aMediaExpressions.isEmpty ())
    {
      for (final CSSMediaExpression aMediaExpression : m_aMediaExpressions)
      {
        if (bIsFirstExpression)
          bIsFirstExpression = false;
        else
        {
          // The leading blank is required in case this is the first expression
          // after a medium declaration ("projectorand" instead of
          // "projector and")!
          // The trailing blank is required, because otherwise it is considered
          // a function ("and(")!
          aSB.append (" and ");
        }
        aSB.append (aMediaExpression.getAsCSSString (aSettings, nIndentLevel));
      }
    }

    return aSB.toString ();
  }

  public void setSourceLocation (@Nullable final CSSSourceLocation aSourceLocation)
  {
    m_aSourceLocation = aSourceLocation;
  }

  @Nullable
  public CSSSourceLocation getSourceLocation ()
  {
    return m_aSourceLocation;
  }

  @Override
  public boolean equals (final Object o)
  {
    if (o == this)
      return true;
    if (o == null || !getClass ().equals (o.getClass ()))
      return false;
    final CSSMediaQuery rhs = (CSSMediaQuery) o;
    return m_eModifier.equals (rhs.m_eModifier) &&
           EqualsUtils.equals (m_sMedium, rhs.m_sMedium) &&
           m_aMediaExpressions.equals (rhs.m_aMediaExpressions);
  }

  @Override
  public int hashCode ()
  {
    return new HashCodeGenerator (this).append (m_eModifier)
                                       .append (m_sMedium)
                                       .append (m_aMediaExpressions)
                                       .getHashCode ();
  }

  @Override
  public String toString ()
  {
    return new ToStringGenerator (this).append ("modifier", m_eModifier)
                                       .append ("medium", m_sMedium)
                                       .append ("expressions", m_aMediaExpressions)
                                       .appendIfNotNull ("sourceLocation", m_aSourceLocation)
                                       .toString ();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy