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

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

There is a newer version: 3.7.7
Show 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.io.Serializable;
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.annotations.ReturnsMutableCopy;
import com.phloc.commons.collections.ContainerHelper;
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;

/**
 * This is the main object for a parsed CSS declaration. It has special handling
 * for import and namespace rules, as these rules must always be on the
 * beginning of a file. All other rules (all implementing
 * {@link ICSSTopLevelRule}) are maintained in a combined list.
 * 
 * @author Philip Helger
 */
@NotThreadSafe
public class CascadingStyleSheet implements ICSSSourceLocationAware, Serializable
{
  private final List  m_aImportRules = new ArrayList  ();
  private final List  m_aNamespaceRules = new ArrayList  ();
  private final List  m_aRules = new ArrayList  ();
  private CSSSourceLocation m_aSourceLocation;

  public CascadingStyleSheet ()
  {}

  /**
   * @return true if at least one @import rule is
   *         present, false otherwise.
   */
  public boolean hasImportRules ()
  {
    return !m_aImportRules.isEmpty ();
  }

  /**
   * @return The number of contained @import rules. Always ≥ 0.
   */
  @Nonnegative
  public int getImportRuleCount ()
  {
    return m_aImportRules.size ();
  }

  /**
   * Get the @import rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getImportRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSImportRule getImportRuleAtIndex (@Nonnegative final int nIndex)
  {
    return ContainerHelper.getSafe (m_aImportRules, nIndex);
  }

  /**
   * Add a new @import rule at the end of the @import
   * rule list.
   * 
   * @param aImportRule
   *        The import rule to add. May not be null.
   * @return this
   */
  @Nonnull
  public CascadingStyleSheet addImportRule (@Nonnull final CSSImportRule aImportRule)
  {
    if (aImportRule == null)
      throw new NullPointerException ("ImportRule");

    m_aImportRules.add (aImportRule);
    return this;
  }

  /**
   * Add a new @import rule at a specified index of the
   * @import rule list.
   * 
   * @param nIndex
   *        The index where the rule should be added. Must be ≥ 0.
   * @param aImportRule
   *        The import rule to add. May not be null.
   * @return this
   * @throws ArrayIndexOutOfBoundsException
   *         if the index is invalid
   */
  @Nonnull
  public CascadingStyleSheet addImportRule (@Nonnegative final int nIndex, @Nonnull final CSSImportRule aImportRule)
  {
    if (nIndex < 0)
      throw new IllegalArgumentException ("Index too small: " + nIndex);
    if (aImportRule == null)
      throw new NullPointerException ("ImportRule");

    if (nIndex >= getImportRuleCount ())
      m_aImportRules.add (aImportRule);
    else
      m_aImportRules.add (nIndex, aImportRule);
    return this;
  }

  /**
   * Remove the specified @import rule.
   * 
   * @param aImportRule
   *        The import rule to be removed. May be null.
   * @return {@link EChange#CHANGED} if removal was successful,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   */
  @Nonnull
  public EChange removeImportRule (@Nullable final CSSImportRule aImportRule)
  {
    return EChange.valueOf (m_aImportRules.remove (aImportRule));
  }

  /**
   * Remove the @import rule at the specified index.
   * 
   * @param nImportRuleIndex
   *        The index to be removed. Should be ≥ 0.
   * @return {@link EChange#CHANGED} if removal was successful,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   */
  @Nonnull
  public EChange removeImportRule (@Nonnegative final int nImportRuleIndex)
  {
    if (nImportRuleIndex < 0 || nImportRuleIndex >= m_aImportRules.size ())
      return EChange.UNCHANGED;
    m_aImportRules.remove (nImportRuleIndex);
    return EChange.CHANGED;
  }

  /**
   * Remove all @import rules.
   * 
   * @return {@link EChange#CHANGED} if any rule was removed,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   * @since 3.7.3
   */
  @Nonnull
  public EChange removeAllImportRules ()
  {
    if (m_aImportRules.isEmpty ())
      return EChange.UNCHANGED;
    m_aImportRules.clear ();
    return EChange.CHANGED;
  }

  /**
   * @return A copy of all contained @import rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllImportRules ()
  {
    return ContainerHelper.newList (m_aImportRules);
  }

  /**
   * @return true if at least one @namespace rule is
   *         present, false otherwise.
   */
  public boolean hasNamespaceRules ()
  {
    return !m_aNamespaceRules.isEmpty ();
  }

  /**
   * @return The number of contained @namespace rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getNamespaceRuleCount ()
  {
    return m_aNamespaceRules.size ();
  }

  /**
   * Get the @namespace rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getNamespaceRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSNamespaceRule getNamespaceRuleAtIndex (@Nonnegative final int nIndex)
  {
    return ContainerHelper.getSafe (m_aNamespaceRules, nIndex);
  }

  /**
   * Add a new @namespace rule at the end of the
   * @namespace rule list.
   * 
   * @param aNamespaceRule
   *        The namespace rule to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CascadingStyleSheet addNamespaceRule (@Nonnull final CSSNamespaceRule aNamespaceRule)
  {
    if (aNamespaceRule == null)
      throw new NullPointerException ("NamespaceRule");

    m_aNamespaceRules.add (aNamespaceRule);
    return this;
  }

  /**
   * Add a new @namespace rule at the specified index of the
   * @namespace rule list.
   * 
   * @param nIndex
   *        The index where the rule should be added. Must be ≥ 0.
   * @param aNamespaceRule
   *        The namespace rule to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CascadingStyleSheet addNamespaceRule (@Nonnegative final int nIndex,
                                               @Nonnull final CSSNamespaceRule aNamespaceRule)
  {
    if (nIndex < 0)
      throw new IllegalArgumentException ("Index too small: " + nIndex);
    if (aNamespaceRule == null)
      throw new NullPointerException ("NamespaceRule");

    if (nIndex >= getNamespaceRuleCount ())
      m_aNamespaceRules.add (aNamespaceRule);
    else
      m_aNamespaceRules.add (nIndex, aNamespaceRule);
    return this;
  }

  /**
   * Remove the specified @namespace rule.
   * 
   * @param aNamespaceRule
   *        The namespace rule to be removed. May be null.
   * @return {@link EChange#CHANGED} if the namespace rule was successfully
   *         removed, {@link EChange#UNCHANGED} otherwise. Never
   *         null.
   */
  @Nonnull
  public EChange removeNamespaceRule (@Nullable final CSSNamespaceRule aNamespaceRule)
  {
    return EChange.valueOf (m_aNamespaceRules.remove (aNamespaceRule));
  }

  /**
   * Remove the @namespace rule at the specified index.
   * 
   * @param nNamespaceRuleIndex
   *        The index to be removed. Should be ≥ 0.
   * @return {@link EChange#CHANGED} if the namespace rule was successfully
   *         removed, {@link EChange#UNCHANGED} otherwise. Never
   *         null.
   */
  @Nonnull
  public EChange removeNamespaceRule (@Nonnegative final int nNamespaceRuleIndex)
  {
    if (nNamespaceRuleIndex < 0 || nNamespaceRuleIndex >= m_aNamespaceRules.size ())
      return EChange.UNCHANGED;
    m_aNamespaceRules.remove (nNamespaceRuleIndex);
    return EChange.CHANGED;
  }

  /**
   * Remove all @namespace rules.
   * 
   * @return {@link EChange#CHANGED} if any rule was removed,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   * @since 3.7.3
   */
  @Nonnull
  public EChange removeAllNamespaceRules ()
  {
    if (m_aNamespaceRules.isEmpty ())
      return EChange.UNCHANGED;
    m_aNamespaceRules.clear ();
    return EChange.CHANGED;
  }

  /**
   * @return A copy of all @namespace rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllNamespaceRules ()
  {
    return ContainerHelper.newList (m_aNamespaceRules);
  }

  /**
   * Check if any top-level rule. This method only considers top-level rules and
   * not @import and @namespace rules!
   * 
   * @return true if at least one top-level rule is present,
   *         false if otherwise.
   */
  public boolean hasRules ()
  {
    return !m_aRules.isEmpty ();
  }

  /**
   * Get the number of total contained top-level rules. This method only
   * considers top-level rules and not @import and
   * @namespace rules!
   * 
   * @return The number of total contained top-level rules. Always ≥ 0.
   */
  @Nonnegative
  public int getRuleCount ()
  {
    return m_aRules.size ();
  }

  /**
   * Get the top-level rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public ICSSTopLevelRule getRuleAtIndex (@Nonnegative final int nIndex)
  {
    return ContainerHelper.getSafe (m_aRules, nIndex);
  }

  /**
   * Add a new top-level rule at the end. This method only considers top-level
   * rules and not @import and @namespace rules!
   * 
   * @param aRule
   *        The rule to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CascadingStyleSheet addRule (@Nonnull final ICSSTopLevelRule aRule)
  {
    if (aRule == null)
      throw new NullPointerException ("styleRule");

    m_aRules.add (aRule);
    return this;
  }

  /**
   * Add a new top-level rule at the specified index. This method only considers
   * top-level rules and not @import and @namespace
   * rules!
   * 
   * @param nIndex
   *        The index where the top-level rule should be added. Must be ≥ 0.
   * @param aRule
   *        The rule to be added. May not be null.
   * @return this
   */
  @Nonnull
  public CascadingStyleSheet addRule (@Nonnegative final int nIndex, @Nonnull final ICSSTopLevelRule aRule)
  {
    if (nIndex < 0)
      throw new IllegalArgumentException ("Index too small: " + nIndex);
    if (aRule == null)
      throw new NullPointerException ("styleRule");

    if (nIndex >= getRuleCount ())
      m_aRules.add (aRule);
    else
      m_aRules.add (nIndex, aRule);
    return this;
  }

  /**
   * Remove the specified top-level rule. This method only considers top-level
   * rules and not @import and @namespace rules!
   * 
   * @param aRule
   *        The rule to be removed. May be null.
   * @return {@link EChange#CHANGED} if the rule was successfully removed,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   */
  @Nonnull
  public EChange removeRule (@Nullable final ICSSTopLevelRule aRule)
  {
    return EChange.valueOf (m_aRules.remove (aRule));
  }

  /**
   * Remove the rule at the specified index. This method only considers
   * top-level rules and not @import and @namespace
   * rules!
   * 
   * @param nRuleIndex
   *        The index of the rule to be removed. Should be ≥ 0.
   * @return {@link EChange#CHANGED} if the rule at the specified index was
   *         successfully removed, {@link EChange#UNCHANGED} otherwise. Never
   *         null.
   */
  @Nonnull
  public EChange removeRule (@Nonnegative final int nRuleIndex)
  {
    if (nRuleIndex < 0 || nRuleIndex >= m_aRules.size ())
      return EChange.UNCHANGED;
    m_aRules.remove (nRuleIndex);
    return EChange.CHANGED;
  }

  /**
   * Remove all top-level rules.
   * 
   * @return {@link EChange#CHANGED} if any rule was removed,
   *         {@link EChange#UNCHANGED} otherwise. Never null.
   * @since 3.7.3
   */
  @Nonnull
  public EChange removeAllRules ()
  {
    if (m_aRules.isEmpty ())
      return EChange.UNCHANGED;
    m_aRules.clear ();
    return EChange.CHANGED;
  }

  /**
   * Get a copy of all contained top-level rules. This method only considers
   * top-level rules and not @import and @namespace
   * rules!
   * 
   * @return A copy of all contained top-level rules. Never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllRules ()
  {
    return ContainerHelper.newList (m_aRules);
  }

  /**
   * Check if at least one of the top-level rules is a style rule (implementing
   * {@link CSSStyleRule}).
   * 
   * @return true if at least one style rule is contained,
   *         false otherwise.
   */
  public boolean hasStyleRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSStyleRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are style rules (implementing
   * {@link CSSStyleRule}).
   * 
   * @return The number of contained style rules. Always ≥ 0.
   */
  @Nonnegative
  public int getStyleRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSStyleRule)
        ret++;
    return ret;
  }

  /**
   * Get the style rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getStyleRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSStyleRule getStyleRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSStyleRule)
        {
          if (nCurIndex == nIndex)
            return (CSSStyleRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are style rules (implementing
   * {@link CSSStyleRule}).
   * 
   * @return A copy of all contained style rules. Never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllStyleRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSStyleRule)
        ret.add ((CSSStyleRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a page rule (implementing
   * {@link CSSPageRule}).
   * 
   * @return true if at least one @page rule is
   *         contained, false otherwise.
   */
  public boolean hasPageRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSPageRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are page rules (implementing
   * {@link CSSPageRule}).
   * 
   * @return The number of contained @page rules. Always ≥ 0.
   */
  @Nonnegative
  public int getPageRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSPageRule)
        ret++;
    return ret;
  }

  /**
   * Get the @page rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getPageRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSPageRule getPageRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSPageRule)
        {
          if (nCurIndex == nIndex)
            return (CSSPageRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are page rules (implementing
   * {@link CSSPageRule}).
   * 
   * @return A copy of all contained @page rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllPageRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSPageRule)
        ret.add ((CSSPageRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a media rule (implementing
   * {@link CSSMediaRule}).
   * 
   * @return true if at least one @media rule is
   *         contained, false otherwise.
   */
  public boolean hasMediaRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSMediaRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are media rules (implementing
   * {@link CSSMediaRule}).
   * 
   * @return The number of contained @media rules. Always ≥ 0.
   */
  @Nonnegative
  public int getMediaRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSMediaRule)
        ret++;
    return ret;
  }

  /**
   * Get the @media rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getMediaRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSMediaRule getMediaRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSMediaRule)
        {
          if (nCurIndex == nIndex)
            return (CSSMediaRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are media rules (implementing
   * {@link CSSMediaRule}).
   * 
   * @return A copy of all contained @media rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllMediaRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSMediaRule)
        ret.add ((CSSMediaRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a font-face rule
   * (implementing {@link CSSFontFaceRule}).
   * 
   * @return true if at least one @font-face rule is
   *         contained, false otherwise.
   */
  public boolean hasFontFaceRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSFontFaceRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are font-face rules (implementing
   * {@link CSSFontFaceRule}).
   * 
   * @return The number of contained @font-face rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getFontFaceRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSFontFaceRule)
        ret++;
    return ret;
  }

  /**
   * Get the @font-face rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getFontFaceRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSFontFaceRule getFontFaceRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSFontFaceRule)
        {
          if (nCurIndex == nIndex)
            return (CSSFontFaceRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are font-face rules (implementing
   * {@link CSSFontFaceRule}).
   * 
   * @return A copy of all contained @font-face rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllFontFaceRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSFontFaceRule)
        ret.add ((CSSFontFaceRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a keyframes rule
   * (implementing {@link CSSKeyframesRule}).
   * 
   * @return true if at least one @keyframes rule is
   *         contained, false otherwise.
   */
  public boolean hasKeyframesRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSKeyframesRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are keyframes rules (implementing
   * {@link CSSKeyframesRule}).
   * 
   * @return The number of contained @keyframes rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getKeyframesRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSKeyframesRule)
        ret++;
    return ret;
  }

  /**
   * Get the @keyframes rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getKeyframesRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSKeyframesRule getKeyframesRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSKeyframesRule)
        {
          if (nCurIndex == nIndex)
            return (CSSKeyframesRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are keyframes rules (implementing
   * {@link CSSKeyframesRule}).
   * 
   * @return A copy of all contained @keyframes rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllKeyframesRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSKeyframesRule)
        ret.add ((CSSKeyframesRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a viewport rule
   * (implementing {@link CSSViewportRule}).
   * 
   * @return true if at least one @viewport rule is
   *         contained, false otherwise.
   */
  public boolean hasViewportRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSViewportRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are viewport rules (implementing
   * {@link CSSViewportRule}).
   * 
   * @return The number of contained @viewport rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getViewportRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSViewportRule)
        ret++;
    return ret;
  }

  /**
   * Get the @viewport rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getViewportRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSViewportRule getViewportRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSViewportRule)
        {
          if (nCurIndex == nIndex)
            return (CSSViewportRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are viewport rules (implementing
   * {@link CSSViewportRule}).
   * 
   * @return A copy of all contained @viewport rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllViewportRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSViewportRule)
        ret.add ((CSSViewportRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is a supports rule
   * (implementing {@link CSSSupportsRule}).
   * 
   * @return true if at least one @supports rule is
   *         contained, false otherwise.
   */
  public boolean hasSupportsRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSSupportsRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are support rules (implementing
   * {@link CSSSupportsRule}).
   * 
   * @return The number of contained @supports rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getSupportsRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSSupportsRule)
        ret++;
    return ret;
  }

  /**
   * Get the @supports rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getSupportsRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSSupportsRule getSupportsRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSSupportsRule)
        {
          if (nCurIndex == nIndex)
            return (CSSSupportsRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are support rules (implementing
   * {@link CSSSupportsRule}).
   * 
   * @return A copy of all contained @supports rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllSupportsRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSSupportsRule)
        ret.add ((CSSSupportsRule) aTopLevelRule);
    return ret;
  }

  /**
   * Check if at least one of the top-level rules is an unknown rule
   * (implementing {@link CSSUnknownRule}).
   * 
   * @return true if at least one unknown @ rule is
   *         contained, false otherwise.
   */
  public boolean hasUnknownRules ()
  {
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSUnknownRule)
        return true;
    return false;
  }

  /**
   * Get the number of top-level rules that are unknown rules (implementing
   * {@link CSSUnknownRule}).
   * 
   * @return The number of contained unknown @ rules. Always ≥
   *         0.
   */
  @Nonnegative
  public int getUnknownRuleCount ()
  {
    int ret = 0;
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSUnknownRule)
        ret++;
    return ret;
  }

  /**
   * Get the unknown rule at the specified index.
   * 
   * @param nIndex
   *        The index to be resolved. Should be ≥ 0 and <
   *        {@link #getUnknownRuleCount()}.
   * @return null if an invalid index was specified.
   * @since 3.7.4
   */
  @Nullable
  public CSSUnknownRule getUnknownRuleAtIndex (@Nonnegative final int nIndex)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
        if (aTopLevelRule instanceof CSSUnknownRule)
        {
          if (nCurIndex == nIndex)
            return (CSSUnknownRule) aTopLevelRule;
          ++nCurIndex;
        }
    }
    return null;
  }

  /**
   * Get a list of all top-level rules that are unknown rules (implementing
   * {@link CSSUnknownRule}).
   * 
   * @return A copy of all contained unknown @ rules. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public List  getAllUnknownRules ()
  {
    final List  ret = new ArrayList  ();
    for (final ICSSTopLevelRule aTopLevelRule : m_aRules)
      if (aTopLevelRule instanceof CSSUnknownRule)
        ret.add ((CSSUnknownRule) aTopLevelRule);
    return ret;
  }

  /**
   * Set the source location of the object, determined while parsing.
   * 
   * @param aSourceLocation
   *        The source location to use. May be null.
   */
  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 CascadingStyleSheet rhs = (CascadingStyleSheet) o;
    return m_aImportRules.equals (rhs.m_aImportRules) &&
           m_aNamespaceRules.equals (rhs.m_aNamespaceRules) &&
           m_aRules.equals (rhs.m_aRules);
  }

  @Override
  public int hashCode ()
  {
    return new HashCodeGenerator (this).append (m_aImportRules)
                                       .append (m_aNamespaceRules)
                                       .append (m_aRules)
                                       .getHashCode ();
  }

  @Override
  public String toString ()
  {
    return new ToStringGenerator (this).append ("importRules", m_aImportRules)
                                       .append ("namespaceRules", m_aNamespaceRules)
                                       .append ("rules", m_aRules)
                                       .appendIfNotNull ("sourceLocation", m_aSourceLocation)
                                       .toString ();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy