/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * 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.android.ide.eclipse.adt.internal.editors.layout.configuration; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.resources.NightMode; import com.android.resources.UiMode; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.devices.Device; import com.android.sdklib.devices.State; import com.google.common.base.Objects; /** * An {@linkplain NestedConfiguration} is a {@link Configuration} which inherits * all of its values from a different configuration, except for one or more * attributes where it overrides a custom value. * <p> * Unlike a {@link VaryingConfiguration}, a {@linkplain NestedConfiguration} * will always return the same overridden value, regardless of the inherited * value. * <p> * For example, an {@linkplain NestedConfiguration} may fix the locale to always * be "en", but otherwise inherit everything else. */ public class NestedConfiguration extends Configuration { /** The configuration we are inheriting non-overridden values from */ protected Configuration mParent; /** Bitmask of attributes to be overridden in this configuration */ private int mOverride; /** * Constructs a new {@linkplain NestedConfiguration}. * Construct via * * @param chooser the associated chooser * @param configuration the configuration to inherit from */ protected NestedConfiguration( @NonNull ConfigurationChooser chooser, @NonNull Configuration configuration) { super(chooser); mParent = configuration; mFullConfig.set(mParent.mFullConfig); if (mParent.getEditedConfig() != null) { mEditedConfig = new FolderConfiguration(); mEditedConfig.set(mParent.mEditedConfig); } } /** * Returns the override flags for this configuration. Corresponds to * the {@code CFG_} flags in {@link ConfigurationClient}. * * @return the bitmask */ public int getOverrideFlags() { return mOverride; } /** * Creates a new {@linkplain NestedConfiguration} that has the same overriding * attributes as the given other {@linkplain NestedConfiguration}, and gets * its values from the given {@linkplain Configuration}. * * @param other the configuration to copy overrides from * @param values the configuration to copy values from * @param parent the parent to tie the configuration to for inheriting values * @return a new configuration */ @NonNull public static NestedConfiguration create( @NonNull NestedConfiguration other, @NonNull Configuration values, @NonNull Configuration parent) { NestedConfiguration configuration = new NestedConfiguration(other.mConfigChooser, parent); initFrom(configuration, other, values, true /*sync*/); return configuration; } /** * Initializes a new {@linkplain NestedConfiguration} with the overriding * attributes as the given other {@linkplain NestedConfiguration}, and gets * its values from the given {@linkplain Configuration}. * * @param configuration the configuration to initialize * @param other the configuration to copy overrides from * @param values the configuration to copy values from * @param sync if true, sync the folder configuration from */ protected static void initFrom(NestedConfiguration configuration, NestedConfiguration other, Configuration values, boolean sync) { configuration.mOverride = other.mOverride; configuration.setDisplayName(values.getDisplayName()); configuration.setActivity(values.getActivity()); if (configuration.isOverridingLocale()) { configuration.setLocale(values.getLocale(), true); } if (configuration.isOverridingTarget()) { configuration.setTarget(values.getTarget(), true); } if (configuration.isOverridingDevice()) { configuration.setDevice(values.getDevice(), true); } if (configuration.isOverridingDeviceState()) { configuration.setDeviceState(values.getDeviceState(), true); } if (configuration.isOverridingNightMode()) { configuration.setNightMode(values.getNightMode(), true); } if (configuration.isOverridingUiMode()) { configuration.setUiMode(values.getUiMode(), true); } if (sync) { configuration.syncFolderConfig(); } } /** * Sets the parent configuration that this configuration is inheriting from. * * @param parent the parent configuration */ public void setParent(@NonNull Configuration parent) { mParent = parent; } /** * Creates a new {@linkplain Configuration} which inherits values from the * given parent {@linkplain Configuration}, possibly overriding some as * well. * * @param chooser the associated chooser * @param parent the configuration to inherit values from * @return a new configuration */ @NonNull public static NestedConfiguration create(@NonNull ConfigurationChooser chooser, @NonNull Configuration parent) { return new NestedConfiguration(chooser, parent); } @Override @Nullable public String getTheme() { // Never overridden: this is a static attribute of a layout, not something which // varies by configuration or at runtime return mParent.getTheme(); } @Override public void setTheme(String theme) { // Never overridden mParent.setTheme(theme); } /** * Sets whether the locale should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideLocale(boolean override) { mOverride |= CFG_LOCALE; } /** * Returns true if the locale is overridden * * @return true if the locale is overridden */ public final boolean isOverridingLocale() { return (mOverride & CFG_LOCALE) != 0; } @Override @NonNull public Locale getLocale() { if (isOverridingLocale()) { return super.getLocale(); } else { return mParent.getLocale(); } } @Override public void setLocale(@NonNull Locale locale, boolean skipSync) { if (isOverridingLocale()) { super.setLocale(locale, skipSync); } else { mParent.setLocale(locale, skipSync); } } /** * Sets whether the rendering target should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideTarget(boolean override) { mOverride |= CFG_TARGET; } /** * Returns true if the target is overridden * * @return true if the target is overridden */ public final boolean isOverridingTarget() { return (mOverride & CFG_TARGET) != 0; } @Override @Nullable public IAndroidTarget getTarget() { if (isOverridingTarget()) { return super.getTarget(); } else { return mParent.getTarget(); } } @Override public void setTarget(IAndroidTarget target, boolean skipSync) { if (isOverridingTarget()) { super.setTarget(target, skipSync); } else { mParent.setTarget(target, skipSync); } } /** * Sets whether the device should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideDevice(boolean override) { mOverride |= CFG_DEVICE; } /** * Returns true if the device is overridden * * @return true if the device is overridden */ public final boolean isOverridingDevice() { return (mOverride & CFG_DEVICE) != 0; } @Override @Nullable public Device getDevice() { if (isOverridingDevice()) { return super.getDevice(); } else { return mParent.getDevice(); } } @Override public void setDevice(Device device, boolean skipSync) { if (isOverridingDevice()) { super.setDevice(device, skipSync); } else { mParent.setDevice(device, skipSync); } } /** * Sets whether the device state should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideDeviceState(boolean override) { mOverride |= CFG_DEVICE_STATE; } /** * Returns true if the device state is overridden * * @return true if the device state is overridden */ public final boolean isOverridingDeviceState() { return (mOverride & CFG_DEVICE_STATE) != 0; } @Override @Nullable public State getDeviceState() { if (isOverridingDeviceState()) { return super.getDeviceState(); } else { State state = mParent.getDeviceState(); if (isOverridingDevice()) { // If the device differs, I need to look up a suitable equivalent state // on our device if (state != null) { Device device = super.getDevice(); if (device != null) { return device.getState(state.getName()); } } } return state; } } @Override public void setDeviceState(State state, boolean skipSync) { if (isOverridingDeviceState()) { super.setDeviceState(state, skipSync); } else { if (isOverridingDevice()) { Device device = super.getDevice(); if (device != null) { State equivalentState = device.getState(state.getName()); if (equivalentState != null) { state = equivalentState; } } } mParent.setDeviceState(state, skipSync); } } /** * Sets whether the night mode should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideNightMode(boolean override) { mOverride |= CFG_NIGHT_MODE; } /** * Returns true if the night mode is overridden * * @return true if the night mode is overridden */ public final boolean isOverridingNightMode() { return (mOverride & CFG_NIGHT_MODE) != 0; } @Override @NonNull public NightMode getNightMode() { if (isOverridingNightMode()) { return super.getNightMode(); } else { return mParent.getNightMode(); } } @Override public void setNightMode(@NonNull NightMode night, boolean skipSync) { if (isOverridingNightMode()) { super.setNightMode(night, skipSync); } else { mParent.setNightMode(night, skipSync); } } /** * Sets whether the UI mode should be overridden by this configuration * * @param override if true, override the inherited value */ public void setOverrideUiMode(boolean override) { mOverride |= CFG_UI_MODE; } /** * Returns true if the UI mode is overridden * * @return true if the UI mode is overridden */ public final boolean isOverridingUiMode() { return (mOverride & CFG_UI_MODE) != 0; } @Override @NonNull public UiMode getUiMode() { if (isOverridingUiMode()) { return super.getUiMode(); } else { return mParent.getUiMode(); } } @Override public void setUiMode(@NonNull UiMode uiMode, boolean skipSync) { if (isOverridingUiMode()) { super.setUiMode(uiMode, skipSync); } else { mParent.setUiMode(uiMode, skipSync); } } /** * Returns the configuration this {@linkplain NestedConfiguration} is * inheriting from * * @return the configuration this configuration is inheriting from */ @NonNull public Configuration getParent() { return mParent; } @Override @Nullable public String getActivity() { return mParent.getActivity(); } @Override public void setActivity(String activity) { super.setActivity(activity); } /** * Returns a computed display name (ignoring the value stored by * {@link #setDisplayName(String)}) by looking at the override flags * and picking a suitable name. * * @return a suitable display name */ @Nullable public String computeDisplayName() { return computeDisplayName(mOverride, this); } /** * Computes a display name for the given configuration, using the given * override flags (which correspond to the {@code CFG_} constants in * {@link ConfigurationClient} * * @param flags the override bitmask * @param configuration the configuration to fetch values from * @return a suitable display name */ @Nullable public static String computeDisplayName(int flags, @NonNull Configuration configuration) { if ((flags & CFG_LOCALE) != 0) { return ConfigurationChooser.getLocaleLabel(configuration.mConfigChooser, configuration.getLocale(), false); } if ((flags & CFG_TARGET) != 0) { return ConfigurationChooser.getRenderingTargetLabel(configuration.getTarget(), false); } if ((flags & CFG_DEVICE) != 0) { return ConfigurationChooser.getDeviceLabel(configuration.getDevice(), true); } if ((flags & CFG_DEVICE_STATE) != 0) { State deviceState = configuration.getDeviceState(); if (deviceState != null) { return deviceState.getName(); } } if ((flags & CFG_NIGHT_MODE) != 0) { return configuration.getNightMode().getLongDisplayValue(); } if ((flags & CFG_UI_MODE) != 0) { configuration.getUiMode().getLongDisplayValue(); } return null; } @Override public String toString() { return Objects.toStringHelper(this.getClass()) .add("parent", mParent.getDisplayName()) //$NON-NLS-1$ .add("display", getDisplayName()) //$NON-NLS-1$ .add("overrideLocale", isOverridingLocale()) //$NON-NLS-1$ .add("overrideTarget", isOverridingTarget()) //$NON-NLS-1$ .add("overrideDevice", isOverridingDevice()) //$NON-NLS-1$ .add("overrideDeviceState", isOverridingDeviceState()) //$NON-NLS-1$ .add("persistent", toPersistentString()) //$NON-NLS-1$ .toString(); } }