blob: 50778e2f13f7d9ec70cd770b6a503b46c3c11bcc [file] [log] [blame]
/*
* 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();
}
}