/******************************************************************************* * Copyright 2012-present Pixate, Inc. * * 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.pixate.freestyle.styling.selectors; import java.util.ArrayList; import java.util.List; import com.pixate.freestyle.styling.PXStyleUtils; import com.pixate.freestyle.styling.PXStyleUtils.PXStyleableChildrenInfo; import com.pixate.freestyle.styling.selectors.PXSpecificity.PXSpecificityType; import com.pixate.freestyle.util.CollectionUtil; import com.pixate.freestyle.util.PXLog; /** * A PXPseudoClassFunction is used to select styleables based on their positions * or pattern of positions from the start or end of their list of siblings */ public class PXPseudoClassFunction extends PXSelector { /** * The PXPseudoClassFunctionType enumeration specifies what nth-child * function should be applied */ public enum PXPseudoClassFunctionType { NTH_CHILD, NTH_LAST_CHILD, NTH_OF_TYPE, NTH_LAST_OF_TYPE }; private PXPseudoClassFunctionType functionType; private int modulus; private int remainder; /** * Initialize a newly allocation PXPseudoClassFunction * * @param type The nth-child operator type * @param modulus The modulus of the nth-child operation * @param remainder The remainder of the nth-child operation */ public PXPseudoClassFunction(PXPseudoClassFunctionType type, int modulus, int remainder) { super(PXSpecificityType.CLASS_OR_ATTRIBUTE); this.functionType = type; this.modulus = modulus; this.remainder = remainder; } public boolean matches(Object element) { boolean result = false; PXStyleableChildrenInfo info = PXStyleUtils.getChildrenInfoForStyleable(element); if (modulus != 0 || remainder != 0) { switch (functionType) { case NTH_LAST_CHILD: info.childrenIndex = info.childrenCount - info.childrenIndex + 1; // fall through case NTH_CHILD: { if (modulus == 1) { result = (info.childrenIndex == remainder); } else { int diff = info.childrenIndex - remainder; int diffMod = (modulus != 0) ? diff % modulus : diff; if ((diff <= 0 && modulus < 0) || (diff >= 0 && modulus > 0)) { result = (diffMod == 0); } } break; } case NTH_LAST_OF_TYPE: info.childrenOfTypeIndex = info.childrenOfTypeCount - info.childrenOfTypeIndex + 1; // fall through case NTH_OF_TYPE: { if (modulus == 1) { result = (info.childrenOfTypeIndex == remainder); } else { int diff = info.childrenOfTypeIndex - remainder; int diffMod = (modulus != 0) ? diff % modulus : diff; if ((diff <= 0 && modulus < 0) || (diff >= 0 && modulus > 0)) { result = (diffMod == 0); } } break; } } } if (PXLog.isLogging()) { if (result) { PXLog.v(PXPseudoClassFunction.class.getSimpleName(), "%s matched %s", toString(), PXStyleUtils.getDescriptionForStyleable(element)); } else { PXLog.v(PXPseudoClassFunction.class.getSimpleName(), "%s did not match %s", toString(), PXStyleUtils.getDescriptionForStyleable(element)); } } return result; } /** * Returns the type of nth-child operation that this selector will perform * during matching */ public PXPseudoClassFunctionType getFunctionType() { return functionType; } /** * Returns the modulus. In the expression 'an + b', the modulus corresponds * to the 'n' value */ public int getModulus() { return modulus; } /** * Returns the remainder. In the expression 'an + b', the remainder * corresponds to the 'b' value */ public int getRemainder() { return remainder; } @Override public String toString() { List<String> parts = new ArrayList<String>(); switch (functionType) { case NTH_CHILD: parts.add(":nth-child("); break; case NTH_LAST_CHILD: parts.add(":nth-last-child("); break; case NTH_OF_TYPE: parts.add(":nth-of-type("); break; case NTH_LAST_OF_TYPE: parts.add(":nth-last-of-type("); break; } if (modulus == 0) { parts.add(String.format("%d", remainder)); } else if (remainder == 0) { parts.add(String.format("%dn", modulus)); } else { parts.add(String.format("%dn+%d", modulus, remainder)); } parts.add(")"); return CollectionUtil.toString(parts, ""); } }