| /* |
| * 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(); |
| } |
| } |