aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ActivityMenuListener.java162
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java1091
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationChooser.java2096
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationClient.java129
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationDescription.java395
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMatcher.java843
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMenuListener.java290
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/DeviceMenuListener.java199
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManager.java215
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LayoutCreatorDialog.java149
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Locale.java184
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleMenuListener.java124
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java506
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/OrientationMenuAction.java180
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/SelectThemeAction.java50
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/TargetMenuListener.java126
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java318
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/VaryingConfiguration.java509
18 files changed, 0 insertions, 7566 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ActivityMenuListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ActivityMenuListener.java
deleted file mode 100644
index 36cd0fbbb..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ActivityMenuListener.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.jdt.ui.ISharedImages;
-import org.eclipse.jdt.ui.JavaUI;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * The {@linkplain ActivityMenuListener} class is responsible for
- * generating the activity menu in the {@link ConfigurationChooser}.
- */
-class ActivityMenuListener extends SelectionAdapter {
- private static final int ACTION_OPEN_ACTIVITY = 1;
- private static final int ACTION_SELECT_ACTIVITY = 2;
-
- private final ConfigurationChooser mConfigChooser;
- private final int mAction;
- private final String mFqcn;
-
- ActivityMenuListener(
- @NonNull ConfigurationChooser configChooser,
- int action,
- @Nullable String fqcn) {
- mConfigChooser = configChooser;
- mAction = action;
- mFqcn = fqcn;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- switch (mAction) {
- case ACTION_OPEN_ACTIVITY: {
- Configuration configuration = mConfigChooser.getConfiguration();
- String fqcn = configuration.getActivity();
- AdtPlugin.openJavaClass(mConfigChooser.getProject(), fqcn);
- break;
- }
- case ACTION_SELECT_ACTIVITY: {
- mConfigChooser.selectActivity(mFqcn);
- mConfigChooser.onSelectActivity();
- break;
- }
- default: assert false : mAction;
- }
- }
-
- static void show(ConfigurationChooser chooser, ToolItem combo) {
- // TODO: Allow using fragments here as well?
- Menu menu = new Menu(chooser.getShell(), SWT.POP_UP);
- ISharedImages sharedImages = JavaUI.getSharedImages();
- Configuration configuration = chooser.getConfiguration();
- String current = configuration.getActivity();
-
- if (current != null) {
- MenuItem item = new MenuItem(menu, SWT.PUSH);
- String label = ConfigurationChooser.getActivityLabel(current, true);
- item.setText( String.format("Open %1$s...", label));
- Image image = sharedImages.getImage(ISharedImages.IMG_OBJS_CUNIT);
- item.setImage(image);
- item.addSelectionListener(
- new ActivityMenuListener(chooser, ACTION_OPEN_ACTIVITY, null));
-
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
- }
-
- IProject project = chooser.getProject();
- Image image = sharedImages.getImage(ISharedImages.IMG_OBJS_CLASS);
-
- // Add activities found to be relevant to this layout
- String layoutName = ResourceHelper.getLayoutName(chooser.getEditedFile());
- String pkg = ManifestInfo.get(project).getPackage();
- List<String> preferred = ManifestInfo.guessActivities(project, layoutName, pkg);
- current = addActivities(chooser, menu, current, image, preferred);
-
- // Add all activities
- List<String> activities = ManifestInfo.getProjectActivities(project);
- if (preferred.size() > 0) {
- // Filter out the activities we've already listed above
- List<String> filtered = new ArrayList<String>(activities.size());
- Set<String> remove = new HashSet<String>(preferred);
- for (String fqcn : activities) {
- if (!remove.contains(fqcn)) {
- filtered.add(fqcn);
- }
- }
- activities = filtered;
- }
-
- if (activities.size() > 0) {
- if (preferred.size() > 0) {
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
- }
-
- addActivities(chooser, menu, current, image, activities);
- }
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-
- private static String addActivities(ConfigurationChooser chooser, Menu menu, String current,
- Image image, List<String> activities) {
- for (final String fqcn : activities) {
- String title = ConfigurationChooser.getActivityLabel(fqcn, false);
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(title);
- item.setImage(image);
-
- boolean selected = title.equals(current);
- if (selected) {
- item.setSelection(true);
- current = null; // Only show the first occurrence as selected
- // such that we don't show it selected again in the full activity list
- }
-
- item.addSelectionListener(new ActivityMenuListener(chooser,
- ACTION_SELECT_ACTIVITY, fqcn));
- }
-
- return current;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java
deleted file mode 100644
index c4253cddf..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Configuration.java
+++ /dev/null
@@ -1,1091 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.rendering.LayoutLibrary;
-import com.android.ide.common.rendering.api.Capability;
-import com.android.ide.common.resources.ResourceFolder;
-import com.android.ide.common.resources.ResourceRepository;
-import com.android.ide.common.resources.configuration.DensityQualifier;
-import com.android.ide.common.resources.configuration.DeviceConfigHelper;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LayoutDirectionQualifier;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-import com.android.ide.common.resources.configuration.NightModeQualifier;
-import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
-import com.android.ide.common.resources.configuration.UiModeQualifier;
-import com.android.ide.common.resources.configuration.VersionQualifier;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo.ActivityAttributes;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.Density;
-import com.android.resources.LayoutDirection;
-import com.android.resources.NightMode;
-import com.android.resources.ScreenSize;
-import com.android.resources.UiMode;
-import com.android.sdklib.AndroidVersion;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.State;
-import com.android.utils.Pair;
-import com.google.common.base.Objects;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.QualifiedName;
-
-import java.util.List;
-
-/**
- * A {@linkplain Configuration} is a selection of device, orientation, theme,
- * etc for use when rendering a layout.
- */
-public class Configuration {
- /** The {@link FolderConfiguration} in change flags or override flags */
- public static final int CFG_FOLDER = 1 << 0;
- /** The {@link Device} in change flags or override flags */
- public static final int CFG_DEVICE = 1 << 1;
- /** The {@link State} in change flags or override flags */
- public static final int CFG_DEVICE_STATE = 1 << 2;
- /** The theme in change flags or override flags */
- public static final int CFG_THEME = 1 << 3;
- /** The locale in change flags or override flags */
- public static final int CFG_LOCALE = 1 << 4;
- /** The rendering {@link IAndroidTarget} in change flags or override flags */
- public static final int CFG_TARGET = 1 << 5;
- /** The {@link NightMode} in change flags or override flags */
- public static final int CFG_NIGHT_MODE = 1 << 6;
- /** The {@link UiMode} in change flags or override flags */
- public static final int CFG_UI_MODE = 1 << 7;
- /** The {@link UiMode} in change flags or override flags */
- public static final int CFG_ACTIVITY = 1 << 8;
-
- /** References all attributes */
- public static final int MASK_ALL = 0xFFFF;
-
- /** Attributes which affect which best-layout-file selection */
- public static final int MASK_FILE_ATTRS =
- CFG_DEVICE|CFG_DEVICE_STATE|CFG_LOCALE|CFG_TARGET|CFG_NIGHT_MODE|CFG_UI_MODE;
-
- /** Attributes which affect rendering appearance */
- public static final int MASK_RENDERING = MASK_FILE_ATTRS|CFG_THEME;
-
- /**
- * Setting name for project-wide setting controlling rendering target and locale which
- * is shared for all files
- */
- public final static QualifiedName NAME_RENDER_STATE =
- new QualifiedName(AdtPlugin.PLUGIN_ID, "render"); //$NON-NLS-1$
-
- private final static String MARKER_FRAMEWORK = "-"; //$NON-NLS-1$
- private final static String MARKER_PROJECT = "+"; //$NON-NLS-1$
- private final static String SEP = ":"; //$NON-NLS-1$
- private final static String SEP_LOCALE = "-"; //$NON-NLS-1$
-
- @NonNull
- protected ConfigurationChooser mConfigChooser;
-
- /** The {@link FolderConfiguration} representing the state of the UI controls */
- @NonNull
- protected final FolderConfiguration mFullConfig = new FolderConfiguration();
-
- /** The {@link FolderConfiguration} being edited. */
- @Nullable
- protected FolderConfiguration mEditedConfig;
-
- /** The target of the project of the file being edited. */
- @Nullable
- private IAndroidTarget mTarget;
-
- /** The theme style to render with */
- @Nullable
- private String mTheme;
-
- /** The device to render with */
- @Nullable
- private Device mDevice;
-
- /** The device state */
- @Nullable
- private State mState;
-
- /**
- * The activity associated with the layout. This is just a cached value of
- * the true value stored on the layout.
- */
- @Nullable
- private String mActivity;
-
- /** The locale to use for this configuration */
- @NonNull
- private Locale mLocale = Locale.ANY;
-
- /** UI mode */
- @NonNull
- private UiMode mUiMode = UiMode.NORMAL;
-
- /** Night mode */
- @NonNull
- private NightMode mNightMode = NightMode.NOTNIGHT;
-
- /** The display name */
- private String mDisplayName;
-
- /**
- * Creates a new {@linkplain Configuration}
- *
- * @param chooser the associated chooser
- */
- protected Configuration(@NonNull ConfigurationChooser chooser) {
- mConfigChooser = chooser;
- }
-
- /**
- * Sets the associated configuration chooser
- *
- * @param chooser the chooser
- */
- void setChooser(@NonNull ConfigurationChooser chooser) {
- // TODO: We should get rid of the binding between configurations
- // and configuration choosers. This is currently needed because
- // the choosers contain vital data such as the set of available
- // rendering targets, the set of available locales etc, which
- // also doesn't belong inside the configuration but is needed by it.
- mConfigChooser = chooser;
- }
-
- /**
- * Gets the associated configuration chooser
- *
- * @return the chooser
- */
- @NonNull
- ConfigurationChooser getChooser() {
- return mConfigChooser;
- }
-
- /**
- * Creates a new {@linkplain Configuration}
- *
- * @param chooser the associated chooser
- * @return a new configuration
- */
- @NonNull
- public static Configuration create(@NonNull ConfigurationChooser chooser) {
- return new Configuration(chooser);
- }
-
- /**
- * Creates a configuration suitable for the given file
- *
- * @param base the base configuration to base the file configuration off of
- * @param file the file to look up a configuration for
- * @return a suitable configuration
- */
- @NonNull
- public static Configuration create(
- @NonNull Configuration base,
- @NonNull IFile file) {
- Configuration configuration = copy(base);
- ConfigurationChooser chooser = base.getChooser();
- ProjectResources resources = chooser.getResources();
- ConfigurationMatcher matcher = new ConfigurationMatcher(chooser, configuration, file,
- resources, false);
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- configuration.mEditedConfig = new FolderConfiguration();
- configuration.mEditedConfig.set(resFolder.getConfiguration());
-
- matcher.adaptConfigSelection(true /*needBestMatch*/);
- configuration.syncFolderConfig();
-
- return configuration;
- }
-
- /**
- * Creates a new {@linkplain Configuration} that is a copy from a different configuration
- *
- * @param original the original to copy from
- * @return a new configuration copied from the original
- */
- @NonNull
- public static Configuration copy(@NonNull Configuration original) {
- Configuration copy = create(original.mConfigChooser);
- copy.mFullConfig.set(original.mFullConfig);
- if (original.mEditedConfig != null) {
- copy.mEditedConfig = new FolderConfiguration();
- copy.mEditedConfig.set(original.mEditedConfig);
- }
- copy.mTarget = original.getTarget();
- copy.mTheme = original.getTheme();
- copy.mDevice = original.getDevice();
- copy.mState = original.getDeviceState();
- copy.mActivity = original.getActivity();
- copy.mLocale = original.getLocale();
- copy.mUiMode = original.getUiMode();
- copy.mNightMode = original.getNightMode();
- copy.mDisplayName = original.getDisplayName();
-
- return copy;
- }
-
- /**
- * Returns the associated activity
- *
- * @return the activity
- */
- @Nullable
- public String getActivity() {
- return mActivity;
- }
-
- /**
- * Returns the chosen device.
- *
- * @return the chosen device
- */
- @Nullable
- public Device getDevice() {
- return mDevice;
- }
-
- /**
- * Returns the chosen device state
- *
- * @return the device state
- */
- @Nullable
- public State getDeviceState() {
- return mState;
- }
-
- /**
- * Returns the chosen locale
- *
- * @return the locale
- */
- @NonNull
- public Locale getLocale() {
- return mLocale;
- }
-
- /**
- * Returns the UI mode
- *
- * @return the UI mode
- */
- @NonNull
- public UiMode getUiMode() {
- return mUiMode;
- }
-
- /**
- * Returns the day/night mode
- *
- * @return the night mode
- */
- @NonNull
- public NightMode getNightMode() {
- return mNightMode;
- }
-
- /**
- * Returns the current theme style
- *
- * @return the theme style
- */
- @Nullable
- public String getTheme() {
- return mTheme;
- }
-
- /**
- * Returns the rendering target
- *
- * @return the target
- */
- @Nullable
- public IAndroidTarget getTarget() {
- return mTarget;
- }
-
- /**
- * Returns the display name to show for this configuration
- *
- * @return the display name, or null if none has been assigned
- */
- @Nullable
- public String getDisplayName() {
- return mDisplayName;
- }
-
- /**
- * Returns whether the configuration's theme is a project theme.
- * <p/>
- * The returned value is meaningless if {@link #getTheme()} returns
- * <code>null</code>.
- *
- * @return true for project a theme, false for a framework theme
- */
- public boolean isProjectTheme() {
- String theme = getTheme();
- if (theme != null) {
- assert theme.startsWith(STYLE_RESOURCE_PREFIX)
- || theme.startsWith(ANDROID_STYLE_RESOURCE_PREFIX);
-
- return ResourceHelper.isProjectStyle(theme);
- }
-
- return false;
- }
-
- /**
- * Returns true if the current layout is locale-specific
- *
- * @return if this configuration represents a locale-specific layout
- */
- public boolean isLocaleSpecificLayout() {
- return mEditedConfig == null || mEditedConfig.getLocaleQualifier() != null;
- }
-
- /**
- * Returns the full, complete {@link FolderConfiguration}
- *
- * @return the full configuration
- */
- @NonNull
- public FolderConfiguration getFullConfig() {
- return mFullConfig;
- }
-
- /**
- * Copies the full, complete {@link FolderConfiguration} into the given
- * folder config instance.
- *
- * @param dest the {@link FolderConfiguration} instance to copy into
- */
- public void copyFullConfig(FolderConfiguration dest) {
- dest.set(mFullConfig);
- }
-
- /**
- * Returns the edited {@link FolderConfiguration} (this is not a full
- * configuration, so you can think of it as the "constraints" used by the
- * {@link ConfigurationMatcher} to produce a full configuration.
- *
- * @return the constraints configuration
- */
- @NonNull
- public FolderConfiguration getEditedConfig() {
- return mEditedConfig;
- }
-
- /**
- * Sets the edited {@link FolderConfiguration} (this is not a full
- * configuration, so you can think of it as the "constraints" used by the
- * {@link ConfigurationMatcher} to produce a full configuration.
- *
- * @param editedConfig the constraints configuration
- */
- public void setEditedConfig(@NonNull FolderConfiguration editedConfig) {
- mEditedConfig = editedConfig;
- }
-
- /**
- * Sets the associated activity
- *
- * @param activity the activity
- */
- public void setActivity(String activity) {
- mActivity = activity;
- }
-
- /**
- * Sets the device
- *
- * @param device the device
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setDevice(Device device, boolean skipSync) {
- mDevice = device;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the device state
- *
- * @param state the device state
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setDeviceState(State state, boolean skipSync) {
- mState = state;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the locale
- *
- * @param locale the locale
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setLocale(@NonNull Locale locale, boolean skipSync) {
- mLocale = locale;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the rendering target
- *
- * @param target rendering target
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setTarget(IAndroidTarget target, boolean skipSync) {
- mTarget = target;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the display name to be shown for this configuration.
- *
- * @param displayName the new display name
- */
- public void setDisplayName(@Nullable String displayName) {
- mDisplayName = displayName;
- }
-
- /**
- * Sets the night mode
- *
- * @param night the night mode
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setNightMode(@NonNull NightMode night, boolean skipSync) {
- mNightMode = night;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the UI mode
- *
- * @param uiMode the UI mode
- * @param skipSync if true, don't sync folder configuration (typically because
- * you are going to set other configuration parameters and you'll call
- * {@link #syncFolderConfig()} once at the end)
- */
- public void setUiMode(@NonNull UiMode uiMode, boolean skipSync) {
- mUiMode = uiMode;
-
- if (!skipSync) {
- syncFolderConfig();
- }
- }
-
- /**
- * Sets the theme style
- *
- * @param theme the theme
- */
- public void setTheme(String theme) {
- mTheme = theme;
- checkThemePrefix();
- }
-
- /**
- * Updates the folder configuration such that it reflects changes in
- * configuration state such as the device orientation, the UI mode, the
- * rendering target, etc.
- */
- public void syncFolderConfig() {
- Device device = getDevice();
- if (device == null) {
- return;
- }
-
- // get the device config from the device/state combos.
- FolderConfiguration config = DeviceConfigHelper.getFolderConfig(getDeviceState());
-
- // replace the config with the one from the device
- mFullConfig.set(config);
-
- // sync the selected locale
- Locale locale = getLocale();
- mFullConfig.setLocaleQualifier(locale.qualifier);
- if (!locale.hasLanguage()) {
- // Avoid getting the layout library if the locale doesn't have any language.
- mFullConfig.setLayoutDirectionQualifier(
- new LayoutDirectionQualifier(LayoutDirection.LTR));
- } else {
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- AndroidTargetData targetData = currentSdk.getTargetData(getTarget());
- if (targetData != null) {
- LayoutLibrary layoutLib = targetData.getLayoutLibrary();
- if (layoutLib != null) {
- if (layoutLib.isRtl(locale.toLocaleId())) {
- mFullConfig.setLayoutDirectionQualifier(
- new LayoutDirectionQualifier(LayoutDirection.RTL));
- } else {
- mFullConfig.setLayoutDirectionQualifier(
- new LayoutDirectionQualifier(LayoutDirection.LTR));
- }
- }
- }
- }
- }
-
- // Replace the UiMode with the selected one, if one is selected
- UiMode uiMode = getUiMode();
- if (uiMode != null) {
- mFullConfig.setUiModeQualifier(new UiModeQualifier(uiMode));
- }
-
- // Replace the NightMode with the selected one, if one is selected
- NightMode nightMode = getNightMode();
- if (nightMode != null) {
- mFullConfig.setNightModeQualifier(new NightModeQualifier(nightMode));
- }
-
- // replace the API level by the selection of the combo
- IAndroidTarget target = getTarget();
- if (target == null && mConfigChooser != null) {
- target = mConfigChooser.getProjectTarget();
- }
- if (target != null) {
- int apiLevel = target.getVersion().getApiLevel();
- mFullConfig.setVersionQualifier(new VersionQualifier(apiLevel));
- }
- }
-
- /**
- * Creates a string suitable for persistence, which can be initialized back
- * to a configuration via {@link #initialize(String)}
- *
- * @return a persistent string
- */
- @NonNull
- public String toPersistentString() {
- StringBuilder sb = new StringBuilder(32);
- Device device = getDevice();
- if (device != null) {
- sb.append(device.getName());
- sb.append(SEP);
- State state = getDeviceState();
- if (state != null) {
- sb.append(state.getName());
- }
- sb.append(SEP);
- Locale locale = getLocale();
- if (isLocaleSpecificLayout() && locale != null && locale.qualifier.hasLanguage()) {
- // locale[0]/[1] can be null sometimes when starting Eclipse
- sb.append(locale.qualifier.getLanguage());
- sb.append(SEP_LOCALE);
- if (locale.qualifier.hasRegion()) {
- sb.append(locale.qualifier.getRegion());
- }
- }
- sb.append(SEP);
- // Need to escape the theme: if we write the full theme style, then
- // we can end up with ":"'s in the string (as in @android:style/Theme) which
- // can be mistaken for {@link #SEP}. Instead use {@link #MARKER_FRAMEWORK}.
- String theme = getTheme();
- if (theme != null) {
- String themeName = ResourceHelper.styleToTheme(theme);
- if (theme.startsWith(STYLE_RESOURCE_PREFIX)) {
- sb.append(MARKER_PROJECT);
- } else if (theme.startsWith(ANDROID_STYLE_RESOURCE_PREFIX)) {
- sb.append(MARKER_FRAMEWORK);
- }
- sb.append(themeName);
- }
- sb.append(SEP);
- UiMode uiMode = getUiMode();
- if (uiMode != null) {
- sb.append(uiMode.getResourceValue());
- }
- sb.append(SEP);
- NightMode nightMode = getNightMode();
- if (nightMode != null) {
- sb.append(nightMode.getResourceValue());
- }
- sb.append(SEP);
-
- // We used to store the render target here in R9. Leave a marker
- // to ensure that we don't reuse this slot; add new extra fields after it.
- sb.append(SEP);
- String activity = getActivity();
- if (activity != null) {
- sb.append(activity);
- }
- }
-
- return sb.toString();
- }
-
- /** Returns the preferred theme, or null */
- @Nullable
- String computePreferredTheme() {
- IProject project = mConfigChooser.getProject();
- ManifestInfo manifest = ManifestInfo.get(project);
-
- // Look up the screen size for the current state
- ScreenSize screenSize = null;
- Device device = getDevice();
- if (device != null) {
- List<State> states = device.getAllStates();
- for (State state : states) {
- FolderConfiguration folderConfig = DeviceConfigHelper.getFolderConfig(state);
- if (folderConfig != null) {
- ScreenSizeQualifier qualifier = folderConfig.getScreenSizeQualifier();
- screenSize = qualifier.getValue();
- break;
- }
- }
- }
-
- // Look up the default/fallback theme to use for this project (which
- // depends on the screen size when no particular theme is specified
- // in the manifest)
- String defaultTheme = manifest.getDefaultTheme(getTarget(), screenSize);
-
- String preferred = defaultTheme;
- if (getTheme() == null) {
- // If we are rendering a layout in included context, pick the theme
- // from the outer layout instead
-
- String activity = getActivity();
- if (activity != null) {
- ActivityAttributes attributes = manifest.getActivityAttributes(activity);
- if (attributes != null) {
- preferred = attributes.getTheme();
- }
- }
- if (preferred == null) {
- preferred = defaultTheme;
- }
- setTheme(preferred);
- }
-
- return preferred;
- }
-
- private void checkThemePrefix() {
- if (mTheme != null && !mTheme.startsWith(PREFIX_RESOURCE_REF)) {
- if (mTheme.isEmpty()) {
- computePreferredTheme();
- return;
- }
- ResourceRepository frameworkRes = mConfigChooser.getClient().getFrameworkResources();
- if (frameworkRes != null
- && frameworkRes.hasResourceItem(ANDROID_STYLE_RESOURCE_PREFIX + mTheme)) {
- mTheme = ANDROID_STYLE_RESOURCE_PREFIX + mTheme;
- } else {
- mTheme = STYLE_RESOURCE_PREFIX + mTheme;
- }
- }
- }
-
- /**
- * Initializes a string previously created with
- * {@link #toPersistentString()}
- *
- * @param data the string to initialize back from
- * @return true if the configuration was initialized
- */
- boolean initialize(String data) {
- String[] values = data.split(SEP);
- if (values.length >= 6 && values.length <= 8) {
- for (Device d : mConfigChooser.getDevices()) {
- if (d.getName().equals(values[0])) {
- mDevice = d;
- String stateName = null;
- FolderConfiguration config = null;
- if (!values[1].isEmpty() && !values[1].equals("null")) { //$NON-NLS-1$
- stateName = values[1];
- config = DeviceConfigHelper.getFolderConfig(mDevice, stateName);
- } else if (mDevice.getAllStates().size() > 0) {
- State first = mDevice.getAllStates().get(0);
- stateName = first.getName();
- config = DeviceConfigHelper.getFolderConfig(first);
- }
- mState = getState(mDevice, stateName);
- if (config != null) {
- // Load locale. Note that this can get overwritten by the
- // project-wide settings read below.
- LocaleQualifier locale = Locale.ANY_QUALIFIER;
- String locales[] = values[2].split(SEP_LOCALE);
- if (locales.length >= 2 && locales[0].length() > 0
- && !LocaleQualifier.FAKE_VALUE.equals(locales[0])) {
- String language = locales[0];
- String region = locales[1];
- if (region.length() > 0 && !LocaleQualifier.FAKE_VALUE.equals(region)) {
- locale = LocaleQualifier.getQualifier(language + "-r" + region);
- } else {
- locale = new LocaleQualifier(language);
- }
- mLocale = Locale.create(locale);
- }
-
- // Decode the theme name: See {@link #getData}
- mTheme = values[3];
- if (mTheme.startsWith(MARKER_FRAMEWORK)) {
- mTheme = ANDROID_STYLE_RESOURCE_PREFIX
- + mTheme.substring(MARKER_FRAMEWORK.length());
- } else if (mTheme.startsWith(MARKER_PROJECT)) {
- mTheme = STYLE_RESOURCE_PREFIX
- + mTheme.substring(MARKER_PROJECT.length());
- } else {
- checkThemePrefix();
- }
-
- mUiMode = UiMode.getEnum(values[4]);
- if (mUiMode == null) {
- mUiMode = UiMode.NORMAL;
- }
- mNightMode = NightMode.getEnum(values[5]);
- if (mNightMode == null) {
- mNightMode = NightMode.NOTNIGHT;
- }
-
- // element 7/values[6]: used to store render target in R9.
- // No longer stored here. If adding more data, make
- // sure you leave 7 alone.
-
- Pair<Locale, IAndroidTarget> pair = loadRenderState(mConfigChooser);
- if (pair != null) {
- // We only use the "global" setting
- if (!isLocaleSpecificLayout()) {
- mLocale = pair.getFirst();
- }
- mTarget = pair.getSecond();
- }
-
- if (values.length == 8) {
- mActivity = values[7];
- }
-
- return true;
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Loads the render state (the locale and the render target, which are shared among
- * all the layouts meaning that changing it in one will change it in all) and returns
- * the current project-wide locale and render target to be used.
- *
- * @param chooser the {@link ConfigurationChooser} providing information about
- * loaded targets
- * @return a pair of a locale and a render target
- */
- @Nullable
- static Pair<Locale, IAndroidTarget> loadRenderState(ConfigurationChooser chooser) {
- IProject project = chooser.getProject();
- if (project == null || !project.isAccessible()) {
- return null;
- }
-
- try {
- String data = project.getPersistentProperty(NAME_RENDER_STATE);
- if (data != null) {
- Locale locale = Locale.ANY;
- IAndroidTarget target = null;
-
- String[] values = data.split(SEP);
- if (values.length == 2) {
-
- LocaleQualifier qualifier = Locale.ANY_QUALIFIER;
- String locales[] = values[0].split(SEP_LOCALE);
- if (locales.length >= 2 && locales[0].length() > 0
- && !LocaleQualifier.FAKE_VALUE.equals(locales[0])) {
- String language = locales[0];
- String region = locales[1];
- if (region.length() > 0 && !LocaleQualifier.FAKE_VALUE.equals(region)) {
- locale = Locale.create(LocaleQualifier.getQualifier(language + "-r" + region));
- } else {
- locale = Locale.create(new LocaleQualifier(language));
- }
- } else {
- locale = Locale.ANY;
- }
- if (AdtPrefs.getPrefs().isAutoPickRenderTarget()) {
- target = ConfigurationMatcher.findDefaultRenderTarget(chooser);
- } else {
- String targetString = values[1];
- target = stringToTarget(chooser, targetString);
- // See if we should "correct" the rendering target to a
- // better version. If you're using a pre-release version
- // of the render target, and a final release is
- // available and installed, we should switch to that
- // one instead.
- if (target != null) {
- AndroidVersion version = target.getVersion();
- List<IAndroidTarget> targetList = chooser.getTargetList();
- if (version.getCodename() != null && targetList != null) {
- int targetApiLevel = version.getApiLevel() + 1;
- for (IAndroidTarget t : targetList) {
- if (t.getVersion().getApiLevel() == targetApiLevel
- && t.isPlatform()) {
- target = t;
- break;
- }
- }
- }
- } else {
- target = ConfigurationMatcher.findDefaultRenderTarget(chooser);
- }
- }
- }
-
- return Pair.of(locale, target);
- }
-
- return Pair.of(Locale.ANY, ConfigurationMatcher.findDefaultRenderTarget(chooser));
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- return null;
- }
-
- /**
- * Saves the render state (the current locale and render target settings) into the
- * project wide settings storage
- */
- void saveRenderState() {
- IProject project = mConfigChooser.getProject();
- if (project == null) {
- return;
- }
- try {
- // Generate a persistent string from locale+target
- StringBuilder sb = new StringBuilder(32);
- Locale locale = getLocale();
- if (locale != null) {
- // locale[0]/[1] can be null sometimes when starting Eclipse
- sb.append(locale.qualifier.getLanguage());
- sb.append(SEP_LOCALE);
- if (locale.qualifier.hasRegion()) {
- sb.append(locale.qualifier.getRegion());
- }
- }
- sb.append(SEP);
- IAndroidTarget target = getTarget();
- if (target != null) {
- sb.append(targetToString(target));
- sb.append(SEP);
- }
-
- project.setPersistentProperty(NAME_RENDER_STATE, sb.toString());
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
- }
-
- /**
- * Returns a String id to represent an {@link IAndroidTarget} which can be translated
- * back to an {@link IAndroidTarget} by the matching {@link #stringToTarget}. The id
- * will never contain the {@link #SEP} character.
- *
- * @param target the target to return an id for
- * @return an id for the given target; never null
- */
- @NonNull
- public static String targetToString(@NonNull IAndroidTarget target) {
- return target.getFullName().replace(SEP, ""); //$NON-NLS-1$
- }
-
- /**
- * Returns an {@link IAndroidTarget} that corresponds to the given id that was
- * originally returned by {@link #targetToString}. May be null, if the platform is no
- * longer available, or if the platform list has not yet been initialized.
- *
- * @param chooser the {@link ConfigurationChooser} providing information about
- * loaded targets
- * @param id the id that corresponds to the desired platform
- * @return an {@link IAndroidTarget} that matches the given id, or null
- */
- @Nullable
- public static IAndroidTarget stringToTarget(
- @NonNull ConfigurationChooser chooser,
- @NonNull String id) {
- List<IAndroidTarget> targetList = chooser.getTargetList();
- if (targetList != null && targetList.size() > 0) {
- for (IAndroidTarget target : targetList) {
- if (id.equals(targetToString(target))) {
- return target;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns an {@link IAndroidTarget} that corresponds to the given id that was
- * originally returned by {@link #targetToString}. May be null, if the platform is no
- * longer available, or if the platform list has not yet been initialized.
- *
- * @param id the id that corresponds to the desired platform
- * @return an {@link IAndroidTarget} that matches the given id, or null
- */
- @Nullable
- public static IAndroidTarget stringToTarget(
- @NonNull String id) {
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget[] targets = currentSdk.getTargets();
- for (IAndroidTarget target : targets) {
- if (id.equals(targetToString(target))) {
- return target;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns the {@link State} by the given name for the given {@link Device}
- *
- * @param device the device
- * @param name the name of the state
- */
- @Nullable
- static State getState(@Nullable Device device, @Nullable String name) {
- if (device == null) {
- return null;
- } else if (name != null) {
- State state = device.getState(name);
- if (state != null) {
- return state;
- }
- }
-
- return device.getDefaultState();
- }
-
- /**
- * Returns the currently selected {@link Density}. This is guaranteed to be non null.
- *
- * @return the density
- */
- @NonNull
- public Density getDensity() {
- if (mFullConfig != null) {
- DensityQualifier qual = mFullConfig.getDensityQualifier();
- if (qual != null) {
- // just a sanity check
- Density d = qual.getValue();
- if (d != Density.NODPI) {
- return d;
- }
- }
- }
-
- // no config? return medium as the default density.
- return Density.MEDIUM;
- }
-
- /**
- * Get the next cyclical state after the given state
- *
- * @param from the state to start with
- * @return the following state following
- */
- @Nullable
- public State getNextDeviceState(@Nullable State from) {
- Device device = getDevice();
- if (device == null) {
- return null;
- }
- List<State> states = device.getAllStates();
- for (int i = 0; i < states.size(); i++) {
- if (states.get(i) == from) {
- return states.get((i + 1) % states.size());
- }
- }
-
- return null;
- }
-
- /**
- * Returns true if this configuration supports the given rendering
- * capability
- *
- * @param capability the capability to check
- * @return true if the capability is supported
- */
- public boolean supports(Capability capability) {
- IAndroidTarget target = getTarget();
- if (target != null) {
- return RenderService.supports(target, capability);
- }
-
- return false;
- }
-
- @Override
- public String toString() {
- return Objects.toStringHelper(this.getClass())
- .add("display", getDisplayName()) //$NON-NLS-1$
- .add("persistent", toPersistentString()) //$NON-NLS-1$
- .toString();
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationChooser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationChooser.java
deleted file mode 100644
index 009b8646c..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationChooser.java
+++ /dev/null
@@ -1,2096 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
-import static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_CONTEXT;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.RES_QUALIFIER_SEP;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.TOOLS_URI;
-import static com.android.ide.eclipse.adt.AdtUtils.isUiThread;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_DEVICE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_DEVICE_STATE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_FOLDER;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_LOCALE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_TARGET;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.CFG_THEME;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.MASK_ALL;
-import static com.google.common.base.Objects.equal;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.rendering.api.StyleResourceValue;
-import com.android.ide.common.resources.LocaleManager;
-import com.android.ide.common.resources.ResourceFile;
-import com.android.ide.common.resources.ResourceFolder;
-import com.android.ide.common.resources.ResourceRepository;
-import com.android.ide.common.resources.configuration.DeviceConfigHelper;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-import com.android.ide.common.resources.configuration.ResourceQualifier;
-import com.android.ide.common.sdk.LoadStatus;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate;
-import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo.ActivityAttributes;
-import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.ResourceType;
-import com.android.resources.ScreenOrientation;
-import com.android.sdklib.AndroidVersion;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.DeviceManager;
-import com.android.sdklib.devices.DeviceManager.DevicesChangedListener;
-import com.android.sdklib.devices.State;
-import com.android.utils.Pair;
-import com.google.common.base.Objects;
-import com.google.common.base.Strings;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.jface.resource.ImageDescriptor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.swt.widgets.ToolItem;
-import org.eclipse.ui.IEditorPart;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-
-/**
- * The {@linkplain ConfigurationChooser} allows the user to pick a
- * {@link Configuration} by configuring various constraints.
- */
-public class ConfigurationChooser extends Composite
- implements DevicesChangedListener, DisposeListener {
- private static final String ICON_SQUARE = "square"; //$NON-NLS-1$
- private static final String ICON_LANDSCAPE = "landscape"; //$NON-NLS-1$
- private static final String ICON_PORTRAIT = "portrait"; //$NON-NLS-1$
- private static final String ICON_LANDSCAPE_FLIP = "flip_landscape";//$NON-NLS-1$
- private static final String ICON_PORTRAIT_FLIP = "flip_portrait";//$NON-NLS-1$
- private static final String ICON_DISPLAY = "display"; //$NON-NLS-1$
- private static final String ICON_THEMES = "themes"; //$NON-NLS-1$
- private static final String ICON_ACTIVITY = "activity"; //$NON-NLS-1$
-
- /** The configuration state associated with this editor */
- private @NonNull Configuration mConfiguration = Configuration.create(this);
-
- /** Serialized state to use when initializing the configuration after the SDK is loaded */
- private String mInitialState;
-
- /** The client of the configuration editor */
- private final ConfigurationClient mClient;
-
- /** Counter for programmatic UI changes: if greater than 0, we're within a call */
- private int mDisableUpdates = 0;
-
- /** List of available devices */
- private Collection<Device> mDevices = Collections.emptyList();
-
- /** List of available targets */
- private final List<IAndroidTarget> mTargetList = new ArrayList<IAndroidTarget>();
-
- /** List of available themes */
- private final List<String> mThemeList = new ArrayList<String>();
-
- /** List of available locales */
- private final List<Locale > mLocaleList = new ArrayList<Locale>();
-
- /** The file being edited */
- private IFile mEditedFile;
-
- /** The {@link ProjectResources} for the edited file's project */
- private ProjectResources mResources;
-
- /** The target of the project of the file being edited. */
- private IAndroidTarget mProjectTarget;
-
- /** Dropdown for configurations */
- private ToolItem mConfigCombo;
-
- /** Dropdown for devices */
- private ToolItem mDeviceCombo;
-
- /** Dropdown for device states */
- private ToolItem mOrientationCombo;
-
- /** Dropdown for themes */
- private ToolItem mThemeCombo;
-
- /** Dropdown for locales */
- private ToolItem mLocaleCombo;
-
- /** Dropdown for activities */
- private ToolItem mActivityCombo;
-
- /** Dropdown for rendering targets */
- private ToolItem mTargetCombo;
-
- /** Whether the SDK has changed since the last model reload; if so we must reload targets */
- private boolean mSdkChanged = true;
-
- /**
- * Creates a new {@linkplain ConfigurationChooser} and adds it to the
- * parent. The method also receives custom buttons to set into the
- * configuration composite. The list is organized as an array of arrays.
- * Each array represents a group of buttons thematically grouped together.
- *
- * @param client the client embedding this configuration chooser
- * @param parent The parent composite.
- * @param initialState The initial state (serialized form) to use for the
- * configuration
- */
- public ConfigurationChooser(
- @NonNull ConfigurationClient client,
- Composite parent,
- @Nullable String initialState) {
- super(parent, SWT.NONE);
- mClient = client;
-
- setVisible(false); // Delayed until the targets are loaded
-
- mInitialState = initialState;
- setLayout(new GridLayout(1, false));
-
- IconFactory icons = IconFactory.getInstance();
-
- // TODO: Consider switching to a CoolBar instead
- ToolBar toolBar = new ToolBar(this, SWT.WRAP | SWT.FLAT | SWT.RIGHT | SWT.HORIZONTAL);
- toolBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
-
- mConfigCombo = new ToolItem(toolBar, SWT.DROP_DOWN );
- mConfigCombo.setImage(icons.getIcon("android_file")); //$NON-NLS-1$
- mConfigCombo.setToolTipText("Configuration to render this layout with in Eclipse");
-
- @SuppressWarnings("unused")
- ToolItem separator2 = new ToolItem(toolBar, SWT.SEPARATOR);
-
- mDeviceCombo = new ToolItem(toolBar, SWT.DROP_DOWN);
- mDeviceCombo.setImage(icons.getIcon(ICON_DISPLAY));
-
- @SuppressWarnings("unused")
- ToolItem separator3 = new ToolItem(toolBar, SWT.SEPARATOR);
-
- mOrientationCombo = new ToolItem(toolBar, SWT.DROP_DOWN);
- mOrientationCombo.setImage(icons.getIcon(ICON_PORTRAIT));
- mOrientationCombo.setToolTipText("Go to next state");
-
- @SuppressWarnings("unused")
- ToolItem separator4 = new ToolItem(toolBar, SWT.SEPARATOR);
-
- mThemeCombo = new ToolItem(toolBar, SWT.DROP_DOWN);
- mThemeCombo.setImage(icons.getIcon(ICON_THEMES));
-
- @SuppressWarnings("unused")
- ToolItem separator5 = new ToolItem(toolBar, SWT.SEPARATOR);
-
- mActivityCombo = new ToolItem(toolBar, SWT.DROP_DOWN);
- mActivityCombo.setToolTipText("Associated activity or fragment providing context");
- // The JDT class icon is lopsided, presumably because they've left room in the
- // bottom right corner for badges (for static, final etc). Unfortunately, this
- // means that the icon looks out of place when sitting close to the language globe
- // icon, the theme icon, etc so that it looks vertically misaligned:
- //mActivityCombo.setImage(JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CLASS));
- // ...so use one that is centered instead:
- mActivityCombo.setImage(icons.getIcon(ICON_ACTIVITY));
-
- @SuppressWarnings("unused")
- ToolItem separator6 = new ToolItem(toolBar, SWT.SEPARATOR);
-
- //ToolBar rightToolBar = new ToolBar(this, SWT.WRAP | SWT.FLAT | SWT.RIGHT | SWT.HORIZONTAL);
- //rightToolBar.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));
- ToolBar rightToolBar = toolBar;
-
- mLocaleCombo = new ToolItem(rightToolBar, SWT.DROP_DOWN);
- mLocaleCombo.setImage(FlagManager.getGlobeIcon());
- mLocaleCombo.setToolTipText("Locale to use when rendering layouts in Eclipse");
-
- @SuppressWarnings("unused")
- ToolItem separator7 = new ToolItem(rightToolBar, SWT.SEPARATOR);
-
- mTargetCombo = new ToolItem(rightToolBar, SWT.DROP_DOWN);
- mTargetCombo.setImage(AdtPlugin.getAndroidLogo());
- mTargetCombo.setToolTipText("Android version to use when rendering layouts in Eclipse");
-
- SelectionListener listener = new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- Object source = e.getSource();
-
- if (source == mConfigCombo) {
- ConfigurationMenuListener.show(ConfigurationChooser.this, mConfigCombo);
- } else if (source == mActivityCombo) {
- ActivityMenuListener.show(ConfigurationChooser.this, mActivityCombo);
- } else if (source == mLocaleCombo) {
- LocaleMenuListener.show(ConfigurationChooser.this, mLocaleCombo);
- } else if (source == mDeviceCombo) {
- DeviceMenuListener.show(ConfigurationChooser.this, mDeviceCombo);
- } else if (source == mTargetCombo) {
- TargetMenuListener.show(ConfigurationChooser.this, mTargetCombo);
- } else if (source == mThemeCombo) {
- ThemeMenuAction.showThemeMenu(ConfigurationChooser.this, mThemeCombo,
- mThemeList);
- } else if (source == mOrientationCombo) {
- if (e.detail == SWT.ARROW) {
- OrientationMenuAction.showMenu(ConfigurationChooser.this,
- mOrientationCombo);
- } else {
- gotoNextState();
- }
- }
- }
- };
- mConfigCombo.addSelectionListener(listener);
- mActivityCombo.addSelectionListener(listener);
- mLocaleCombo.addSelectionListener(listener);
- mDeviceCombo.addSelectionListener(listener);
- mTargetCombo.addSelectionListener(listener);
- mThemeCombo.addSelectionListener(listener);
- mOrientationCombo.addSelectionListener(listener);
-
- addDisposeListener(this);
-
- initDevices();
- initTargets();
- }
-
- /**
- * Returns the edited file
- *
- * @return the file
- */
- @Nullable
- public IFile getEditedFile() {
- return mEditedFile;
- }
-
- /**
- * Returns the project of the edited file
- *
- * @return the project
- */
- @Nullable
- public IProject getProject() {
- if (mEditedFile != null) {
- return mEditedFile.getProject();
- } else {
- return null;
- }
- }
-
- ConfigurationClient getClient() {
- return mClient;
- }
-
- /**
- * Returns the project resources for the project being configured by this
- * chooser
- *
- * @return the project resources
- */
- @Nullable
- public ProjectResources getResources() {
- return mResources;
- }
-
- /**
- * Returns the full, complete {@link FolderConfiguration}
- *
- * @return the full configuration
- */
- public FolderConfiguration getFullConfiguration() {
- return mConfiguration.getFullConfig();
- }
-
- /**
- * Returns the project target
- *
- * @return the project target
- */
- public IAndroidTarget getProjectTarget() {
- return mProjectTarget;
- }
-
- /**
- * Returns the configuration being edited by this {@linkplain ConfigurationChooser}
- *
- * @return the configuration
- */
- public Configuration getConfiguration() {
- return mConfiguration;
- }
-
- /**
- * Returns the list of locales
- * @return a list of {@link ResourceQualifier} pairs
- */
- @NonNull
- public List<Locale> getLocaleList() {
- return mLocaleList;
- }
-
- /**
- * Returns the list of available devices
- *
- * @return a list of {@link Device} objects
- */
- @NonNull
- public Collection<Device> getDevices() {
- return mDevices;
- }
-
- /**
- * Returns the list of available render targets
- *
- * @return a list of {@link IAndroidTarget} objects
- */
- @NonNull
- public List<IAndroidTarget> getTargetList() {
- return mTargetList;
- }
-
- // ---- Configuration State Lookup ----
-
- /**
- * Returns the rendering target to be used
- *
- * @return the target
- */
- @NonNull
- public IAndroidTarget getTarget() {
- IAndroidTarget target = mConfiguration.getTarget();
- if (target == null) {
- target = mProjectTarget;
- }
-
- return target;
- }
-
- /**
- * Returns the current device string, or null if no device is selected
- *
- * @return the device name, or null
- */
- @Nullable
- public String getDeviceName() {
- Device device = mConfiguration.getDevice();
- if (device != null) {
- return device.getName();
- }
-
- return null;
- }
-
- /**
- * Returns the current theme, or null if none has been selected
- *
- * @return the theme name, or null
- */
- @Nullable
- public String getThemeName() {
- String theme = mConfiguration.getTheme();
- if (theme != null) {
- theme = ResourceHelper.styleToTheme(theme);
- }
-
- return theme;
- }
-
- /** Move to the next device state, changing the icon if it changes orientation */
- private void gotoNextState() {
- State state = mConfiguration.getDeviceState();
- State flipped = mConfiguration.getNextDeviceState(state);
- if (flipped != state) {
- selectDeviceState(flipped);
- onDeviceConfigChange();
- }
- }
-
- // ---- Implements DisposeListener ----
-
- @Override
- public void widgetDisposed(DisposeEvent e) {
- dispose();
- }
-
- @Override
- public void dispose() {
- if (!isDisposed()) {
- super.dispose();
-
- final Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- DeviceManager manager = sdk.getDeviceManager();
- manager.unregisterListener(this);
- }
- }
- }
-
- // ---- Init and reset/reload methods ----
-
- /**
- * Sets the reference to the file being edited.
- * <p/>The UI is initialized in {@link #onXmlModelLoaded()} which is called as the XML model is
- * loaded (or reloaded as the SDK/target changes).
- *
- * @param file the file being opened
- *
- * @see #onXmlModelLoaded()
- * @see #replaceFile(IFile)
- * @see #changeFileOnNewConfig(IFile)
- */
- public void setFile(IFile file) {
- mEditedFile = file;
- ensureInitialized();
- }
-
- /**
- * Replaces the UI with a given file configuration. This is meant to answer the user
- * explicitly opening a different version of the same layout from the Package Explorer.
- * <p/>This attempts to keep the current config, but may change it if it's not compatible or
- * not the best match
- * @param file the file being opened.
- */
- public void replaceFile(IFile file) {
- // if there is no previous selection, revert to default mode.
- if (mConfiguration.getDevice() == null) {
- setFile(file); // onTargetChanged will be called later.
- return;
- }
-
- setFile(file);
- IProject project = mEditedFile.getProject();
- mResources = ResourceManager.getInstance().getProjectResources(project);
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- mConfiguration.setEditedConfig(resFolder.getConfiguration());
-
- mDisableUpdates++; // we do not want to trigger onXXXChange when setting
- // new values in the widgets.
-
- try {
- // only attempt to do anything if the SDK and targets are loaded.
- LoadStatus sdkStatus = AdtPlugin.getDefault().getSdkLoadStatus();
-
- if (sdkStatus == LoadStatus.LOADED) {
- setVisible(true);
-
- LoadStatus targetStatus = Sdk.getCurrent().checkAndLoadTargetData(mProjectTarget,
- null /*project*/);
-
- if (targetStatus == LoadStatus.LOADED) {
-
- // update the current config selection to make sure it's
- // compatible with the new file
- ConfigurationMatcher matcher = new ConfigurationMatcher(this);
- matcher.adaptConfigSelection(true /*needBestMatch*/);
- mConfiguration.syncFolderConfig();
-
- // update the string showing the config value
- selectConfiguration(mConfiguration.getEditedConfig());
- updateActivity();
- }
- } else if (sdkStatus == LoadStatus.FAILED) {
- setVisible(true);
- }
- } finally {
- mDisableUpdates--;
- }
- }
-
- /**
- * Updates the UI with a new file that was opened in response to a config change.
- * @param file the file being opened.
- *
- * @see #replaceFile(IFile)
- */
- public void changeFileOnNewConfig(IFile file) {
- setFile(file);
- IProject project = mEditedFile.getProject();
- mResources = ResourceManager.getInstance().getProjectResources(project);
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- FolderConfiguration config = resFolder.getConfiguration();
- mConfiguration.setEditedConfig(config);
-
- // All that's needed is to update the string showing the config value
- // (since the config combo settings chosen by the user).
- selectConfiguration(config);
- }
-
- /**
- * Resets the configuration chooser to reflect the given file configuration. This is
- * intended to be used by the "Show Included In" functionality where the user has
- * picked a non-default configuration (such as a particular landscape layout) and the
- * configuration chooser must be switched to a landscape layout. This method will
- * trigger a model change.
- * <p>
- * This will NOT trigger a redraw event!
- * <p>
- * FIXME: We are currently setting the configuration file to be the configuration for
- * the "outer" (the including) file, rather than the inner file, which is the file the
- * user is actually editing. We need to refine this, possibly with a way for the user
- * to choose which configuration they are editing. And in particular, we should be
- * filtering the configuration chooser to only show options in the outer configuration
- * that are compatible with the inner included file.
- *
- * @param file the file to be configured
- */
- public void resetConfigFor(IFile file) {
- setFile(file);
-
- IFolder parent = (IFolder) mEditedFile.getParent();
- ResourceFolder resFolder = mResources.getResourceFolder(parent);
- if (resFolder != null) {
- mConfiguration.setEditedConfig(resFolder.getConfiguration());
- } else {
- FolderConfiguration config = FolderConfiguration.getConfig(
- parent.getName().split(RES_QUALIFIER_SEP));
- if (config != null) {
- mConfiguration.setEditedConfig(config);
- } else {
- mConfiguration.setEditedConfig(new FolderConfiguration());
- }
- }
-
- onXmlModelLoaded();
- }
-
-
- /**
- * Sets the current configuration to match the given folder configuration,
- * the given theme name, the given device and device state.
- *
- * @param configuration new folder configuration to use
- */
- public void setConfiguration(@NonNull Configuration configuration) {
- if (mClient != null) {
- mClient.aboutToChange(MASK_ALL);
- }
-
- Configuration oldConfiguration = mConfiguration;
- mConfiguration = configuration;
- mConfiguration.setChooser(this);
-
- selectTheme(configuration.getTheme());
- selectLocale(configuration.getLocale());
- selectDevice(configuration.getDevice());
- selectDeviceState(configuration.getDeviceState());
- selectTarget(configuration.getTarget());
- selectActivity(configuration.getActivity());
-
- // This may be a second refresh after triggered by theme above
- if (mClient != null) {
- LayoutCanvas canvas = mClient.getCanvas();
- if (canvas != null) {
- assert mConfiguration != oldConfiguration;
- canvas.getPreviewManager().updateChooserConfig(oldConfiguration, mConfiguration);
- }
-
- boolean accepted = mClient.changed(MASK_ALL);
- if (!accepted) {
- configuration = oldConfiguration;
- selectTheme(configuration.getTheme());
- selectLocale(configuration.getLocale());
- selectDevice(configuration.getDevice());
- selectDeviceState(configuration.getDeviceState());
- selectTarget(configuration.getTarget());
- selectActivity(configuration.getActivity());
- if (canvas != null && mConfiguration != oldConfiguration) {
- canvas.getPreviewManager().updateChooserConfig(mConfiguration,
- oldConfiguration);
- }
- return;
- } else {
- int changed = 0;
- if (!equal(oldConfiguration.getTheme(), mConfiguration.getTheme())) {
- changed |= CFG_THEME;
- }
- if (!equal(oldConfiguration.getDevice(), mConfiguration.getDevice())) {
- changed |= CFG_DEVICE | CFG_DEVICE_STATE;
- }
- if (changed != 0) {
- syncToVariations(changed, mEditedFile, mConfiguration, false, true);
- }
- }
- }
-
- saveConstraints();
- }
-
- /**
- * Responds to the event that the basic SDK information finished loading.
- * @param target the possibly new target object associated with the file being edited (in case
- * the SDK path was changed).
- */
- public void onSdkLoaded(IAndroidTarget target) {
- // a change to the SDK means that we need to check for new/removed devices.
- mSdkChanged = true;
-
- // store the new target.
- mProjectTarget = target;
-
- mDisableUpdates++; // we do not want to trigger onXXXChange when setting
- // new values in the widgets.
- try {
- updateDevices();
- updateTargets();
- ensureInitialized();
- } finally {
- mDisableUpdates--;
- }
- }
-
- /**
- * Responds to the XML model being loaded, either the first time or when the
- * Target/SDK changes.
- * <p>
- * This initializes the UI, either with the first compatible configuration
- * found, or it will attempt to restore a configuration if one is found to
- * have been saved in the file persistent storage.
- * <p>
- * If the SDK or target are not loaded, nothing will happen (but the method
- * must be called back when they are.)
- * <p>
- * The method automatically handles being called the first time after editor
- * creation, or being called after during SDK/Target changes (as long as
- * {@link #onSdkLoaded(IAndroidTarget)} is properly called).
- *
- * @return the target data for the rendering target used to render the
- * layout
- *
- * @see #saveConstraints()
- * @see #onSdkLoaded(IAndroidTarget)
- */
- public AndroidTargetData onXmlModelLoaded() {
- AndroidTargetData targetData = null;
-
- // only attempt to do anything if the SDK and targets are loaded.
- LoadStatus sdkStatus = AdtPlugin.getDefault().getSdkLoadStatus();
- if (sdkStatus == LoadStatus.LOADED) {
- mDisableUpdates++; // we do not want to trigger onXXXChange when setting
-
- try {
- // init the devices if needed (new SDK or first time going through here)
- if (mSdkChanged) {
- updateDevices();
- updateTargets();
- ensureInitialized();
- mSdkChanged = false;
- }
-
- IProject project = mEditedFile.getProject();
-
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- mProjectTarget = currentSdk.getTarget(project);
- }
-
- LoadStatus targetStatus = LoadStatus.FAILED;
- if (mProjectTarget != null) {
- targetStatus = Sdk.getCurrent().checkAndLoadTargetData(mProjectTarget, null);
- updateTargets();
- ensureInitialized();
- }
-
- if (targetStatus == LoadStatus.LOADED) {
- setVisible(true);
- if (mResources == null) {
- mResources = ResourceManager.getInstance().getProjectResources(project);
- }
- if (mConfiguration.getEditedConfig() == null) {
- IFolder parent = (IFolder) mEditedFile.getParent();
- ResourceFolder resFolder = mResources.getResourceFolder(parent);
- if (resFolder != null) {
- mConfiguration.setEditedConfig(resFolder.getConfiguration());
- } else {
- FolderConfiguration config = FolderConfiguration.getConfig(
- parent.getName().split(RES_QUALIFIER_SEP));
- if (config != null) {
- mConfiguration.setEditedConfig(config);
- } else {
- mConfiguration.setEditedConfig(new FolderConfiguration());
- }
- }
- }
-
- targetData = Sdk.getCurrent().getTargetData(mProjectTarget);
-
- // get the file stored state
- ensureInitialized();
- boolean loadedConfigData = mConfiguration.getDevice() != null &&
- mConfiguration.getDeviceState() != null;
-
- // Load locale list. This must be run after we initialize the
- // configuration above, since it attempts to sync the UI with
- // the value loaded into the configuration.
- updateLocales();
-
- // If the current state was loaded from the persistent storage, we update the
- // UI with it and then try to adapt it (which will handle incompatible
- // configuration).
- // Otherwise, just look for the first compatible configuration.
- ConfigurationMatcher matcher = new ConfigurationMatcher(this);
- if (loadedConfigData) {
- // first make sure we have the config to adapt
- selectDevice(mConfiguration.getDevice());
- selectDeviceState(mConfiguration.getDeviceState());
- mConfiguration.syncFolderConfig();
-
- matcher.adaptConfigSelection(false);
-
- IAndroidTarget target = mConfiguration.getTarget();
- selectTarget(target);
- targetData = Sdk.getCurrent().getTargetData(target);
- } else {
- matcher.findAndSetCompatibleConfig(false);
-
- // Default to modern layout lib
- IAndroidTarget target = ConfigurationMatcher.findDefaultRenderTarget(this);
- if (target != null) {
- targetData = Sdk.getCurrent().getTargetData(target);
- selectTarget(target);
- mConfiguration.setTarget(target, true);
- }
- }
-
- // Update activity: This is done before updateThemes() since
- // the themes selection can depend on the currently selected activity
- // (e.g. when there are manifest registrations for the theme to use
- // for a given activity)
- updateActivity();
-
- // Update themes. This is done after updating the devices above,
- // since we want to look at the chosen device size to decide
- // what the default theme (for example, with Honeycomb we choose
- // Holo as the default theme but only if the screen size is XLARGE
- // (and of course only if the manifest does not specify another
- // default theme).
- updateThemes();
-
- // update the string showing the config value
- selectConfiguration(mConfiguration.getEditedConfig());
-
- // compute the final current config
- mConfiguration.syncFolderConfig();
- } else if (targetStatus == LoadStatus.FAILED) {
- setVisible(true);
- }
- } finally {
- mDisableUpdates--;
- }
- }
-
- return targetData;
- }
-
- /**
- * This is a temporary workaround for a infrequently happening bug; apparently
- * there are cases where the configuration chooser isn't shown
- */
- public void ensureVisible() {
- if (!isVisible()) {
- LoadStatus sdkStatus = AdtPlugin.getDefault().getSdkLoadStatus();
- if (sdkStatus == LoadStatus.LOADED) {
- onXmlModelLoaded();
- }
- }
- }
-
- /**
- * An alternate layout for this layout has been created. This means that the
- * current layout may no longer be a best fit. However, since we support multiple
- * layouts being open at the same time, we need to adjust the current configuration
- * back to something where this layout <b>is</b> a best match.
- */
- public void onAlternateLayoutCreated() {
- IFile best = ConfigurationMatcher.getBestFileMatch(this);
- if (best != null && !best.equals(mEditedFile)) {
- ConfigurationMatcher matcher = new ConfigurationMatcher(this);
- matcher.adaptConfigSelection(true /*needBestMatch*/);
- mConfiguration.syncFolderConfig();
- if (mClient != null) {
- mClient.changed(MASK_ALL);
- }
- }
- }
-
- /**
- * Loads the list of {@link Device}s and inits the UI with it.
- */
- private void initDevices() {
- final Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- DeviceManager manager = sdk.getDeviceManager();
- // This method can be called more than once, so avoid duplicate entries
- manager.unregisterListener(this);
- manager.registerListener(this);
- mDevices = manager.getDevices(DeviceManager.ALL_DEVICES);
- } else {
- mDevices = new ArrayList<Device>();
- }
- }
-
- /**
- * Loads the list of {@link IAndroidTarget} and inits the UI with it.
- */
- private boolean initTargets() {
- mTargetList.clear();
-
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget[] targets = currentSdk.getTargets();
- for (int i = 0 ; i < targets.length; i++) {
- if (targets[i].hasRenderingLibrary()) {
- mTargetList.add(targets[i]);
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- /** Ensures that the configuration has been initialized */
- public void ensureInitialized() {
- if (mConfiguration.getDevice() == null && mEditedFile != null) {
- String data = ConfigurationDescription.getDescription(mEditedFile);
- if (mInitialState != null) {
- data = mInitialState;
- mInitialState = null;
- }
- if (data != null) {
- mConfiguration.initialize(data);
- mConfiguration.syncFolderConfig();
- }
- }
- }
-
- private void updateDevices() {
- if (mDevices.size() == 0) {
- initDevices();
- }
- }
-
- private void updateTargets() {
- if (mTargetList.size() == 0) {
- if (!initTargets()) {
- return;
- }
- }
-
- IAndroidTarget renderingTarget = mConfiguration.getTarget();
-
- IAndroidTarget match = null;
- for (IAndroidTarget target : mTargetList) {
- if (renderingTarget != null) {
- // use equals because the rendering could be from a previous SDK, so
- // it may not be the same instance.
- if (renderingTarget.equals(target)) {
- match = target;
- }
- } else if (mProjectTarget == target) {
- match = target;
- }
-
- }
-
- if (match == null) {
- // the rendering target is the same as the project.
- renderingTarget = mProjectTarget;
- } else {
- // set the rendering target to the new object.
- renderingTarget = match;
- }
-
- mConfiguration.setTarget(renderingTarget, true);
- selectTarget(renderingTarget);
- }
-
- /** Update the toolbar whenever a label has changed, to not only
- * cause the layout in the current toolbar to update, but to possibly
- * wrap the toolbars and update the layout of the surrounding area.
- */
- private void resizeToolBar() {
- Point size = getSize();
- Point newSize = computeSize(size.x, SWT.DEFAULT, true);
- setSize(newSize);
- Composite parent = getParent();
- parent.layout();
- parent.redraw();
- }
-
-
- Image getOrientationIcon(ScreenOrientation orientation, boolean flip) {
- IconFactory icons = IconFactory.getInstance();
- switch (orientation) {
- case LANDSCAPE:
- return icons.getIcon(flip ? ICON_LANDSCAPE_FLIP : ICON_LANDSCAPE);
- case SQUARE:
- return icons.getIcon(ICON_SQUARE);
- case PORTRAIT:
- default:
- return icons.getIcon(flip ? ICON_PORTRAIT_FLIP : ICON_PORTRAIT);
- }
- }
-
- ImageDescriptor getOrientationImage(ScreenOrientation orientation, boolean flip) {
- IconFactory icons = IconFactory.getInstance();
- switch (orientation) {
- case LANDSCAPE:
- return icons.getImageDescriptor(flip ? ICON_LANDSCAPE_FLIP : ICON_LANDSCAPE);
- case SQUARE:
- return icons.getImageDescriptor(ICON_SQUARE);
- case PORTRAIT:
- default:
- return icons.getImageDescriptor(flip ? ICON_PORTRAIT_FLIP : ICON_PORTRAIT);
- }
- }
-
- @NonNull
- ScreenOrientation getOrientation(State state) {
- FolderConfiguration config = DeviceConfigHelper.getFolderConfig(state);
- ScreenOrientation orientation = null;
- if (config != null && config.getScreenOrientationQualifier() != null) {
- orientation = config.getScreenOrientationQualifier().getValue();
- }
-
- if (orientation == null) {
- orientation = ScreenOrientation.PORTRAIT;
- }
-
- return orientation;
- }
-
- /**
- * Stores the current config selection into the edited file such that we can
- * bring it back the next time this layout is opened.
- */
- public void saveConstraints() {
- String description = mConfiguration.toPersistentString();
- if (description != null && !description.isEmpty()) {
- ConfigurationDescription.setDescription(mEditedFile, description);
- }
- }
-
- // ---- Setting the current UI state ----
-
- void selectDeviceState(@Nullable State state) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- mOrientationCombo.setData(state);
-
- State nextState = mConfiguration.getNextDeviceState(state);
- mOrientationCombo.setImage(getOrientationIcon(getOrientation(state),
- nextState != state));
- } finally {
- mDisableUpdates--;
- }
- }
-
- void selectTarget(IAndroidTarget target) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- mTargetCombo.setData(target);
- String label = getRenderingTargetLabel(target, true);
- mTargetCombo.setText(label);
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
- }
-
- /**
- * Selects a given {@link Device} in the device combo, if it is found.
- * @param device the device to select
- * @return true if the device was found.
- */
- boolean selectDevice(@Nullable Device device) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- mDeviceCombo.setData(device);
- if (device != null) {
- mDeviceCombo.setText(getDeviceLabel(device, true));
- } else {
- mDeviceCombo.setText("Device");
- }
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
-
- return false;
- }
-
- void selectActivity(@Nullable String fqcn) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- if (fqcn != null) {
- mActivityCombo.setData(fqcn);
- String label = getActivityLabel(fqcn, true);
- mActivityCombo.setText(label);
- } else {
- mActivityCombo.setText("(Select)");
- }
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
- }
-
- void selectTheme(@Nullable String theme) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- assert theme == null || theme.startsWith(STYLE_RESOURCE_PREFIX)
- || theme.startsWith(ANDROID_STYLE_RESOURCE_PREFIX) : theme;
- mThemeCombo.setData(theme);
- if (theme != null) {
- mThemeCombo.setText(getThemeLabel(theme, true));
- } else {
- // FIXME eclipse claims this is dead code.
- mThemeCombo.setText("(Set Theme)");
- }
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
- }
-
- void selectLocale(@Nullable Locale locale) {
- assert isUiThread();
- try {
- mDisableUpdates++;
- mLocaleCombo.setData(locale);
- String label = Strings.nullToEmpty(getLocaleLabel(this, locale, true));
- mLocaleCombo.setText(label);
-
- Image image = getFlagImage(locale);
- mLocaleCombo.setImage(image);
-
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
- }
-
- @NonNull
- Image getFlagImage(@Nullable Locale locale) {
- if (locale != null) {
- return locale.getFlagImage();
- }
-
- return FlagManager.getGlobeIcon();
- }
-
- private void selectConfiguration(FolderConfiguration fileConfig) {
- /* For now, don't show any text in the configuration combo, use just an
- icon. This has the advantage that the configuration contents don't
- shift around, so you can for example click back and forth between
- portrait and landscape without the icon moving under the mouse.
- If this works well, remove this whole method post ADT 21.
- assert isUiThread();
- try {
- String current = mEditedFile.getParent().getName();
- if (current.equals(FD_RES_LAYOUT)) {
- current = "default";
- }
-
- // Pretty things up a bit
- //if (current == null || current.equals("default")) {
- // current = "Default Configuration";
- //}
- mConfigCombo.setText(current);
- resizeToolBar();
- } finally {
- mDisableUpdates--;
- }
- */
- }
-
- /**
- * Finds a locale matching the config from a file.
- *
- * @param language the language qualifier or null if none is set.
- * @param region the region qualifier or null if none is set.
- * @return true if there was a change in the combobox as a result of
- * applying the locale
- */
- private boolean setLocale(@Nullable Locale locale) {
- boolean changed = !Objects.equal(mConfiguration.getLocale(), locale);
- selectLocale(locale);
-
- return changed;
- }
-
- // ---- Creating UI labels ----
-
- /**
- * Returns a suitable label to use to display the given activity
- *
- * @param fqcn the activity class to look up a label for
- * @param brief if true, generate a brief label (suitable for a toolbar
- * button), otherwise a fuller name (suitable for a menu item)
- * @return the label
- */
- public static String getActivityLabel(String fqcn, boolean brief) {
- if (brief) {
- String label = fqcn;
- int packageIndex = label.lastIndexOf('.');
- if (packageIndex != -1) {
- label = label.substring(packageIndex + 1);
- }
- int innerClass = label.lastIndexOf('$');
- if (innerClass != -1) {
- label = label.substring(innerClass + 1);
- }
-
- // Also strip out the "Activity" or "Fragment" common suffix
- // if this is a long name
- if (label.endsWith("Activity") && label.length() > 8 + 12) { // 12 chars + 8 in suffix
- label = label.substring(0, label.length() - 8);
- } else if (label.endsWith("Fragment") && label.length() > 8 + 12) {
- label = label.substring(0, label.length() - 8);
- }
-
- return label;
- }
-
- return fqcn;
- }
-
- /**
- * Returns a suitable label to use to display the given theme
- *
- * @param theme the theme to produce a label for
- * @param brief if true, generate a brief label (suitable for a toolbar
- * button), otherwise a fuller name (suitable for a menu item)
- * @return the label
- */
- public static String getThemeLabel(String theme, boolean brief) {
- theme = ResourceHelper.styleToTheme(theme);
-
- if (brief) {
- int index = theme.lastIndexOf('.');
- if (index < theme.length() - 1) {
- return theme.substring(index + 1);
- }
- }
- return theme;
- }
-
- /**
- * Returns a suitable label to use to display the given rendering target
- *
- * @param target the target to produce a label for
- * @param brief if true, generate a brief label (suitable for a toolbar
- * button), otherwise a fuller name (suitable for a menu item)
- * @return the label
- */
- public static String getRenderingTargetLabel(IAndroidTarget target, boolean brief) {
- if (target == null) {
- return "<null>";
- }
-
- AndroidVersion version = target.getVersion();
-
- if (brief) {
- if (target.isPlatform()) {
- return Integer.toString(version.getApiLevel());
- } else {
- return target.getName() + ':' + Integer.toString(version.getApiLevel());
- }
- }
-
- String label = String.format("API %1$d: %2$s",
- version.getApiLevel(),
- target.getShortClasspathName());
-
- return label;
- }
-
- /**
- * Returns a suitable label to use to display the given device
- *
- * @param device the device to produce a label for
- * @param brief if true, generate a brief label (suitable for a toolbar
- * button), otherwise a fuller name (suitable for a menu item)
- * @return the label
- */
- public static String getDeviceLabel(@Nullable Device device, boolean brief) {
- if (device == null) {
- return "";
- }
- String name = device.getName();
-
- if (brief) {
- // Produce a really brief summary of the device name, suitable for
- // use in the narrow space available in the toolbar for example
- int nexus = name.indexOf("Nexus"); //$NON-NLS-1$
- if (nexus != -1) {
- int begin = name.indexOf('(');
- if (begin != -1) {
- begin++;
- int end = name.indexOf(')', begin);
- if (end != -1) {
- return name.substring(begin, end).trim();
- }
- }
- }
- }
-
- return name;
- }
-
- /**
- * Returns a suitable label to use to display the given locale
- *
- * @param chooser the chooser, if known
- * @param locale the locale to look up a label for
- * @param brief if true, generate a brief label (suitable for a toolbar
- * button), otherwise a fuller name (suitable for a menu item)
- * @return the label
- */
- @Nullable
- public static String getLocaleLabel(
- @Nullable ConfigurationChooser chooser,
- @Nullable Locale locale,
- boolean brief) {
- if (locale == null) {
- return null;
- }
-
- if (!locale.hasLanguage()) {
- if (brief) {
- // Just use the icon
- return "";
- }
-
- boolean hasLocale = false;
- ResourceRepository projectRes = chooser != null ? chooser.mClient.getProjectResources()
- : null;
- if (projectRes != null) {
- hasLocale = projectRes.getLanguages().size() > 0;
- }
-
- if (hasLocale) {
- return "Other";
- } else {
- return "Any";
- }
- }
-
- String languageCode = locale.qualifier.getLanguage();
- String languageName = LocaleManager.getLanguageName(languageCode);
-
- if (!locale.hasRegion()) {
- // TODO: Make the region string use "Other" instead of "Any" if
- // there is more than one region for a given language
- //if (regions.size() > 0) {
- // return String.format("%1$s / Other", language);
- //} else {
- // return String.format("%1$s / Any", language);
- //}
- if (!brief && languageName != null) {
- return String.format("%1$s (%2$s)", languageName, languageCode);
- } else {
- return languageCode;
- }
- } else {
- String regionCode = locale.qualifier.getRegion();
- if (!brief && languageName != null) {
- String regionName = LocaleManager.getRegionName(regionCode);
- if (regionName != null) {
- return String.format("%1$s (%2$s) in %3$s (%4$s)", languageName, languageCode,
- regionName, regionCode);
- }
- return String.format("%1$s (%2$s) in %3$s", languageName, languageCode,
- regionCode);
- }
- return String.format("%1$s / %2$s", languageCode, regionCode);
- }
- }
-
- // ---- Implements DevicesChangedListener ----
-
- @Override
- public void onDevicesChanged() {
- final Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- mDevices = sdk.getDeviceManager().getDevices(DeviceManager.ALL_DEVICES);
- } else {
- mDevices = new ArrayList<Device>();
- }
- }
-
- // ---- Reacting to UI changes ----
-
- /**
- * Called when the selection of the device combo changes.
- */
- void onDeviceChange() {
- // because changing the content of a combo triggers a change event, respect the
- // mDisableUpdates flag
- if (mDisableUpdates > 0) {
- return;
- }
-
- // Attempt to preserve the device state
- String stateName = null;
- Device prevDevice = mConfiguration.getDevice();
- State prevState = mConfiguration.getDeviceState();
- Device device = (Device) mDeviceCombo.getData();
- if (prevDevice != null && prevState != null && device != null) {
- // get the previous config, so that we can look for a close match
- FolderConfiguration oldConfig = DeviceConfigHelper.getFolderConfig(prevState);
- if (oldConfig != null) {
- stateName = ConfigurationMatcher.getClosestMatch(oldConfig, device.getAllStates());
- }
- }
- mConfiguration.setDevice(device, true);
- State newState = Configuration.getState(device, stateName);
- mConfiguration.setDeviceState(newState, true);
- selectDeviceState(newState);
- mConfiguration.syncFolderConfig();
-
- // Notify
- IFile file = mEditedFile;
- boolean accepted = mClient.changed(CFG_DEVICE | CFG_DEVICE_STATE);
- if (!accepted) {
- mConfiguration.setDevice(prevDevice, true);
- mConfiguration.setDeviceState(prevState, true);
- mConfiguration.syncFolderConfig();
- selectDevice(prevDevice);
- selectDeviceState(prevState);
- return;
- } else {
- syncToVariations(CFG_DEVICE | CFG_DEVICE_STATE, file, mConfiguration, false, true);
- }
-
- saveConstraints();
- }
-
- /**
- * Synchronizes changes to the given attributes (indicated by the mask
- * referencing the {@code CFG_} configuration attribute bit flags in
- * {@link Configuration} to the layout variations of the given updated file.
- *
- * @param flags the attributes which were updated
- * @param updatedFile the file which was updated
- * @param base the base configuration to base the chooser off of
- * @param includeSelf whether the updated file itself should be updated
- * @param async whether the updates should be performed asynchronously
- */
- public void syncToVariations(
- final int flags,
- final @NonNull IFile updatedFile,
- final @NonNull Configuration base,
- final boolean includeSelf,
- boolean async) {
- if (async) {
- getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- doSyncToVariations(flags, updatedFile, includeSelf, base);
- }
- });
- } else {
- doSyncToVariations(flags, updatedFile, includeSelf, base);
- }
- }
-
- private void doSyncToVariations(int flags, IFile updatedFile, boolean includeSelf,
- Configuration base) {
- // Synchronize the given changes to other configurations as well
- List<IFile> files = AdtUtils.getResourceVariations(updatedFile, includeSelf);
- for (IFile file : files) {
- Configuration configuration = Configuration.create(base, file);
- configuration.setTheme(base.getTheme());
- configuration.setActivity(base.getActivity());
- Collection<IEditorPart> editors = AdtUtils.findEditorsFor(file, false);
- boolean found = false;
- for (IEditorPart editor : editors) {
- if (editor instanceof CommonXmlEditor) {
- CommonXmlDelegate delegate = ((CommonXmlEditor) editor).getDelegate();
- if (delegate instanceof LayoutEditorDelegate) {
- editor = ((LayoutEditorDelegate) delegate).getGraphicalEditor();
- }
- }
- if (editor instanceof GraphicalEditorPart) {
- ConfigurationChooser chooser =
- ((GraphicalEditorPart) editor).getConfigurationChooser();
- chooser.setConfiguration(configuration);
- found = true;
- }
- }
- if (!found) {
- // Just update the file persistence
- String description = configuration.toPersistentString();
- ConfigurationDescription.setDescription(file, description);
- }
- }
- }
-
- /**
- * Called when the device config selection changes.
- */
- void onDeviceConfigChange() {
- // because changing the content of a combo triggers a change event, respect the
- // mDisableUpdates flag
- if (mDisableUpdates > 0) {
- return;
- }
-
- State prev = mConfiguration.getDeviceState();
- State state = (State) mOrientationCombo.getData();
- mConfiguration.setDeviceState(state, false);
-
- if (mClient != null) {
- boolean accepted = mClient.changed(CFG_DEVICE | CFG_DEVICE_STATE);
- if (!accepted) {
- mConfiguration.setDeviceState(prev, false);
- selectDeviceState(prev);
- return;
- }
- }
-
- saveConstraints();
- }
-
- /**
- * Call back for language combo selection
- */
- void onLocaleChange() {
- // because mLocaleList triggers onLocaleChange at each modification, the filling
- // of the combo with data will trigger notifications, and we don't want that.
- if (mDisableUpdates > 0) {
- return;
- }
-
- Locale prev = mConfiguration.getLocale();
- Locale locale = (Locale) mLocaleCombo.getData();
- if (locale == null) {
- locale = Locale.ANY;
- }
- mConfiguration.setLocale(locale, false);
-
- if (mClient != null) {
- boolean accepted = mClient.changed(CFG_LOCALE);
- if (!accepted) {
- mConfiguration.setLocale(prev, false);
- selectLocale(prev);
- }
- }
-
- // Store locale project-wide setting
- mConfiguration.saveRenderState();
- }
-
-
- void onThemeChange() {
- if (mDisableUpdates > 0) {
- return;
- }
-
- String prev = mConfiguration.getTheme();
- mConfiguration.setTheme((String) mThemeCombo.getData());
-
- if (mClient != null) {
- boolean accepted = mClient.changed(CFG_THEME);
- if (!accepted) {
- mConfiguration.setTheme(prev);
- selectTheme(prev);
- return;
- } else {
- syncToVariations(CFG_DEVICE|CFG_DEVICE_STATE, mEditedFile, mConfiguration,
- false, true);
- }
- }
-
- saveConstraints();
- }
-
- void notifyFolderConfigChanged() {
- if (mDisableUpdates > 0 || mClient == null) {
- return;
- }
-
- if (mClient.changed(CFG_FOLDER)) {
- saveConstraints();
- }
- }
-
- void onSelectActivity() {
- if (mDisableUpdates > 0) {
- return;
- }
-
- String activity = (String) mActivityCombo.getData();
- mConfiguration.setActivity(activity);
-
- if (activity == null) {
- return;
- }
-
- // See if there is a default theme assigned to this activity, and if so, use it
- ManifestInfo manifest = ManifestInfo.get(mEditedFile.getProject());
- String preferred = null;
- ActivityAttributes attributes = manifest.getActivityAttributes(activity);
- if (attributes != null) {
- preferred = attributes.getTheme();
- }
- if (preferred != null && !Objects.equal(preferred, mConfiguration.getTheme())) {
- // Yes, switch to it
- selectTheme(preferred);
- onThemeChange();
- }
-
- // Persist in XML
- if (mClient != null) {
- mClient.setActivity(activity);
- }
-
- saveConstraints();
- }
-
- /**
- * Call back for api level combo selection
- */
- void onRenderingTargetChange() {
- // because mApiCombo triggers onApiLevelChange at each modification, the filling
- // of the combo with data will trigger notifications, and we don't want that.
- if (mDisableUpdates > 0) {
- return;
- }
-
- IAndroidTarget prevTarget = mConfiguration.getTarget();
- String prevTheme = mConfiguration.getTheme();
-
- int changeFlags = 0;
-
- // tell the listener a new rendering target is being set. Need to do this before updating
- // mRenderingTarget.
- if (prevTarget != null) {
- changeFlags |= CFG_TARGET;
- mClient.aboutToChange(changeFlags);
- }
-
- IAndroidTarget target = (IAndroidTarget) mTargetCombo.getData();
- mConfiguration.setTarget(target, true);
-
- // force a theme update to reflect the new rendering target.
- // This must be done after computeCurrentConfig since it'll depend on the currentConfig
- // to figure out the theme list.
- String oldTheme = mConfiguration.getTheme();
- updateThemes();
- // updateThemes may change the theme (based on theme availability in the new rendering
- // target) so mark theme change if necessary
- if (!Objects.equal(oldTheme, mConfiguration.getTheme())) {
- changeFlags |= CFG_THEME;
- }
-
- if (target != null) {
- changeFlags |= CFG_TARGET;
- changeFlags |= CFG_FOLDER; // In case we added a -vNN qualifier
- }
-
- // Store project-wide render-target setting
- mConfiguration.saveRenderState();
-
- mConfiguration.syncFolderConfig();
-
- if (mClient != null) {
- boolean accepted = mClient.changed(changeFlags);
- if (!accepted) {
- mConfiguration.setTarget(prevTarget, true);
- mConfiguration.setTheme(prevTheme);
- mConfiguration.syncFolderConfig();
- selectTheme(prevTheme);
- selectTarget(prevTarget);
- }
- }
- }
-
- /**
- * Syncs this configuration to the project wide locale and render target settings. The
- * locale may ignore the project-wide setting if it is a locale-specific
- * configuration.
- *
- * @return true if one or both of the toggles were changed, false if there were no
- * changes
- */
- public boolean syncRenderState() {
- if (mConfiguration.getEditedConfig() == null) {
- // Startup; ignore
- return false;
- }
-
- boolean renderTargetChanged = false;
-
- // When a page is re-activated, force the toggles to reflect the current project
- // state
-
- Pair<Locale, IAndroidTarget> pair = Configuration.loadRenderState(this);
-
- int changeFlags = 0;
- // Only sync the locale if this layout is not already a locale-specific layout!
- if (pair != null && !mConfiguration.isLocaleSpecificLayout()) {
- Locale locale = pair.getFirst();
- if (locale != null) {
- boolean localeChanged = setLocale(locale);
- if (localeChanged) {
- changeFlags |= CFG_LOCALE;
- }
- } else {
- locale = Locale.ANY;
- }
- mConfiguration.setLocale(locale, true);
- }
-
- // Sync render target
- IAndroidTarget configurationTarget = mConfiguration.getTarget();
- IAndroidTarget target = pair != null ? pair.getSecond() : configurationTarget;
- if (target != null && configurationTarget != target) {
- if (mClient != null && configurationTarget != null) {
- changeFlags |= CFG_TARGET;
- mClient.aboutToChange(changeFlags);
- }
-
- mConfiguration.setTarget(target, true);
- selectTarget(target);
- renderTargetChanged = true;
- }
-
- // Neither locale nor render target changed: nothing to do
- if (changeFlags == 0) {
- return false;
- }
-
- // Update the locale and/or the render target. This code contains a logical
- // merge of the onRenderingTargetChange() and onLocaleChange() methods, combined
- // such that we don't duplicate work.
-
- // Compute the new configuration; we want to do this both for locale changes
- // and for render targets.
- mConfiguration.syncFolderConfig();
- changeFlags |= CFG_FOLDER; // in case we added/remove a -v<NN> qualifier
-
- if (renderTargetChanged) {
- // force a theme update to reflect the new rendering target.
- // This must be done after computeCurrentConfig since it'll depend on the currentConfig
- // to figure out the theme list.
- updateThemes();
- }
-
- if (mClient != null) {
- mClient.changed(changeFlags);
- }
-
- return true;
- }
-
- // ---- Populate data structures with themes, locales, etc ----
-
- /**
- * Updates the internal list of themes.
- */
- private void updateThemes() {
- if (mClient == null) {
- return; // can't do anything without it.
- }
-
- ResourceRepository frameworkRes = mClient.getFrameworkResources(
- mConfiguration.getTarget());
-
- mDisableUpdates++;
-
- try {
- if (mEditedFile != null) {
- String theme = mConfiguration.getTheme();
- if (theme == null || theme.isEmpty() || mClient.getIncludedWithin() != null) {
- mConfiguration.setTheme(null);
- mConfiguration.computePreferredTheme();
- }
- assert mConfiguration.getTheme() != null;
- }
-
- mThemeList.clear();
-
- ArrayList<String> themes = new ArrayList<String>();
- ResourceRepository projectRes = mClient.getProjectResources();
- // in cases where the opened file is not linked to a project, this could be null.
- if (projectRes != null) {
- // get the configured resources for the project
- Map<ResourceType, Map<String, ResourceValue>> configuredProjectRes =
- mClient.getConfiguredProjectResources();
-
- if (configuredProjectRes != null) {
- // get the styles.
- Map<String, ResourceValue> styleMap = configuredProjectRes.get(
- ResourceType.STYLE);
-
- if (styleMap != null) {
- // collect the themes out of all the styles, ie styles that extend,
- // directly or indirectly a platform theme.
- for (ResourceValue value : styleMap.values()) {
- if (isTheme(value, styleMap, null)) {
- String theme = value.getName();
- themes.add(theme);
- }
- }
-
- Collections.sort(themes);
-
- for (String theme : themes) {
- if (!theme.startsWith(PREFIX_RESOURCE_REF)) {
- theme = STYLE_RESOURCE_PREFIX + theme;
- }
- mThemeList.add(theme);
- }
- }
- }
- themes.clear();
- }
-
- // get the themes, and languages from the Framework.
- if (frameworkRes != null) {
- // get the configured resources for the framework
- Map<ResourceType, Map<String, ResourceValue>> frameworResources =
- frameworkRes.getConfiguredResources(mConfiguration.getFullConfig());
-
- if (frameworResources != null) {
- // get the styles.
- Map<String, ResourceValue> styles = frameworResources.get(ResourceType.STYLE);
-
- // collect the themes out of all the styles.
- for (ResourceValue value : styles.values()) {
- String name = value.getName();
- if (name.startsWith("Theme.") || name.equals("Theme")) { //$NON-NLS-1$ //$NON-NLS-2$
- themes.add(value.getName());
- }
- }
-
- // sort them and add them to the combo
- Collections.sort(themes);
-
- for (String theme : themes) {
- if (!theme.startsWith(PREFIX_RESOURCE_REF)) {
- theme = ANDROID_STYLE_RESOURCE_PREFIX + theme;
- }
- mThemeList.add(theme);
- }
-
- themes.clear();
- }
- }
-
- // Migration: In the past we didn't store the style prefix in the settings;
- // this meant we might lose track of whether the theme is a project style
- // or a framework style. For now we need to migrate. Search through the
- // theme list until we have a match
- String theme = mConfiguration.getTheme();
- if (theme != null && !theme.startsWith(PREFIX_RESOURCE_REF)) {
- String projectStyle = STYLE_RESOURCE_PREFIX + theme;
- String frameworkStyle = ANDROID_STYLE_RESOURCE_PREFIX + theme;
- for (String t : mThemeList) {
- if (t.equals(projectStyle)) {
- mConfiguration.setTheme(projectStyle);
- break;
- } else if (t.equals(frameworkStyle)) {
- mConfiguration.setTheme(frameworkStyle);
- break;
- }
- }
- if (!theme.startsWith(PREFIX_RESOURCE_REF)) {
- // Arbitrary guess
- if (theme.startsWith("Theme.")) {
- theme = ANDROID_STYLE_RESOURCE_PREFIX + theme;
- } else {
- theme = STYLE_RESOURCE_PREFIX + theme;
- }
- }
- }
-
- // TODO: Handle the case where you have a theme persisted that isn't available??
- // We could look up mConfiguration.theme and make sure it appears in the list! And if
- // not, picking one.
- selectTheme(mConfiguration.getTheme());
- } finally {
- mDisableUpdates--;
- }
- }
-
- private void updateActivity() {
- if (mEditedFile != null) {
- String preferred = getPreferredActivity(mEditedFile);
- selectActivity(preferred);
- }
- }
-
- /**
- * Updates the locale combo.
- * This must be called from the UI thread.
- */
- public void updateLocales() {
- if (mClient == null) {
- return; // can't do anything w/o it.
- }
-
- mDisableUpdates++;
-
- try {
- mLocaleList.clear();
-
- SortedSet<String> languages = null;
-
- // get the languages from the project.
- ResourceRepository projectRes = mClient.getProjectResources();
-
- // in cases where the opened file is not linked to a project, this could be null.
- if (projectRes != null) {
- // now get the languages from the project.
- languages = projectRes.getLanguages();
-
- for (String language : languages) {
- // find the matching regions and add them
- SortedSet<String> regions = projectRes.getRegions(language);
- for (String region : regions) {
- LocaleQualifier locale = LocaleQualifier.getQualifier(language + "-r" + region);
- if (locale != null) {
- mLocaleList.add(Locale.create(locale));
- }
- }
-
- // now the entry for the other regions the language alone
- // create a region qualifier that will never be matched by qualified resources.
- LocaleQualifier locale = new LocaleQualifier(language);
- mLocaleList.add(Locale.create(locale));
- }
- }
-
- // create language/region qualifier that will never be matched by qualified resources.
- mLocaleList.add(Locale.ANY);
-
- Locale locale = mConfiguration.getLocale();
- setLocale(locale);
- } finally {
- mDisableUpdates--;
- }
- }
-
- @Nullable
- private String getPreferredActivity(@NonNull IFile file) {
- // Store/restore the activity context in the config state to help with
- // performance if for some reason we can't write it into the XML file and to
- // avoid having to open the model below
- if (mConfiguration.getActivity() != null) {
- return mConfiguration.getActivity();
- }
-
- IProject project = file.getProject();
-
- // Look up from XML file
- Document document = DomUtilities.getDocument(file);
- if (document != null) {
- Element element = document.getDocumentElement();
- if (element != null) {
- String activity = element.getAttributeNS(TOOLS_URI, ATTR_CONTEXT);
- if (activity != null && !activity.isEmpty()) {
- if (activity.startsWith(".") || activity.indexOf('.') == -1) { //$NON-NLS-1$
- ManifestInfo manifest = ManifestInfo.get(project);
- String pkg = manifest.getPackage();
- if (!pkg.isEmpty()) {
- if (activity.startsWith(".")) { //$NON-NLS-1$
- activity = pkg + activity;
- } else {
- activity = activity + '.' + pkg;
- }
- }
- }
-
- mConfiguration.setActivity(activity);
- saveConstraints();
- return activity;
- }
- }
- }
-
- // No, not available there: try to infer it from the code index
- String includedIn = null;
- Reference includedWithin = mClient.getIncludedWithin();
- if (mClient != null && includedWithin != null) {
- includedIn = includedWithin.getName();
- }
-
- ManifestInfo manifest = ManifestInfo.get(project);
- String pkg = manifest.getPackage();
- String layoutName = ResourceHelper.getLayoutName(mEditedFile);
-
- // If we are rendering a layout in included context, pick the theme
- // from the outer layout instead
- if (includedIn != null) {
- layoutName = includedIn;
- }
-
- String activity = ManifestInfo.guessActivity(project, layoutName, pkg);
-
- if (activity == null) {
- List<String> activities = ManifestInfo.getProjectActivities(project);
- if (activities.size() == 1) {
- activity = activities.get(0);
- }
- }
-
- if (activity != null) {
- mConfiguration.setActivity(activity);
- saveConstraints();
- return activity;
- }
-
- // TODO: Do anything else, such as pick the first activity found?
- // Or just leave some default label instead?
- // Also, figure out what to store in the mState so I don't keep trying
-
- return null;
- }
-
- /**
- * Returns whether the given <var>style</var> is a theme.
- * This is done by making sure the parent is a theme.
- * @param value the style to check
- * @param styleMap the map of styles for the current project. Key is the style name.
- * @param seen the map of styles we have already processed (or null if not yet
- * initialized). Only the keys are significant (since there is no IdentityHashSet).
- * @return True if the given <var>style</var> is a theme.
- */
- private static boolean isTheme(ResourceValue value, Map<String, ResourceValue> styleMap,
- IdentityHashMap<ResourceValue, Boolean> seen) {
- if (value instanceof StyleResourceValue) {
- StyleResourceValue style = (StyleResourceValue)value;
-
- boolean frameworkStyle = false;
- String parentStyle = style.getParentStyle();
- if (parentStyle == null) {
- // if there is no specified parent style we look an implied one.
- // For instance 'Theme.light' is implied child style of 'Theme',
- // and 'Theme.light.fullscreen' is implied child style of 'Theme.light'
- String name = style.getName();
- int index = name.lastIndexOf('.');
- if (index != -1) {
- parentStyle = name.substring(0, index);
- }
- } else {
- // remove the useless @ if it's there
- if (parentStyle.startsWith("@")) {
- parentStyle = parentStyle.substring(1);
- }
-
- // check for framework identifier.
- if (parentStyle.startsWith(ANDROID_NS_NAME_PREFIX)) {
- frameworkStyle = true;
- parentStyle = parentStyle.substring(ANDROID_NS_NAME_PREFIX.length());
- }
-
- // at this point we could have the format style/<name>. we want only the name
- if (parentStyle.startsWith("style/")) {
- parentStyle = parentStyle.substring("style/".length());
- }
- }
-
- if (parentStyle != null) {
- if (frameworkStyle) {
- // if the parent is a framework style, it has to be 'Theme' or 'Theme.*'
- return parentStyle.equals("Theme") || parentStyle.startsWith("Theme.");
- } else {
- // if it's a project style, we check this is a theme.
- ResourceValue parentValue = styleMap.get(parentStyle);
-
- // also prevent stack overflow in case the dev mistakenly declared
- // the parent of the style as the style itself.
- if (parentValue != null && !parentValue.equals(value)) {
- if (seen == null) {
- seen = new IdentityHashMap<ResourceValue, Boolean>();
- seen.put(value, Boolean.TRUE);
- } else if (seen.containsKey(parentValue)) {
- return false;
- }
- seen.put(parentValue, Boolean.TRUE);
- return isTheme(parentValue, styleMap, seen);
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if this configuration chooser represents the best match for
- * the given file
- *
- * @param file the file to test
- * @param config the config to test
- * @return true if the given config is the best match for the given file
- */
- public boolean isBestMatchFor(IFile file, FolderConfiguration config) {
- ResourceFile match = mResources.getMatchingFile(mEditedFile.getName(),
- ResourceType.LAYOUT, config);
- if (match != null) {
- return match.getFile().equals(mEditedFile);
- }
-
- return false;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationClient.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationClient.java
deleted file mode 100644
index 3df2feda3..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationClient.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * 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.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ResourceRepository;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
-import com.android.resources.ResourceType;
-import com.android.sdklib.IAndroidTarget;
-
-import java.util.Map;
-
-/**
- * Interface implemented by clients who embed a {@link ConfigurationChooser}.
- */
-public interface ConfigurationClient {
- /**
- * The configuration is about to be changed.
- *
- * @param flags details about what changed; consult the {@code CFG_} flags
- * in {@link Configuration} such as
- * {@link Configuration#CFG_DEVICE},
- * {@link Configuration#CFG_LOCALE}, etc.
- */
- void aboutToChange(int flags);
-
- /**
- * The configuration has changed. If the client returns false, it means that
- * the change was rejected. This typically means that changing the
- * configuration in this particular way makes a configuration which has a
- * better file match than the current client's file, so it will open that
- * file to edit the new configuration -- and the current configuration
- * should go back to editing the state prior to this change.
- *
- * @param flags details about what changed; consult the {@code CFG_} flags
- * such as {@link Configuration#CFG_DEVICE},
- * {@link Configuration#CFG_LOCALE}, etc.
- * @return true if the change was accepted, false if it was rejected.
- */
- boolean changed(int flags);
-
- /**
- * Compute the project resources
- *
- * @return the project resources as a {@link ResourceRepository}
- */
- @Nullable
- ResourceRepository getProjectResources();
-
- /**
- * Compute the framework resources
- *
- * @return the project resources as a {@link ResourceRepository}
- */
- @Nullable
- ResourceRepository getFrameworkResources();
-
- /**
- * Compute the framework resources for the given Android API target
- *
- * @param target the target to look up framework resources for
- * @return the project resources as a {@link ResourceRepository}
- */
- @Nullable
- ResourceRepository getFrameworkResources(@Nullable IAndroidTarget target);
-
- /**
- * Returns the configured project resources for the current file and
- * configuration
- *
- * @return resource type maps to names to resource values
- */
- @NonNull
- Map<ResourceType, Map<String, ResourceValue>> getConfiguredProjectResources();
-
- /**
- * Returns the configured framework resources for the current file and
- * configuration
- *
- * @return resource type maps to names to resource values
- */
- @NonNull
- Map<ResourceType, Map<String, ResourceValue>> getConfiguredFrameworkResources();
-
- /**
- * If the current layout is an included layout rendered within an outer layout,
- * returns the outer layout.
- *
- * @return the outer including layout, or null
- */
- @Nullable
- Reference getIncludedWithin();
-
- /**
- * Called when the "Create" button is clicked.
- */
- void createConfigFile();
-
- /**
- * Called when an associated activity is picked
- *
- * @param fqcn the fully qualified class name for the associated activity context
- */
- void setActivity(@NonNull String fqcn);
-
- /**
- * Returns the associated layout canvas, if any
- *
- * @return the canvas, if any
- */
- @Nullable
- LayoutCanvas getCanvas();
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationDescription.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationDescription.java
deleted file mode 100644
index 956ac1839..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationDescription.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_THEME;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.resources.ResourceRepository;
-import com.android.ide.common.resources.configuration.DeviceConfigHelper;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo.ActivityAttributes;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.NightMode;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ScreenSize;
-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.Splitter;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.QualifiedName;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.util.Collection;
-import java.util.List;
-
-/** A description of a configuration, used for persistence */
-public class ConfigurationDescription {
- private static final String TAG_PREVIEWS = "previews"; //$NON-NLS-1$
- private static final String TAG_PREVIEW = "preview"; //$NON-NLS-1$
- private static final String ATTR_TARGET = "target"; //$NON-NLS-1$
- private static final String ATTR_CONFIG = "config"; //$NON-NLS-1$
- private static final String ATTR_LOCALE = "locale"; //$NON-NLS-1$
- private static final String ATTR_ACTIVITY = "activity"; //$NON-NLS-1$
- private static final String ATTR_DEVICE = "device"; //$NON-NLS-1$
- private static final String ATTR_STATE = "devicestate"; //$NON-NLS-1$
- private static final String ATTR_UIMODE = "ui"; //$NON-NLS-1$
- private static final String ATTR_NIGHTMODE = "night"; //$NON-NLS-1$
- private final static String SEP_LOCALE = "-"; //$NON-NLS-1$
-
- /**
- * Settings name for file-specific configuration preferences, such as which theme or
- * device to render the current layout with
- */
- public final static QualifiedName NAME_CONFIG_STATE =
- new QualifiedName(AdtPlugin.PLUGIN_ID, "state");//$NON-NLS-1$
-
- /** The project corresponding to this configuration's description */
- public final IProject project;
-
- /** The display name */
- public String displayName;
-
- /** The theme */
- public String theme;
-
- /** The target */
- public IAndroidTarget target;
-
- /** The display name */
- public FolderConfiguration folder;
-
- /** The locale */
- public Locale locale = Locale.ANY;
-
- /** The device */
- public Device device;
-
- /** The device state */
- public State state;
-
- /** The activity */
- public String activity;
-
- /** UI mode */
- @NonNull
- public UiMode uiMode = UiMode.NORMAL;
-
- /** Night mode */
- @NonNull
- public NightMode nightMode = NightMode.NOTNIGHT;
-
- private ConfigurationDescription(@Nullable IProject project) {
- this.project = project;
- }
-
- /**
- * Returns the persistent configuration description from the given file
- *
- * @param file the file to look up a description from
- * @return the description or null if never written
- */
- @Nullable
- public static String getDescription(@NonNull IFile file) {
- return AdtPlugin.getFileProperty(file, NAME_CONFIG_STATE);
- }
-
- /**
- * Sets the persistent configuration description data for the given file
- *
- * @param file the file to associate the description with
- * @param description the description
- */
- public static void setDescription(@NonNull IFile file, @NonNull String description) {
- AdtPlugin.setFileProperty(file, NAME_CONFIG_STATE, description);
- }
-
- /**
- * Creates a description from a given configuration
- *
- * @param project the project for this configuration's description
- * @param configuration the configuration to describe
- * @return a new configuration
- */
- public static ConfigurationDescription fromConfiguration(
- @Nullable IProject project,
- @NonNull Configuration configuration) {
- ConfigurationDescription description = new ConfigurationDescription(project);
- description.displayName = configuration.getDisplayName();
- description.theme = configuration.getTheme();
- description.target = configuration.getTarget();
- description.folder = new FolderConfiguration();
- description.folder.set(configuration.getFullConfig());
- description.locale = configuration.getLocale();
- description.device = configuration.getDevice();
- description.state = configuration.getDeviceState();
- description.activity = configuration.getActivity();
- return description;
- }
-
- /**
- * Initializes a string previously created with
- * {@link #toXml(Document)}
- *
- * @param project the project for this configuration's description
- * @param element the element to read back from
- * @param deviceList list of available devices
- * @return true if the configuration was initialized
- */
- @Nullable
- public static ConfigurationDescription fromXml(
- @Nullable IProject project,
- @NonNull Element element,
- @NonNull Collection<Device> deviceList) {
- ConfigurationDescription description = new ConfigurationDescription(project);
-
- if (!TAG_PREVIEW.equals(element.getTagName())) {
- return null;
- }
-
- String displayName = element.getAttribute(ATTR_NAME);
- if (!displayName.isEmpty()) {
- description.displayName = displayName;
- }
-
- String config = element.getAttribute(ATTR_CONFIG);
- Iterable<String> segments = Splitter.on('-').split(config);
- description.folder = FolderConfiguration.getConfig(segments);
-
- String theme = element.getAttribute(ATTR_THEME);
- if (!theme.isEmpty()) {
- description.theme = theme;
- }
-
- String targetId = element.getAttribute(ATTR_TARGET);
- if (!targetId.isEmpty()) {
- IAndroidTarget target = Configuration.stringToTarget(targetId);
- description.target = target;
- }
-
- String localeString = element.getAttribute(ATTR_LOCALE);
- if (!localeString.isEmpty()) {
- // Load locale. Note that this can get overwritten by the
- // project-wide settings read below.
- String locales[] = localeString.split(SEP_LOCALE);
- if (locales[0].length() > 0 && !LocaleQualifier.FAKE_VALUE.equals(locales[0])) {
- String language = locales[0];
- if (locales.length >= 2 && locales[1].length() > 0 && !LocaleQualifier.FAKE_VALUE.equals(locales[1])) {
- description.locale = Locale.create(LocaleQualifier.getQualifier(language + "-r" + locales[1]));
- } else {
- description.locale = Locale.create(new LocaleQualifier(language));
- }
- } else {
- description.locale = Locale.ANY;
- }
-
-
- }
-
- String activity = element.getAttribute(ATTR_ACTIVITY);
- if (activity.isEmpty()) {
- activity = null;
- }
-
- String deviceString = element.getAttribute(ATTR_DEVICE);
- if (!deviceString.isEmpty()) {
- for (Device d : deviceList) {
- if (d.getName().equals(deviceString)) {
- description.device = d;
- String stateName = element.getAttribute(ATTR_STATE);
- if (stateName.isEmpty() || stateName.equals("null")) {
- description.state = Configuration.getState(d, stateName);
- } else if (d.getAllStates().size() > 0) {
- description.state = d.getAllStates().get(0);
- }
- break;
- }
- }
- }
-
- String uiModeString = element.getAttribute(ATTR_UIMODE);
- if (!uiModeString.isEmpty()) {
- description.uiMode = UiMode.getEnum(uiModeString);
- if (description.uiMode == null) {
- description.uiMode = UiMode.NORMAL;
- }
- }
-
- String nightModeString = element.getAttribute(ATTR_NIGHTMODE);
- if (!nightModeString.isEmpty()) {
- description.nightMode = NightMode.getEnum(nightModeString);
- if (description.nightMode == null) {
- description.nightMode = NightMode.NOTNIGHT;
- }
- }
-
-
- // Should I really be storing the FULL configuration? Might be trouble if
- // you bring a different device
-
- return description;
- }
-
- /**
- * Write this description into the given document as a new element.
- *
- * @param document the document to add the description to
- * @return the newly inserted element
- */
- @NonNull
- public Element toXml(Document document) {
- Element element = document.createElement(TAG_PREVIEW);
-
- element.setAttribute(ATTR_NAME, displayName);
- FolderConfiguration fullConfig = folder;
- String folderName = fullConfig.getFolderName(ResourceFolderType.LAYOUT);
- element.setAttribute(ATTR_CONFIG, folderName);
- if (theme != null) {
- element.setAttribute(ATTR_THEME, theme);
- }
- if (target != null) {
- element.setAttribute(ATTR_TARGET, Configuration.targetToString(target));
- }
-
- if (locale != null && (locale.hasLanguage() || locale.hasRegion())) {
- String value;
- if (locale.hasRegion()) {
- value = locale.qualifier.getLanguage() + SEP_LOCALE + locale.qualifier.getRegion();
- } else {
- value = locale.qualifier.getLanguage();
- }
- element.setAttribute(ATTR_LOCALE, value);
- }
-
- if (device != null) {
- element.setAttribute(ATTR_DEVICE, device.getName());
- if (state != null) {
- element.setAttribute(ATTR_STATE, state.getName());
- }
- }
-
- if (activity != null) {
- element.setAttribute(ATTR_ACTIVITY, activity);
- }
-
- if (uiMode != null && uiMode != UiMode.NORMAL) {
- element.setAttribute(ATTR_UIMODE, uiMode.getResourceValue());
- }
-
- if (nightMode != null && nightMode != NightMode.NOTNIGHT) {
- element.setAttribute(ATTR_NIGHTMODE, nightMode.getResourceValue());
- }
-
- Element parent = document.getDocumentElement();
- if (parent == null) {
- parent = document.createElement(TAG_PREVIEWS);
- document.appendChild(parent);
- }
- parent.appendChild(element);
-
- return element;
- }
-
- /** Returns the preferred theme, or null */
- @Nullable
- String computePreferredTheme() {
- if (project == null) {
- return "Theme";
- }
- ManifestInfo manifest = ManifestInfo.get(project);
-
- // Look up the screen size for the current state
- ScreenSize screenSize = null;
- if (device != null) {
- List<State> states = device.getAllStates();
- for (State s : states) {
- FolderConfiguration folderConfig = DeviceConfigHelper.getFolderConfig(s);
- if (folderConfig != null) {
- ScreenSizeQualifier qualifier = folderConfig.getScreenSizeQualifier();
- screenSize = qualifier.getValue();
- break;
- }
- }
- }
-
- // Look up the default/fallback theme to use for this project (which
- // depends on the screen size when no particular theme is specified
- // in the manifest)
- String defaultTheme = manifest.getDefaultTheme(target, screenSize);
-
- String preferred = defaultTheme;
- if (theme == null) {
- // If we are rendering a layout in included context, pick the theme
- // from the outer layout instead
-
- if (activity != null) {
- ActivityAttributes attributes = manifest.getActivityAttributes(activity);
- if (attributes != null) {
- preferred = attributes.getTheme();
- }
- }
- if (preferred == null) {
- preferred = defaultTheme;
- }
- theme = preferred;
- }
-
- return preferred;
- }
-
- private void checkThemePrefix() {
- if (theme != null && !theme.startsWith(PREFIX_RESOURCE_REF)) {
- if (theme.isEmpty()) {
- computePreferredTheme();
- return;
- }
-
- if (target != null) {
- Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- AndroidTargetData data = sdk.getTargetData(target);
-
- if (data != null) {
- ResourceRepository resources = data.getFrameworkResources();
- if (resources != null
- && resources.hasResourceItem(ANDROID_STYLE_RESOURCE_PREFIX + theme)) {
- theme = ANDROID_STYLE_RESOURCE_PREFIX + theme;
- return;
- }
- }
- }
- }
-
- theme = STYLE_RESOURCE_PREFIX + theme;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMatcher.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMatcher.java
deleted file mode 100644
index 9724d4015..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMatcher.java
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * 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.ResourceFile;
-import com.android.ide.common.resources.configuration.DensityQualifier;
-import com.android.ide.common.resources.configuration.DeviceConfigHelper;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-import com.android.ide.common.resources.configuration.NightModeQualifier;
-import com.android.ide.common.resources.configuration.ResourceQualifier;
-import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
-import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
-import com.android.ide.common.resources.configuration.UiModeQualifier;
-import com.android.ide.common.resources.configuration.VersionQualifier;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.ide.eclipse.adt.io.IFileWrapper;
-import com.android.resources.Density;
-import com.android.resources.NightMode;
-import com.android.resources.ResourceType;
-import com.android.resources.ScreenOrientation;
-import com.android.resources.ScreenSize;
-import com.android.resources.UiMode;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.State;
-import com.android.sdklib.repository.PkgProps;
-import com.android.utils.Pair;
-import com.android.utils.SparseIntArray;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.ui.IEditorPart;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Produces matches for configurations
- * <p>
- * See algorithm described here:
- * http://developer.android.com/guide/topics/resources/providing-resources.html
- */
-public class ConfigurationMatcher {
- private static final boolean PREFER_RECENT_RENDER_TARGETS = true;
-
- private final ConfigurationChooser mConfigChooser;
- private final Configuration mConfiguration;
- private final IFile mEditedFile;
- private final ProjectResources mResources;
- private final boolean mUpdateUi;
-
- ConfigurationMatcher(ConfigurationChooser chooser) {
- this(chooser, chooser.getConfiguration(), chooser.getEditedFile(),
- chooser.getResources(), true);
- }
-
- ConfigurationMatcher(
- @NonNull ConfigurationChooser chooser,
- @NonNull Configuration configuration,
- @Nullable IFile editedFile,
- @Nullable ProjectResources resources,
- boolean updateUi) {
- mConfigChooser = chooser;
- mConfiguration = configuration;
- mEditedFile = editedFile;
- mResources = resources;
- mUpdateUi = updateUi;
- }
-
- // ---- Finding matching configurations ----
-
- private static class ConfigBundle {
- private final FolderConfiguration config;
- private int localeIndex;
- private int dockModeIndex;
- private int nightModeIndex;
-
- private ConfigBundle() {
- config = new FolderConfiguration();
- }
-
- private ConfigBundle(ConfigBundle bundle) {
- config = new FolderConfiguration();
- config.set(bundle.config);
- localeIndex = bundle.localeIndex;
- dockModeIndex = bundle.dockModeIndex;
- nightModeIndex = bundle.nightModeIndex;
- }
- }
-
- private static class ConfigMatch {
- final FolderConfiguration testConfig;
- final Device device;
- final State state;
- final ConfigBundle bundle;
-
- public ConfigMatch(@NonNull FolderConfiguration testConfig, @NonNull Device device,
- @NonNull State state, @NonNull ConfigBundle bundle) {
- this.testConfig = testConfig;
- this.device = device;
- this.state = state;
- this.bundle = bundle;
- }
-
- @Override
- public String toString() {
- return device.getName() + " - " + state.getName();
- }
- }
-
- /**
- * Checks whether the current edited file is the best match for a given config.
- * <p>
- * This tests against other versions of the same layout in the project.
- * <p>
- * The given config must be compatible with the current edited file.
- * @param config the config to test.
- * @return true if the current edited file is the best match in the project for the
- * given config.
- */
- public boolean isCurrentFileBestMatchFor(FolderConfiguration config) {
- ResourceFile match = mResources.getMatchingFile(mEditedFile.getName(),
- ResourceType.LAYOUT, config);
-
- if (match != null) {
- return match.getFile().equals(mEditedFile);
- } else {
- // if we stop here that means the current file is not even a match!
- AdtPlugin.log(IStatus.ERROR, "Current file is not a match for the given config.");
- }
-
- return false;
- }
-
- /**
- * Adapts the current device/config selection so that it's compatible with
- * the configuration.
- * <p>
- * If the current selection is compatible, nothing is changed.
- * <p>
- * If it's not compatible, configs from the current devices are tested.
- * <p>
- * If none are compatible, it reverts to
- * {@link #findAndSetCompatibleConfig(boolean)}
- */
- void adaptConfigSelection(boolean needBestMatch) {
- // check the device config (ie sans locale)
- boolean needConfigChange = true; // if still true, we need to find another config.
- boolean currentConfigIsCompatible = false;
- State selectedState = mConfiguration.getDeviceState();
- FolderConfiguration editedConfig = mConfiguration.getEditedConfig();
- if (selectedState != null) {
- FolderConfiguration currentConfig = DeviceConfigHelper.getFolderConfig(selectedState);
- if (currentConfig != null && editedConfig.isMatchFor(currentConfig)) {
- currentConfigIsCompatible = true; // current config is compatible
- if (!needBestMatch || isCurrentFileBestMatchFor(currentConfig)) {
- needConfigChange = false;
- }
- }
- }
-
- if (needConfigChange) {
- List<Locale> localeList = mConfigChooser.getLocaleList();
-
- // if the current state/locale isn't a correct match, then
- // look for another state/locale in the same device.
- FolderConfiguration testConfig = new FolderConfiguration();
-
- // first look in the current device.
- State matchState = null;
- int localeIndex = -1;
- Device device = mConfiguration.getDevice();
- if (device != null) {
- mainloop: for (State state : device.getAllStates()) {
- testConfig.set(DeviceConfigHelper.getFolderConfig(state));
-
- // loop on the locales.
- for (int i = 0 ; i < localeList.size() ; i++) {
- Locale locale = localeList.get(i);
-
- // update the test config with the locale qualifiers
- testConfig.setLocaleQualifier(locale.qualifier);
-
-
- if (editedConfig.isMatchFor(testConfig) &&
- isCurrentFileBestMatchFor(testConfig)) {
- matchState = state;
- localeIndex = i;
- break mainloop;
- }
- }
- }
- }
-
- if (matchState != null) {
- mConfiguration.setDeviceState(matchState, true);
- Locale locale = localeList.get(localeIndex);
- mConfiguration.setLocale(locale, true);
- if (mUpdateUi) {
- mConfigChooser.selectDeviceState(matchState);
- mConfigChooser.selectLocale(locale);
- }
- mConfiguration.syncFolderConfig();
- } else {
- // no match in current device with any state/locale
- // attempt to find another device that can display this
- // particular state.
- findAndSetCompatibleConfig(currentConfigIsCompatible);
- }
- }
- }
-
- /**
- * Finds a device/config that can display a configuration.
- * <p>
- * Once found the device and config combos are set to the config.
- * <p>
- * If there is no compatible configuration, a custom one is created.
- *
- * @param favorCurrentConfig if true, and no best match is found, don't
- * change the current config. This must only be true if the
- * current config is compatible.
- */
- void findAndSetCompatibleConfig(boolean favorCurrentConfig) {
- List<Locale> localeList = mConfigChooser.getLocaleList();
- Collection<Device> devices = mConfigChooser.getDevices();
- FolderConfiguration editedConfig = mConfiguration.getEditedConfig();
- FolderConfiguration currentConfig = mConfiguration.getFullConfig();
-
- // list of compatible device/state/locale
- List<ConfigMatch> anyMatches = new ArrayList<ConfigMatch>();
-
- // list of actual best match (ie the file is a best match for the
- // device/state)
- List<ConfigMatch> bestMatches = new ArrayList<ConfigMatch>();
-
- // get a locale that match the host locale roughly (may not be exact match on the region.)
- int localeHostMatch = getLocaleMatch();
-
- // build a list of combinations of non standard qualifiers to add to each device's
- // qualifier set when testing for a match.
- // These qualifiers are: locale, night-mode, car dock.
- List<ConfigBundle> configBundles = new ArrayList<ConfigBundle>(200);
-
- // If the edited file has locales, then we have to select a matching locale from
- // the list.
- // However, if it doesn't, we don't randomly take the first locale, we take one
- // matching the current host locale (making sure it actually exist in the project)
- int start, max;
- if (editedConfig.getLocaleQualifier() != null || localeHostMatch == -1) {
- // add all the locales
- start = 0;
- max = localeList.size();
- } else {
- // only add the locale host match
- start = localeHostMatch;
- max = localeHostMatch + 1; // test is <
- }
-
- for (int i = start ; i < max ; i++) {
- Locale l = localeList.get(i);
-
- ConfigBundle bundle = new ConfigBundle();
- bundle.config.setLocaleQualifier(l.qualifier);
-
- bundle.localeIndex = i;
- configBundles.add(bundle);
- }
-
- // add the dock mode to the bundle combinations.
- addDockModeToBundles(configBundles);
-
- // add the night mode to the bundle combinations.
- addNightModeToBundles(configBundles);
-
- addRenderTargetToBundles(configBundles);
-
- for (Device device : devices) {
- for (State state : device.getAllStates()) {
-
- // loop on the list of config bundles to create full
- // configurations.
- FolderConfiguration stateConfig = DeviceConfigHelper.getFolderConfig(state);
- for (ConfigBundle bundle : configBundles) {
- // create a new config with device config
- FolderConfiguration testConfig = new FolderConfiguration();
- testConfig.set(stateConfig);
-
- // add on top of it, the extra qualifiers from the bundle
- testConfig.add(bundle.config);
-
- if (editedConfig.isMatchFor(testConfig)) {
- // this is a basic match. record it in case we don't
- // find a match
- // where the edited file is a best config.
- anyMatches.add(new ConfigMatch(testConfig, device, state, bundle));
-
- if (isCurrentFileBestMatchFor(testConfig)) {
- // this is what we want.
- bestMatches.add(new ConfigMatch(testConfig, device, state, bundle));
- }
- }
- }
- }
- }
-
- if (bestMatches.size() == 0) {
- if (favorCurrentConfig) {
- // quick check
- if (!editedConfig.isMatchFor(currentConfig)) {
- AdtPlugin.log(IStatus.ERROR,
- "favorCurrentConfig can only be true if the current config is compatible");
- }
-
- // just display the warning
- AdtPlugin.printErrorToConsole(mEditedFile.getProject(),
- String.format(
- "'%1$s' is not a best match for any device/locale combination.",
- editedConfig.toDisplayString()),
- String.format(
- "Displaying it with '%1$s'",
- currentConfig.toDisplayString()));
- } else if (anyMatches.size() > 0) {
- // select the best device anyway.
- ConfigMatch match = selectConfigMatch(anyMatches);
- mConfiguration.setDevice(match.device, true);
- mConfiguration.setDeviceState(match.state, true);
- mConfiguration.setLocale(localeList.get(match.bundle.localeIndex), true);
- mConfiguration.setUiMode(UiMode.getByIndex(match.bundle.dockModeIndex), true);
- mConfiguration.setNightMode(NightMode.getByIndex(match.bundle.nightModeIndex),
- true);
-
- if (mUpdateUi) {
- mConfigChooser.selectDevice(mConfiguration.getDevice());
- mConfigChooser.selectDeviceState(mConfiguration.getDeviceState());
- mConfigChooser.selectLocale(mConfiguration.getLocale());
- }
-
- mConfiguration.syncFolderConfig();
-
- // TODO: display a better warning!
- AdtPlugin.printErrorToConsole(mEditedFile.getProject(),
- String.format(
- "'%1$s' is not a best match for any device/locale combination.",
- editedConfig.toDisplayString()),
- String.format(
- "Displaying it with '%1$s' which is compatible, but will " +
- "actually be displayed with another more specific version of " +
- "the layout.",
- currentConfig.toDisplayString()));
-
- } else {
- // TODO: there is no device/config able to display the layout, create one.
- // For the base config values, we'll take the first device and state,
- // and replace whatever qualifier required by the layout file.
- }
- } else {
- ConfigMatch match = selectConfigMatch(bestMatches);
- mConfiguration.setDevice(match.device, true);
- mConfiguration.setDeviceState(match.state, true);
- mConfiguration.setLocale(localeList.get(match.bundle.localeIndex), true);
- mConfiguration.setUiMode(UiMode.getByIndex(match.bundle.dockModeIndex), true);
- mConfiguration.setNightMode(NightMode.getByIndex(match.bundle.nightModeIndex), true);
-
- mConfiguration.syncFolderConfig();
-
- if (mUpdateUi) {
- mConfigChooser.selectDevice(mConfiguration.getDevice());
- mConfigChooser.selectDeviceState(mConfiguration.getDeviceState());
- mConfigChooser.selectLocale(mConfiguration.getLocale());
- }
- }
- }
-
- private void addRenderTargetToBundles(List<ConfigBundle> configBundles) {
- Pair<Locale, IAndroidTarget> state = Configuration.loadRenderState(mConfigChooser);
- if (state != null) {
- IAndroidTarget target = state.getSecond();
- if (target != null) {
- int apiLevel = target.getVersion().getApiLevel();
- for (ConfigBundle bundle : configBundles) {
- bundle.config.setVersionQualifier(
- new VersionQualifier(apiLevel));
- }
- }
- }
- }
-
- private void addDockModeToBundles(List<ConfigBundle> addConfig) {
- ArrayList<ConfigBundle> list = new ArrayList<ConfigBundle>();
-
- // loop on each item and for each, add all variations of the dock modes
- for (ConfigBundle bundle : addConfig) {
- int index = 0;
- for (UiMode mode : UiMode.values()) {
- ConfigBundle b = new ConfigBundle(bundle);
- b.config.setUiModeQualifier(new UiModeQualifier(mode));
- b.dockModeIndex = index++;
- list.add(b);
- }
- }
-
- addConfig.clear();
- addConfig.addAll(list);
- }
-
- private void addNightModeToBundles(List<ConfigBundle> addConfig) {
- ArrayList<ConfigBundle> list = new ArrayList<ConfigBundle>();
-
- // loop on each item and for each, add all variations of the night modes
- for (ConfigBundle bundle : addConfig) {
- int index = 0;
- for (NightMode mode : NightMode.values()) {
- ConfigBundle b = new ConfigBundle(bundle);
- b.config.setNightModeQualifier(new NightModeQualifier(mode));
- b.nightModeIndex = index++;
- list.add(b);
- }
- }
-
- addConfig.clear();
- addConfig.addAll(list);
- }
-
- private int getLocaleMatch() {
- java.util.Locale defaultLocale = java.util.Locale.getDefault();
- if (defaultLocale != null) {
- String currentLanguage = defaultLocale.getLanguage();
- String currentRegion = defaultLocale.getCountry();
-
- List<Locale> localeList = mConfigChooser.getLocaleList();
- final int count = localeList.size();
- for (int l = 0; l < count; l++) {
- Locale locale = localeList.get(l);
- LocaleQualifier qualifier = locale.qualifier;
-
- // there's always a ##/Other or ##/Any (which is the same, the region
- // contains FAKE_REGION_VALUE). If we don't find a perfect region match
- // we take the fake region. Since it's last in the list, this makes the
- // test easy.
- if (qualifier.getLanguage().equals(currentLanguage) &&
- (qualifier.getRegion() == null || qualifier.getRegion().equals(currentRegion))) {
- return l;
- }
- }
-
- // if no locale match the current local locale, it's likely that it is
- // the default one which is the last one.
- return count - 1;
- }
-
- return -1;
- }
-
- private ConfigMatch selectConfigMatch(List<ConfigMatch> matches) {
- // API 11-13: look for a x-large device
- Comparator<ConfigMatch> comparator = null;
- Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- IAndroidTarget projectTarget = sdk.getTarget(mEditedFile.getProject());
- if (projectTarget != null) {
- int apiLevel = projectTarget.getVersion().getApiLevel();
- if (apiLevel >= 11 && apiLevel < 14) {
- // TODO: Maybe check the compatible-screen tag in the manifest to figure out
- // what kind of device should be used for display.
- comparator = new TabletConfigComparator();
- }
- }
- }
- if (comparator == null) {
- // lets look for a high density device
- comparator = new PhoneConfigComparator();
- }
- Collections.sort(matches, comparator);
-
- // Look at the currently active editor to see if it's a layout editor, and if so,
- // look up its configuration and if the configuration is in our match list,
- // use it. This means we "preserve" the current configuration when you open
- // new layouts.
- IEditorPart activeEditor = AdtUtils.getActiveEditor();
- LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(activeEditor);
- if (delegate != null
- // (Only do this when the two files are in the same project)
- && delegate.getEditor().getProject() == mEditedFile.getProject()) {
- FolderConfiguration configuration = delegate.getGraphicalEditor().getConfiguration();
- if (configuration != null) {
- for (ConfigMatch match : matches) {
- if (configuration.equals(match.testConfig)) {
- return match;
- }
- }
- }
- }
-
- // the list has been sorted so that the first item is the best config
- return matches.get(0);
- }
-
- /** Return the default render target to use, or null if no strong preference */
- @Nullable
- static IAndroidTarget findDefaultRenderTarget(ConfigurationChooser chooser) {
- if (PREFER_RECENT_RENDER_TARGETS) {
- // Use the most recent target
- List<IAndroidTarget> targetList = chooser.getTargetList();
- if (!targetList.isEmpty()) {
- return targetList.get(targetList.size() - 1);
- }
- }
-
- IProject project = chooser.getProject();
- // Default to layoutlib version 5
- Sdk current = Sdk.getCurrent();
- if (current != null) {
- IAndroidTarget projectTarget = current.getTarget(project);
- int minProjectApi = Integer.MAX_VALUE;
- if (projectTarget != null) {
- if (!projectTarget.isPlatform() && projectTarget.hasRenderingLibrary()) {
- // Renderable non-platform targets are all going to be adequate (they
- // will have at least version 5 of layoutlib) so use the project
- // target as the render target.
- return projectTarget;
- }
-
- if (projectTarget.getVersion().isPreview()
- && projectTarget.hasRenderingLibrary()) {
- // If the project target is a preview version, then just use it
- return projectTarget;
- }
-
- minProjectApi = projectTarget.getVersion().getApiLevel();
- }
-
- // We want to pick a render target that contains at least version 5 (and
- // preferably version 6) of the layout library. To do this, we go through the
- // targets and pick the -smallest- API level that is both simultaneously at
- // least as big as the project API level, and supports layoutlib level 5+.
- IAndroidTarget best = null;
- int bestApiLevel = Integer.MAX_VALUE;
-
- for (IAndroidTarget target : current.getTargets()) {
- // Non-platform targets are not chosen as the default render target
- if (!target.isPlatform()) {
- continue;
- }
-
- int apiLevel = target.getVersion().getApiLevel();
-
- // Ignore targets that have a lower API level than the minimum project
- // API level:
- if (apiLevel < minProjectApi) {
- continue;
- }
-
- // Look up the layout lib API level. This property is new so it will only
- // be defined for version 6 or higher, which means non-null is adequate
- // to see if this target is eligible:
- String property = target.getProperty(PkgProps.LAYOUTLIB_API);
- // In addition, Android 3.0 with API level 11 had version 5.0 which is adequate:
- if (property != null || apiLevel >= 11) {
- if (apiLevel < bestApiLevel) {
- bestApiLevel = apiLevel;
- best = target;
- }
- }
- }
-
- return best;
- }
-
- return null;
- }
-
- /**
- * Attempts to find a close state among a list
- *
- * @param oldConfig the reference config.
- * @param states the list of states to search through
- * @return the name of the closest state match, or possibly null if no states are compatible
- * (this can only happen if the states don't have a single qualifier that is the same).
- */
- @Nullable
- static String getClosestMatch(@NonNull FolderConfiguration oldConfig,
- @NonNull List<State> states) {
-
- // create 2 lists as we're going to go through one and put the
- // candidates in the other.
- List<State> list1 = new ArrayList<State>(states.size());
- List<State> list2 = new ArrayList<State>(states.size());
-
- list1.addAll(states);
-
- final int count = FolderConfiguration.getQualifierCount();
- for (int i = 0 ; i < count ; i++) {
- // compute the new candidate list by only taking states that have
- // the same i-th qualifier as the old state
- for (State s : list1) {
- ResourceQualifier oldQualifier = oldConfig.getQualifier(i);
-
- FolderConfiguration folderConfig = DeviceConfigHelper.getFolderConfig(s);
- ResourceQualifier newQualifier =
- folderConfig != null ? folderConfig.getQualifier(i) : null;
-
- if (oldQualifier == null) {
- if (newQualifier == null) {
- list2.add(s);
- }
- } else if (oldQualifier.equals(newQualifier)) {
- list2.add(s);
- }
- }
-
- // at any moment if the new candidate list contains only one match, its name
- // is returned.
- if (list2.size() == 1) {
- return list2.get(0).getName();
- }
-
- // if the list is empty, then all the new states failed. It is considered ok, and
- // we move to the next qualifier anyway. This way, if a qualifier is different for
- // all new states it is simply ignored.
- if (list2.size() != 0) {
- // move the candidates back into list1.
- list1.clear();
- list1.addAll(list2);
- list2.clear();
- }
- }
-
- // the only way to reach this point is if there's an exact match.
- // (if there are more than one, then there's a duplicate state and it doesn't matter,
- // we take the first one).
- if (list1.size() > 0) {
- return list1.get(0).getName();
- }
-
- return null;
- }
-
- /**
- * Returns the layout {@link IFile} which best matches the configuration
- * selected in the given configuration chooser.
- *
- * @param chooser the associated configuration chooser holding project state
- * @return the file which best matches the settings
- */
- @Nullable
- public static IFile getBestFileMatch(ConfigurationChooser chooser) {
- // get the resources of the file's project.
- ResourceManager manager = ResourceManager.getInstance();
- ProjectResources resources = manager.getProjectResources(chooser.getProject());
- if (resources == null) {
- return null;
- }
-
- // From the resources, look for a matching file
- IFile editedFile = chooser.getEditedFile();
- if (editedFile == null) {
- return null;
- }
- String name = editedFile.getName();
- FolderConfiguration config = chooser.getConfiguration().getFullConfig();
- ResourceFile match = resources.getMatchingFile(name, ResourceType.LAYOUT, config);
-
- if (match != null) {
- // In Eclipse, the match's file is always an instance of IFileWrapper
- return ((IFileWrapper) match.getFile()).getIFile();
- }
-
- return null;
- }
-
- /**
- * Note: this comparator imposes orderings that are inconsistent with equals.
- */
- private static class TabletConfigComparator implements Comparator<ConfigMatch> {
- @Override
- public int compare(ConfigMatch o1, ConfigMatch o2) {
- FolderConfiguration config1 = o1 != null ? o1.testConfig : null;
- FolderConfiguration config2 = o2 != null ? o2.testConfig : null;
- if (config1 == null) {
- if (config2 == null) {
- return 0;
- } else {
- return -1;
- }
- } else if (config2 == null) {
- return 1;
- }
-
- ScreenSizeQualifier size1 = config1.getScreenSizeQualifier();
- ScreenSizeQualifier size2 = config2.getScreenSizeQualifier();
- ScreenSize ss1 = size1 != null ? size1.getValue() : ScreenSize.NORMAL;
- ScreenSize ss2 = size2 != null ? size2.getValue() : ScreenSize.NORMAL;
-
- // X-LARGE is better than all others (which are considered identical)
- // if both X-LARGE, then LANDSCAPE is better than all others (which are identical)
-
- if (ss1 == ScreenSize.XLARGE) {
- if (ss2 == ScreenSize.XLARGE) {
- ScreenOrientationQualifier orientation1 =
- config1.getScreenOrientationQualifier();
- ScreenOrientation so1 = orientation1.getValue();
- if (so1 == null) {
- so1 = ScreenOrientation.PORTRAIT;
- }
- ScreenOrientationQualifier orientation2 =
- config2.getScreenOrientationQualifier();
- ScreenOrientation so2 = orientation2.getValue();
- if (so2 == null) {
- so2 = ScreenOrientation.PORTRAIT;
- }
-
- if (so1 == ScreenOrientation.LANDSCAPE) {
- if (so2 == ScreenOrientation.LANDSCAPE) {
- return 0;
- } else {
- return -1;
- }
- } else if (so2 == ScreenOrientation.LANDSCAPE) {
- return 1;
- } else {
- return 0;
- }
- } else {
- return -1;
- }
- } else if (ss2 == ScreenSize.XLARGE) {
- return 1;
- } else {
- return 0;
- }
- }
- }
-
- /**
- * Note: this comparator imposes orderings that are inconsistent with equals.
- */
- private static class PhoneConfigComparator implements Comparator<ConfigMatch> {
-
- private final SparseIntArray mDensitySort = new SparseIntArray(4);
-
- public PhoneConfigComparator() {
- // put the sort order for the density.
- mDensitySort.put(Density.HIGH.getDpiValue(), 1);
- mDensitySort.put(Density.MEDIUM.getDpiValue(), 2);
- mDensitySort.put(Density.XHIGH.getDpiValue(), 3);
- mDensitySort.put(Density.LOW.getDpiValue(), 4);
- }
-
- @Override
- public int compare(ConfigMatch o1, ConfigMatch o2) {
- FolderConfiguration config1 = o1 != null ? o1.testConfig : null;
- FolderConfiguration config2 = o2 != null ? o2.testConfig : null;
- if (config1 == null) {
- if (config2 == null) {
- return 0;
- } else {
- return -1;
- }
- } else if (config2 == null) {
- return 1;
- }
-
- int dpi1 = Density.DEFAULT_DENSITY;
- int dpi2 = Density.DEFAULT_DENSITY;
-
- DensityQualifier dpiQualifier1 = config1.getDensityQualifier();
- if (dpiQualifier1 != null) {
- Density value = dpiQualifier1.getValue();
- dpi1 = value != null ? value.getDpiValue() : Density.DEFAULT_DENSITY;
- }
- dpi1 = mDensitySort.get(dpi1, 100 /* valueIfKeyNotFound*/);
-
- DensityQualifier dpiQualifier2 = config2.getDensityQualifier();
- if (dpiQualifier2 != null) {
- Density value = dpiQualifier2.getValue();
- dpi2 = value != null ? value.getDpiValue() : Density.DEFAULT_DENSITY;
- }
- dpi2 = mDensitySort.get(dpi2, 100 /* valueIfKeyNotFound*/);
-
- if (dpi1 == dpi2) {
- // portrait is better
- ScreenOrientation so1 = ScreenOrientation.PORTRAIT;
- ScreenOrientationQualifier orientationQualifier1 =
- config1.getScreenOrientationQualifier();
- if (orientationQualifier1 != null) {
- so1 = orientationQualifier1.getValue();
- if (so1 == null) {
- so1 = ScreenOrientation.PORTRAIT;
- }
- }
- ScreenOrientation so2 = ScreenOrientation.PORTRAIT;
- ScreenOrientationQualifier orientationQualifier2 =
- config2.getScreenOrientationQualifier();
- if (orientationQualifier2 != null) {
- so2 = orientationQualifier2.getValue();
- if (so2 == null) {
- so2 = ScreenOrientation.PORTRAIT;
- }
- }
-
- if (so1 == ScreenOrientation.PORTRAIT) {
- if (so2 == ScreenOrientation.PORTRAIT) {
- return 0;
- } else {
- return -1;
- }
- } else if (so2 == ScreenOrientation.PORTRAIT) {
- return 1;
- } else {
- return 0;
- }
- }
-
- return dpi1 - dpi2;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMenuListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMenuListener.java
deleted file mode 100644
index a791c63f8..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationMenuListener.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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 static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.CUSTOM;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.DEFAULT;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.INCLUDES;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.LOCALES;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.NONE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.SCREENS;
-import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.VARIATIONS;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.resources.ResourceFolder;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewManager;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.ToolItem;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.PartInitException;
-
-import java.util.List;
-
-/**
- * The {@linkplain ConfigurationMenuListener} class is responsible for
- * generating the configuration menu in the {@link ConfigurationChooser}.
- */
-class ConfigurationMenuListener extends SelectionAdapter {
- private static final String ICON_NEW_CONFIG = "newConfig"; //$NON-NLS-1$
- private static final int ACTION_SELECT_CONFIG = 1;
- private static final int ACTION_CREATE_CONFIG_FILE = 2;
- private static final int ACTION_ADD = 3;
- private static final int ACTION_DELETE_ALL = 4;
- private static final int ACTION_PREVIEW_MODE = 5;
-
- private final ConfigurationChooser mConfigChooser;
- private final int mAction;
- private final IFile mResource;
- private final RenderPreviewMode mMode;
-
- ConfigurationMenuListener(
- @NonNull ConfigurationChooser configChooser,
- int action,
- @Nullable IFile resource,
- @Nullable RenderPreviewMode mode) {
- mConfigChooser = configChooser;
- mAction = action;
- mResource = resource;
- mMode = mode;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- switch (mAction) {
- case ACTION_SELECT_CONFIG: {
- try {
- AdtPlugin.openFile(mResource, null, false);
- } catch (PartInitException ex) {
- AdtPlugin.log(ex, null);
- }
- return;
- }
- case ACTION_CREATE_CONFIG_FILE: {
- ConfigurationClient client = mConfigChooser.getClient();
- if (client != null) {
- client.createConfigFile();
- }
- return;
- }
- }
-
- IEditorPart activeEditor = AdtUtils.getActiveEditor();
- LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(activeEditor);
- IFile editedFile = mConfigChooser.getEditedFile();
-
- if (delegate == null || editedFile == null) {
- return;
- }
- // (Only do this when the two files are in the same project)
- IProject project = delegate.getEditor().getProject();
- if (project == null ||
- !project.equals(editedFile.getProject())) {
- return;
- }
- LayoutCanvas canvas = delegate.getGraphicalEditor().getCanvasControl();
- RenderPreviewManager previewManager = canvas.getPreviewManager();
-
- switch (mAction) {
- case ACTION_ADD: {
- previewManager.addAsThumbnail();
- break;
- }
- case ACTION_PREVIEW_MODE: {
- previewManager.selectMode(mMode);
- break;
- }
- case ACTION_DELETE_ALL: {
- previewManager.deleteManualPreviews();
- break;
- }
- default: assert false : mAction;
- }
- canvas.setFitScale(true /*onlyZoomOut*/, false /*allowZoomIn*/);
- canvas.redraw();
- }
-
- static void show(ConfigurationChooser chooser, ToolItem combo) {
- Menu menu = new Menu(chooser.getShell(), SWT.POP_UP);
- RenderPreviewMode mode = AdtPrefs.getPrefs().getRenderPreviewMode();
-
- // Configuration Previews
- create(menu, "Add As Thumbnail...",
- new ConfigurationMenuListener(chooser, ACTION_ADD, null, null),
- SWT.PUSH, false);
- if (mode == RenderPreviewMode.CUSTOM) {
- MenuItem item = create(menu, "Delete All Thumbnails",
- new ConfigurationMenuListener(chooser, ACTION_DELETE_ALL, null, null),
- SWT.PUSH, false);
- IEditorPart activeEditor = AdtUtils.getActiveEditor();
- LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(activeEditor);
- if (delegate != null) {
- LayoutCanvas canvas = delegate.getGraphicalEditor().getCanvasControl();
- RenderPreviewManager previewManager = canvas.getPreviewManager();
- if (!previewManager.hasManualPreviews()) {
- item.setEnabled(false);
- }
- }
- }
-
- @SuppressWarnings("unused")
- MenuItem configSeparator = new MenuItem(menu, SWT.SEPARATOR);
-
- create(menu, "Preview Representative Sample",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- DEFAULT), SWT.RADIO, mode == DEFAULT);
- create(menu, "Preview All Screen Sizes",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- SCREENS), SWT.RADIO, mode == SCREENS);
-
- MenuItem localeItem = create(menu, "Preview All Locales",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- LOCALES), SWT.RADIO, mode == LOCALES);
- if (chooser.getLocaleList().size() <= 1) {
- localeItem.setEnabled(false);
- }
-
- boolean canPreviewIncluded = false;
- IProject project = chooser.getProject();
- if (project != null) {
- IncludeFinder finder = IncludeFinder.get(project);
- final List<Reference> includedBy = finder.getIncludedBy(chooser.getEditedFile());
- canPreviewIncluded = includedBy != null && !includedBy.isEmpty();
- }
- //if (!graphicalEditor.renderingSupports(Capability.EMBEDDED_LAYOUT)) {
- // canPreviewIncluded = false;
- //}
- MenuItem includedItem = create(menu, "Preview Included",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- INCLUDES), SWT.RADIO, mode == INCLUDES);
- if (!canPreviewIncluded) {
- includedItem.setEnabled(false);
- }
-
- IFile file = chooser.getEditedFile();
- List<IFile> variations = AdtUtils.getResourceVariations(file, true);
- MenuItem variationsItem = create(menu, "Preview Layout Versions",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- VARIATIONS), SWT.RADIO, mode == VARIATIONS);
- if (variations.size() <= 1) {
- variationsItem.setEnabled(false);
- }
-
- create(menu, "Manual Previews",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- CUSTOM), SWT.RADIO, mode == CUSTOM);
- create(menu, "None",
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null,
- NONE), SWT.RADIO, mode == NONE);
-
- if (variations.size() > 1) {
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
-
- ResourceManager manager = ResourceManager.getInstance();
- for (final IFile resource : variations) {
- IFolder parent = (IFolder) resource.getParent();
- ResourceFolder parentResource = manager.getResourceFolder(parent);
- FolderConfiguration configuration = parentResource.getConfiguration();
- String title = configuration.toDisplayString();
-
- MenuItem item = create(menu, title,
- new ConfigurationMenuListener(chooser, ACTION_SELECT_CONFIG,
- resource, null),
- SWT.CHECK, false);
-
- if (file != null) {
- boolean selected = file.equals(resource);
- if (selected) {
- item.setSelection(true);
- item.setEnabled(false);
- }
- }
- }
- }
-
- Configuration configuration = chooser.getConfiguration();
- if (configuration.getEditedConfig() != null &&
- !configuration.getEditedConfig().equals(configuration.getFullConfig())) {
- if (variations.size() > 0) {
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
- }
-
- // Add action for creating a new configuration
- MenuItem item = create(menu, "Create New...",
- new ConfigurationMenuListener(chooser, ACTION_CREATE_CONFIG_FILE,
- null, null),
- SWT.PUSH, false);
- item.setImage(IconFactory.getInstance().getIcon(ICON_NEW_CONFIG));
- }
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-
- @NonNull
- public static MenuItem create(@NonNull Menu menu, String title,
- ConfigurationMenuListener listener, int style, boolean selected) {
- MenuItem item = new MenuItem(menu, style);
- item.setText(title);
- item.addSelectionListener(listener);
- if (selected) {
- item.setSelection(true);
- }
- return item;
- }
-
- @NonNull
- static MenuItem addTogglePreviewModeAction(
- @NonNull Menu menu,
- @NonNull String title,
- @NonNull ConfigurationChooser chooser,
- @NonNull RenderPreviewMode mode) {
- boolean selected = AdtPrefs.getPrefs().getRenderPreviewMode() == mode;
- if (selected) {
- mode = RenderPreviewMode.NONE;
- }
- return create(menu, title,
- new ConfigurationMenuListener(chooser, ACTION_PREVIEW_MODE, null, mode),
- SWT.CHECK, selected);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/DeviceMenuListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/DeviceMenuListener.java
deleted file mode 100644
index 72910f9cc..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/DeviceMenuListener.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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 static com.android.ide.common.rendering.HardwareConfigHelper.MANUFACTURER_GENERIC;
-import static com.android.ide.common.rendering.HardwareConfigHelper.getGenericLabel;
-import static com.android.ide.common.rendering.HardwareConfigHelper.getNexusLabel;
-import static com.android.ide.common.rendering.HardwareConfigHelper.isGeneric;
-import static com.android.ide.common.rendering.HardwareConfigHelper.isNexus;
-import static com.android.ide.common.rendering.HardwareConfigHelper.sortNexusList;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.internal.avd.AvdInfo;
-import com.android.sdklib.internal.avd.AvdManager;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * The {@linkplain DeviceMenuListener} class is responsible for generating the device
- * menu in the {@link ConfigurationChooser}.
- */
-class DeviceMenuListener extends SelectionAdapter {
- private final ConfigurationChooser mConfigChooser;
- private final Device mDevice;
-
- DeviceMenuListener(
- @NonNull ConfigurationChooser configChooser,
- @Nullable Device device) {
- mConfigChooser = configChooser;
- mDevice = device;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- mConfigChooser.selectDevice(mDevice);
- mConfigChooser.onDeviceChange();
- }
-
- static void show(final ConfigurationChooser chooser, ToolItem combo) {
- Configuration configuration = chooser.getConfiguration();
- Device current = configuration.getDevice();
- Menu menu = new Menu(chooser.getShell(), SWT.POP_UP);
-
- Collection<Device> deviceCollection = chooser.getDevices();
- Sdk sdk = Sdk.getCurrent();
- if (sdk != null) {
- AvdManager avdManager = sdk.getAvdManager();
- if (avdManager != null) {
- boolean separatorNeeded = false;
- AvdInfo[] avds = avdManager.getValidAvds();
- for (AvdInfo avd : avds) {
- for (Device device : deviceCollection) {
- if (device.getManufacturer().equals(avd.getDeviceManufacturer())
- && device.getName().equals(avd.getDeviceName())) {
- separatorNeeded = true;
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(avd.getName());
- item.setSelection(current == device);
-
- item.addSelectionListener(new DeviceMenuListener(chooser, device));
- }
- }
- }
-
- if (separatorNeeded) {
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
- }
- }
- }
-
- // Group the devices by manufacturer, then put them in the menu.
- // If we don't have anything but Nexus devices, group them together rather than
- // make many manufacturer submenus.
- boolean haveNexus = false;
- boolean haveNonNexus = false;
- if (!deviceCollection.isEmpty()) {
- Map<String, List<Device>> manufacturers = new TreeMap<String, List<Device>>();
- for (Device device : deviceCollection) {
- List<Device> devices;
- if (isNexus(device)) {
- haveNexus = true;
- } else if (!isGeneric(device)) {
- haveNonNexus = true;
- }
- if (manufacturers.containsKey(device.getManufacturer())) {
- devices = manufacturers.get(device.getManufacturer());
- } else {
- devices = new ArrayList<Device>();
- manufacturers.put(device.getManufacturer(), devices);
- }
- devices.add(device);
- }
- if (haveNonNexus) {
- for (List<Device> devices : manufacturers.values()) {
- Menu manufacturerMenu = menu;
- if (manufacturers.size() > 1) {
- MenuItem item = new MenuItem(menu, SWT.CASCADE);
- item.setText(devices.get(0).getManufacturer());
- manufacturerMenu = new Menu(menu);
- item.setMenu(manufacturerMenu);
- }
- for (final Device device : devices) {
- MenuItem deviceItem = new MenuItem(manufacturerMenu, SWT.CHECK);
- deviceItem.setText(getGenericLabel(device));
- deviceItem.setSelection(current == device);
- deviceItem.addSelectionListener(new DeviceMenuListener(chooser, device));
- }
- }
- } else {
- List<Device> nexus = new ArrayList<Device>();
- List<Device> generic = new ArrayList<Device>();
- if (haveNexus) {
- // Nexus
- for (List<Device> devices : manufacturers.values()) {
- for (Device device : devices) {
- if (isNexus(device)) {
- if (device.getManufacturer().equals(MANUFACTURER_GENERIC)) {
- generic.add(device);
- } else {
- nexus.add(device);
- }
- } else {
- generic.add(device);
- }
- }
- }
- }
-
- if (!nexus.isEmpty()) {
- sortNexusList(nexus);
- for (final Device device : nexus) {
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(getNexusLabel(device));
- item.setSelection(current == device);
- item.addSelectionListener(new DeviceMenuListener(chooser, device));
- }
-
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
- }
-
- // Generate the generic menu.
- Collections.reverse(generic);
- for (final Device device : generic) {
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(getGenericLabel(device));
- item.setSelection(current == device);
- item.addSelectionListener(new DeviceMenuListener(chooser, device));
- }
- }
- }
-
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
-
- ConfigurationMenuListener.addTogglePreviewModeAction(menu,
- "Preview All Screens", chooser, RenderPreviewMode.SCREENS);
-
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManager.java
deleted file mode 100644
index 15623cf30..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/FlagManager.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.LocaleManager;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.google.common.collect.Maps;
-
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.wb.internal.core.DesignerPlugin;
-
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * The {@linkplain FlagManager} provides access to flags for regions known
- * to {@link LocaleManager}. It also contains some locale related display
- * functions.
- * <p>
- * All the flag images came from the WindowBuilder subversion repository
- * http://dev.eclipse.org/svnroot/tools/org.eclipse.windowbuilder/trunk (and in
- * particular, a snapshot of revision 424). However, it appears that the icons
- * are from http://www.famfamfam.com/lab/icons/flags/ which states that "these
- * flag icons are available for free use for any purpose with no requirement for
- * attribution." Adding the URL here such that we can check back occasionally
- * and see if there are corrections or updates. Also note that the flag names
- * are in ISO 3166-1 alpha-2 country codes.
- */
-public class FlagManager {
- private static final FlagManager sInstance = new FlagManager();
-
- /**
- * Returns the {@linkplain FlagManager} singleton
- *
- * @return the {@linkplain FlagManager} singleton, never null
- */
- @NonNull
- public static FlagManager get() {
- return sInstance;
- }
-
- /** Use the {@link #get()} factory method */
- private FlagManager() {
- }
-
- /** Map from region to flag icon */
- private final Map<String, Image> mImageMap = Maps.newHashMap();
-
- /**
- * Returns the empty flag icon used to indicate an unknown country
- *
- * @return the globe icon used to indicate an unknown country
- */
- public static Image getEmptyIcon() {
- return DesignerPlugin.getImage("nls/flags/flag_empty.png"); //$NON-NLS-1$
- }
-
- /**
- * Returns the globe icon used to indicate "any" language
- *
- * @return the globe icon used to indicate "any" language
- */
- public static Image getGlobeIcon() {
- return IconFactory.getInstance().getIcon("globe"); //$NON-NLS-1$
- }
-
- /**
- * Returns the flag for the given language and region.
- *
- * @param language the language, or null (if null, region must not be null),
- * the 2 letter language code (ISO 639-1), in lower case
- * @param region the region, or null (if null, language must not be null),
- * the 2 letter region code (ISO 3166-1 alpha-2), in upper case
- * @return a suitable flag icon, or null
- */
- @Nullable
- public Image getFlag(@Nullable String language, @Nullable String region) {
- assert region != null || language != null;
- if (region == null || region.isEmpty()) {
- // Look up the region for a given language
- assert language != null;
-
- // Special cases where we have a dedicated flag available:
- if (language.equals("ca")) { //$NON-NLS-1$
- return getIcon("catalonia"); //$NON-NLS-1$
- }
- else if (language.equals("gd")) { //$NON-NLS-1$
- return getIcon("scotland"); //$NON-NLS-1$
- }
- else if (language.equals("cy")) { //$NON-NLS-1$
- return getIcon("wales"); //$NON-NLS-1$
- }
-
- // Prefer the local registration of the current locale; even if
- // for example the default locale for English is the US, if the current
- // default locale is English, then use its associated country, which could
- // for example be Australia.
- Locale locale = Locale.getDefault();
- if (language.equals(locale.getLanguage())) {
- Image flag = getFlag(locale.getCountry());
- if (flag != null) {
- return flag;
- }
- }
-
- region = LocaleManager.getLanguageRegion(language);
- }
-
- if (region == null || region.isEmpty()) {
- // No country specified, and the language is for a country we
- // don't have a flag for
- return null;
- }
-
- return getIcon(region);
- }
-
- /**
- * Returns the flag for the given language and region.
- *
- * @param language the language qualifier, or null (if null, region must not be null),
- * @param region the region, or null (if null, language must not be null),
- * @return a suitable flag icon, or null
- */
- public Image getFlag(@Nullable LocaleQualifier locale) {
- if (locale == null) {
- return null;
- }
- String languageCode = locale.getLanguage();
- String regionCode = locale.getRegion();
- if (LocaleQualifier.FAKE_VALUE.equals(languageCode)) {
- languageCode = null;
- }
- return getFlag(languageCode, regionCode);
- }
-
- /**
- * Returns a flag for a given resource folder name (such as
- * {@code values-en-rUS}), or null
- *
- * @param folder the folder name
- * @return a corresponding flag icon, or null if none was found
- */
- @Nullable
- public Image getFlagForFolderName(@NonNull String folder) {
- FolderConfiguration configuration = FolderConfiguration.getConfigForFolder(folder);
- if (configuration != null) {
- return get().getFlag(configuration);
- }
-
- return null;
- }
-
- /**
- * Returns the flag for the given folder
- *
- * @param configuration the folder configuration
- * @return a suitable flag icon, or null
- */
- @Nullable
- public Image getFlag(@NonNull FolderConfiguration configuration) {
- return getFlag(configuration.getLocaleQualifier());
- }
-
-
-
- /**
- * Returns the flag for the given region.
- *
- * @param region the 2 letter region code (ISO 3166-1 alpha-2), in upper case
- * @return a suitable flag icon, or null
- */
- @Nullable
- public Image getFlag(@NonNull String region) {
- assert region.length() == 2
- && Character.isUpperCase(region.charAt(0))
- && Character.isUpperCase(region.charAt(1)) : region;
-
- return getIcon(region);
- }
-
- private Image getIcon(@NonNull String base) {
- Image flagImage = mImageMap.get(base);
- if (flagImage == null) {
- // TODO: Special case locale currently running on system such
- // that the current country matches the current locale
- if (mImageMap.containsKey(base)) {
- // Already checked: there's just no image there
- return null;
- }
- String flagFileName = base.toLowerCase(Locale.US) + ".png"; //$NON-NLS-1$
- flagImage = DesignerPlugin.getImage("nls/flags/" + flagFileName); //$NON-NLS-1$
- mImageMap.put(base, flagImage);
- }
-
- return flagImage;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LayoutCreatorDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LayoutCreatorDialog.java
deleted file mode 100644
index 97ff66845..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LayoutCreatorDialog.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2008 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.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.ResourceQualifier;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector;
-import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.ConfigurationState;
-import com.android.ide.eclipse.adt.internal.ui.ConfigurationSelector.SelectorMode;
-import com.android.resources.ResourceFolderType;
-import com.android.sdkuilib.ui.GridDialog;
-
-import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.dialogs.IDialogConstants;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * Dialog to choose a non existing {@link FolderConfiguration}.
- */
-public final class LayoutCreatorDialog extends GridDialog {
-
- private ConfigurationSelector mSelector;
- private Composite mStatusComposite;
- private Label mStatusLabel;
- private Label mStatusImage;
-
- private final FolderConfiguration mConfig = new FolderConfiguration();
- private final String mFileName;
-
- /**
- * Creates a dialog, and init the UI from a {@link FolderConfiguration}.
- * @param parentShell the parent {@link Shell}.
- * @param fileName the filename associated with the configuration
- * @param config The starting configuration.
- */
- public LayoutCreatorDialog(Shell parentShell, String fileName, FolderConfiguration config) {
- super(parentShell, 1, false);
-
- mFileName = fileName;
-
- // FIXME: add some data to know what configurations already exist.
- mConfig.set(config);
- }
-
- @Override
- public void createDialogContent(Composite parent) {
- new Label(parent, SWT.NONE).setText(
- String.format("Configuration for the alternate version of %1$s", mFileName));
-
- mSelector = new ConfigurationSelector(parent, SelectorMode.CONFIG_ONLY);
- mSelector.setConfiguration(mConfig);
-
- // because the ConfigSelector is running in CONFIG_ONLY mode, the current config
- // displayed by it is not mConfig anymore, so get the current config.
- mSelector.getConfiguration(mConfig);
-
- // parent's layout is a GridLayout as specified in the javadoc.
- GridData gd = new GridData();
- gd.widthHint = ConfigurationSelector.WIDTH_HINT;
- gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
- mSelector.setLayoutData(gd);
-
- // add a listener to check on the validity of the FolderConfiguration as
- // they are built.
- mSelector.setOnChangeListener(new Runnable() {
- @Override
- public void run() {
- ConfigurationState state = mSelector.getState();
-
- switch (state) {
- case OK:
- mSelector.getConfiguration(mConfig);
-
- resetStatus();
- mStatusImage.setImage(null);
- getButton(IDialogConstants.OK_ID).setEnabled(true);
- break;
- case INVALID_CONFIG:
- ResourceQualifier invalidQualifier = mSelector.getInvalidQualifier();
- mStatusLabel.setText(String.format(
- "Invalid Configuration: %1$s has no filter set.",
- invalidQualifier.getName()));
- mStatusImage.setImage(IconFactory.getInstance().getIcon("warning")); //$NON-NLS-1$
- getButton(IDialogConstants.OK_ID).setEnabled(false);
- break;
- case REGION_WITHOUT_LANGUAGE:
- mStatusLabel.setText(
- "The Region qualifier requires the Language qualifier.");
- mStatusImage.setImage(IconFactory.getInstance().getIcon("warning")); //$NON-NLS-1$
- getButton(IDialogConstants.OK_ID).setEnabled(false);
- break;
- }
-
- // need to relayout, because of the change in size in mErrorImage.
- mStatusComposite.layout();
- }
- });
-
- mStatusComposite = new Composite(parent, SWT.NONE);
- mStatusComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- GridLayout gl = new GridLayout(2, false);
- mStatusComposite.setLayout(gl);
- gl.marginHeight = gl.marginWidth = 0;
-
- mStatusImage = new Label(mStatusComposite, SWT.NONE);
- mStatusLabel = new Label(mStatusComposite, SWT.NONE);
- mStatusLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
- resetStatus();
- }
-
- /**
- * Sets the edited configuration on the given configuration parameter
- *
- * @param config the configuration to apply the current edits to
- */
- public void getConfiguration(FolderConfiguration config) {
- config.set(mConfig);
- }
-
- /**
- * resets the status label to show the file that will be created.
- */
- private void resetStatus() {
- String displayString = Dialog.shortenText(String.format("New File: res/%1$s/%2$s",
- mConfig.getFolderName(ResourceFolderType.LAYOUT), mFileName),
- mStatusLabel);
- mStatusLabel.setText(displayString);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Locale.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Locale.java
deleted file mode 100644
index 6cb396394..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/Locale.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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 static com.android.ide.common.resources.configuration.LocaleQualifier.FAKE_VALUE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.LocaleQualifier;
-
-import org.eclipse.swt.graphics.Image;
-
-/**
- * A language,region pair
- */
-public class Locale {
- /**
- * A special marker region qualifier representing any region
- */
- public static final LocaleQualifier ANY_QUALIFIER = new LocaleQualifier(FAKE_VALUE);
-
- /**
- * A locale which matches any language and region
- */
- public static final Locale ANY = new Locale(ANY_QUALIFIER);
-
- /**
- * The locale qualifier, or {@link #ANY_QUALIFIER} if this locale matches
- * any locale
- */
- @NonNull
- public final LocaleQualifier qualifier;
-
- /**
- * Constructs a new {@linkplain Locale} matching a given language in a given
- * locale.
- *
- * @param locale the locale
- */
- private Locale(@NonNull
- LocaleQualifier locale) {
- qualifier = locale;
- }
-
- /**
- * Constructs a new {@linkplain Locale} matching a given language in a given
- * specific locale.
- *
- * @param locale the locale
- * @return a locale with the given locale
- */
- @NonNull
- public static Locale create(@NonNull
- LocaleQualifier locale) {
- return new Locale(locale);
- }
-
- /**
- * Constructs a new {@linkplain Locale} for the given folder configuration
- *
- * @param folder the folder configuration
- * @return a locale with the given language and region
- */
- public static Locale create(FolderConfiguration folder) {
- LocaleQualifier locale = folder.getLocaleQualifier();
- if (locale == null) {
- return ANY;
- } else {
- return new Locale(locale);
- }
- }
-
- /**
- * Constructs a new {@linkplain Locale} for the given locale string, e.g.
- * "zh", "en-rUS", or "b+eng+US".
- *
- * @param localeString the locale description
- * @return the corresponding locale
- */
- @NonNull
- public static Locale create(@NonNull
- String localeString) {
- // Load locale. Note that this can get overwritten by the
- // project-wide settings read below.
-
- LocaleQualifier qualifier = LocaleQualifier.getQualifier(localeString);
- if (qualifier != null) {
- return new Locale(qualifier);
- } else {
- return ANY;
- }
- }
-
- /**
- * Returns a flag image to use for this locale
- *
- * @return a flag image, or a default globe icon
- */
- @NonNull
- public Image getFlagImage() {
- String languageCode = qualifier.hasLanguage() ? qualifier.getLanguage() : null;
- if (languageCode == null) {
- return FlagManager.getGlobeIcon();
- }
- String regionCode = hasRegion() ? qualifier.getRegion() : null;
- FlagManager icons = FlagManager.get();
- Image image = icons.getFlag(languageCode, regionCode);
- if (image != null) {
- return image;
- } else {
- return FlagManager.getGlobeIcon();
- }
- }
-
- /**
- * Returns true if this locale specifies a specific language. This is true
- * for all locales except {@link #ANY}.
- *
- * @return true if this locale specifies a specific language
- */
- public boolean hasLanguage() {
- return !qualifier.hasFakeValue();
- }
-
- /**
- * Returns true if this locale specifies a specific region
- *
- * @return true if this locale specifies a region
- */
- public boolean hasRegion() {
- return qualifier.getRegion() != null && !FAKE_VALUE.equals(qualifier.getRegion());
- }
-
- /**
- * Returns the locale formatted as language-region. If region is not set,
- * language is returned. If language is not set, empty string is returned.
- */
- public String toLocaleId() {
- return qualifier == ANY_QUALIFIER ? "" : qualifier.getTag();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + qualifier.hashCode();
- return result;
- }
-
- @Override
- public boolean equals(@Nullable
- Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Locale other = (Locale) obj;
- if (!qualifier.equals(other.qualifier))
- return false;
- return true;
- }
-
- @Override
- public String toString() {
- return qualifier.getTag();
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleMenuListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleMenuListener.java
deleted file mode 100644
index 2bc5417b0..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/LocaleMenuListener.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode;
-import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.AddTranslationDialog;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.List;
-
-/**
- * The {@linkplain LocaleMenuListener} class is responsible for generating the locale
- * menu in the {@link ConfigurationChooser}.
- */
-class LocaleMenuListener extends SelectionAdapter {
- private static final int ACTION_SET_LOCALE = 1;
- private static final int ACTION_ADD_TRANSLATION = 2;
-
- private final ConfigurationChooser mConfigChooser;
- private final int mAction;
- private final Locale mLocale;
-
- LocaleMenuListener(
- @NonNull ConfigurationChooser configChooser,
- int action,
- @Nullable Locale locale) {
- mConfigChooser = configChooser;
- mAction = action;
- mLocale = locale;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- switch (mAction) {
- case ACTION_SET_LOCALE: {
- mConfigChooser.selectLocale(mLocale);
- mConfigChooser.onLocaleChange();
- break;
- }
- case ACTION_ADD_TRANSLATION: {
- IProject project = mConfigChooser.getProject();
- Shell shell = mConfigChooser.getShell();
- AddTranslationDialog dialog = new AddTranslationDialog(shell, project);
- dialog.open();
- break;
- }
- default: assert false : mAction;
- }
- }
-
- static void show(final ConfigurationChooser chooser, ToolItem combo) {
- Menu menu = new Menu(chooser.getShell(), SWT.POP_UP);
- Configuration configuration = chooser.getConfiguration();
- List<Locale> locales = chooser.getLocaleList();
- Locale current = configuration.getLocale();
-
- for (Locale locale : locales) {
- String title = ConfigurationChooser.getLocaleLabel(chooser, locale, false);
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(title);
- Image image = locale.getFlagImage();
- item.setImage(image);
-
- boolean selected = current == locale;
- if (selected) {
- item.setSelection(true);
- }
-
- LocaleMenuListener listener = new LocaleMenuListener(chooser, ACTION_SET_LOCALE,
- locale);
- item.addSelectionListener(listener);
- }
-
- if (locales.size() > 1) {
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
-
- ConfigurationMenuListener.addTogglePreviewModeAction(menu,
- "Preview All Locales", chooser, RenderPreviewMode.LOCALES);
- }
-
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
-
- MenuItem item = new MenuItem(menu, SWT.PUSH);
- item.setText("Add New Translation...");
- LocaleMenuListener listener = new LocaleMenuListener(chooser,
- ACTION_ADD_TRANSLATION, null);
- item.addSelectionListener(listener);
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java
deleted file mode 100644
index 50778e2f1..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/NestedConfiguration.java
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * 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();
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/OrientationMenuAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/OrientationMenuAction.java
deleted file mode 100644
index 5cad29afc..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/OrientationMenuAction.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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.ide.eclipse.adt.internal.editors.layout.gle2.SubmenuAction;
-import com.android.resources.NightMode;
-import com.android.resources.ScreenOrientation;
-import com.android.resources.UiMode;
-import com.android.sdklib.devices.Device;
-import com.android.sdklib.devices.State;
-
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.ActionContributionItem;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.action.MenuManager;
-import org.eclipse.jface.action.Separator;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.List;
-
-/**
- * Action which creates a submenu that shows the available orientations as well
- * as some related options for night mode and dock mode
- */
-class OrientationMenuAction extends SubmenuAction {
- // Constants used to indicate what type of menu is being shown, such that
- // the submenus can lazily construct their contents
- private static final int MENU_NIGHTMODE = 1;
- private static final int MENU_UIMODE = 2;
-
- private final ConfigurationChooser mConfigChooser;
- /** Type of menu; one of the constants {@link #MENU_NIGHTMODE} etc */
- private final int mType;
-
- OrientationMenuAction(int type, String title, ConfigurationChooser configuration) {
- super(title);
- mType = type;
- mConfigChooser = configuration;
- }
-
- static void showMenu(ConfigurationChooser configChooser, ToolItem combo) {
- MenuManager manager = new MenuManager();
-
- // Show toggles for all the available states
-
- Configuration configuration = configChooser.getConfiguration();
- Device device = configuration.getDevice();
- State current = configuration.getDeviceState();
- if (device != null) {
- List<State> states = device.getAllStates();
-
- if (states.size() > 1 && current != null) {
- State flip = configuration.getNextDeviceState(current);
- String flipName = flip != null ? flip.getName() : current.getName();
- manager.add(new DeviceConfigAction(configChooser,
- String.format("Switch to %1$s", flipName), flip, false, true));
- manager.add(new Separator());
- }
-
- for (State config : states) {
- manager.add(new DeviceConfigAction(configChooser, config.getName(),
- config, config == current, false));
- }
- manager.add(new Separator());
- }
- manager.add(new OrientationMenuAction(MENU_UIMODE, "UI Mode", configChooser));
- manager.add(new Separator());
- manager.add(new OrientationMenuAction(MENU_NIGHTMODE, "Night Mode", configChooser));
-
- Menu menu = manager.createContextMenu(configChooser.getShell());
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-
- @Override
- protected void addMenuItems(Menu menu) {
- switch (mType) {
- case MENU_NIGHTMODE: {
- NightMode selected = mConfigChooser.getConfiguration().getNightMode();
- for (NightMode mode : NightMode.values()) {
- boolean checked = mode == selected;
- SelectNightModeAction action = new SelectNightModeAction(mode, checked);
- new ActionContributionItem(action).fill(menu, -1);
-
- }
- break;
- }
- case MENU_UIMODE: {
- UiMode selected = mConfigChooser.getConfiguration().getUiMode();
- for (UiMode mode : UiMode.values()) {
- boolean checked = mode == selected;
- SelectUiModeAction action = new SelectUiModeAction(mode, checked);
- new ActionContributionItem(action).fill(menu, -1);
- }
- break;
- }
- }
- }
-
-
- private class SelectNightModeAction extends Action {
- private final NightMode mMode;
-
- private SelectNightModeAction(NightMode mode, boolean checked) {
- super(mode.getLongDisplayValue(), IAction.AS_RADIO_BUTTON);
- mMode = mode;
- if (checked) {
- setChecked(true);
- }
- }
-
- @Override
- public void run() {
- Configuration configuration = mConfigChooser.getConfiguration();
- configuration.setNightMode(mMode, false);
- mConfigChooser.notifyFolderConfigChanged();
- }
- }
-
- private class SelectUiModeAction extends Action {
- private final UiMode mMode;
-
- private SelectUiModeAction(UiMode mode, boolean checked) {
- super(mode.getLongDisplayValue(), IAction.AS_RADIO_BUTTON);
- mMode = mode;
- if (checked) {
- setChecked(true);
- }
- }
-
- @Override
- public void run() {
- Configuration configuration = mConfigChooser.getConfiguration();
- configuration.setUiMode(mMode, false);
- }
- }
-
- private static class DeviceConfigAction extends Action {
- private final ConfigurationChooser mConfiguration;
- private final State mState;
-
- private DeviceConfigAction(ConfigurationChooser configuration, String title,
- State state, boolean checked, boolean flip) {
- super(title, IAction.AS_RADIO_BUTTON);
- mConfiguration = configuration;
- mState = state;
- if (checked) {
- setChecked(true);
- }
- ScreenOrientation orientation = configuration.getOrientation(state);
- setImageDescriptor(configuration.getOrientationImage(orientation, flip));
- }
-
- @Override
- public void run() {
- mConfiguration.selectDeviceState(mState);
- mConfiguration.onDeviceConfigChange();
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/SelectThemeAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/SelectThemeAction.java
deleted file mode 100644
index d062849d1..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/SelectThemeAction.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-import static com.android.SdkConstants.STYLE_RESOURCE_PREFIX;
-
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.IAction;
-
-/**
- * Action which brings up the "Create new XML File" wizard, pre-selected with the
- * animation category
- */
-class SelectThemeAction extends Action {
- private final ConfigurationChooser mConfiguration;
- private final String mTheme;
-
- public SelectThemeAction(ConfigurationChooser configuration, String title, String theme,
- boolean selected) {
- super(title, IAction.AS_RADIO_BUTTON);
- assert theme.startsWith(STYLE_RESOURCE_PREFIX)
- || theme.startsWith(ANDROID_STYLE_RESOURCE_PREFIX) : theme;
- mConfiguration = configuration;
- mTheme = theme;
- if (selected) {
- setChecked(selected);
- }
- }
-
- @Override
- public void run() {
- mConfiguration.selectTheme(mTheme);
- mConfiguration.onThemeChange();
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/TargetMenuListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/TargetMenuListener.java
deleted file mode 100644
index 71905f7c9..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/TargetMenuListener.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.sdklib.AndroidVersion;
-import com.android.sdklib.IAndroidTarget;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.MenuItem;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.List;
-import java.util.RandomAccess;
-
-/**
- * The {@linkplain TargetMenuListener} class is responsible for
- * generating the rendering target menu in the {@link ConfigurationChooser}.
- */
-class TargetMenuListener extends SelectionAdapter {
- private final ConfigurationChooser mConfigChooser;
- private final IAndroidTarget mTarget;
- private final boolean mPickBest;
-
- TargetMenuListener(
- @NonNull ConfigurationChooser configChooser,
- @Nullable IAndroidTarget target,
- boolean pickBest) {
- mConfigChooser = configChooser;
- mTarget = target;
- mPickBest = pickBest;
- }
-
- @Override
- public void widgetSelected(SelectionEvent e) {
- IAndroidTarget target = mTarget;
- AdtPrefs prefs = AdtPrefs.getPrefs();
- if (mPickBest) {
- boolean autoPick = prefs.isAutoPickRenderTarget();
- autoPick = !autoPick;
- prefs.setAutoPickRenderTarget(autoPick);
- if (autoPick) {
- target = ConfigurationMatcher.findDefaultRenderTarget(mConfigChooser);
- } else {
- // Turn it off, but keep current target until another one is chosen
- return;
- }
- } else {
- // Manually picked some other target: turn off auto-pick
- prefs.setAutoPickRenderTarget(false);
- }
- mConfigChooser.selectTarget(target);
- mConfigChooser.onRenderingTargetChange();
- }
-
- static void show(ConfigurationChooser chooser, ToolItem combo) {
- Menu menu = new Menu(chooser.getShell(), SWT.POP_UP);
- Configuration configuration = chooser.getConfiguration();
- IAndroidTarget current = configuration.getTarget();
- List<IAndroidTarget> targets = chooser.getTargetList();
- boolean haveRecent = false;
-
- MenuItem menuItem = new MenuItem(menu, SWT.CHECK);
- menuItem.setText("Automatically Pick Best");
- menuItem.addSelectionListener(new TargetMenuListener(chooser, null, true));
- if (AdtPrefs.getPrefs().isAutoPickRenderTarget()) {
- menuItem.setSelection(true);
- }
-
- @SuppressWarnings("unused")
- MenuItem separator = new MenuItem(menu, SWT.SEPARATOR);
-
- // Process in reverse order: most important targets first
- assert targets instanceof RandomAccess;
- for (int i = targets.size() - 1; i >= 0; i--) {
- IAndroidTarget target = targets.get(i);
-
- AndroidVersion version = target.getVersion();
- if (version.getApiLevel() >= 7) {
- haveRecent = true;
- } else if (haveRecent) {
- // Don't show ancient rendering targets; they're pretty broken
- // (unless of course all you have are ancient targets)
- break;
- }
-
- String title = ConfigurationChooser.getRenderingTargetLabel(target, false);
- MenuItem item = new MenuItem(menu, SWT.CHECK);
- item.setText(title);
-
- boolean selected = current == target;
- if (selected) {
- item.setSelection(true);
- }
-
- item.addSelectionListener(new TargetMenuListener(chooser, target, false));
- }
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java
deleted file mode 100644
index b1ce21d36..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_STYLE_RESOURCE_PREFIX;
-
-import com.android.ide.eclipse.adt.internal.editors.Hyperlinks;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SubmenuAction;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo.ActivityAttributes;
-import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-import com.android.sdklib.IAndroidTarget;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.ActionContributionItem;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.action.MenuManager;
-import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.text.hyperlink.IHyperlink;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Menu;
-import org.eclipse.swt.widgets.ToolItem;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Action which creates a submenu displaying available themes
- */
-class ThemeMenuAction extends SubmenuAction {
- private static final String DEVICE_LIGHT_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX + "Theme.DeviceDefault.Light"; //$NON-NLS-1$
- private static final String HOLO_LIGHT_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX + "Theme.Holo.Light"; //$NON-NLS-1$
- private static final String DEVICE_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX + "Theme.DeviceDefault"; //$NON-NLS-1$
- private static final String HOLO_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX + "Theme.Holo"; //$NON-NLS-1$
- private static final String LIGHT_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX +"Theme.Light"; //$NON-NLS-1$
- private static final String THEME_PREFIX =
- ANDROID_STYLE_RESOURCE_PREFIX +"Theme"; //$NON-NLS-1$
-
- // Constants used to indicate what type of menu is being shown, such that
- // the submenus can lazily construct their contents
- private static final int MENU_MANIFEST = 1;
- private static final int MENU_PROJECT = 2;
- private static final int MENU_THEME = 3;
- private static final int MENU_THEME_LIGHT = 4;
- private static final int MENU_HOLO = 5;
- private static final int MENU_HOLO_LIGHT = 6;
- private static final int MENU_DEVICE = 7;
- private static final int MENU_DEVICE_LIGHT = 8;
- private static final int MENU_ALL = 9;
-
- private final ConfigurationChooser mConfigChooser;
- private final List<String> mThemeList;
- /** Type of menu; one of the constants {@link #MENU_ALL} etc */
- private final int mType;
-
- ThemeMenuAction(int type, String title, ConfigurationChooser configuration,
- List<String> themeList) {
- super(title);
- mType = type;
- mConfigChooser = configuration;
- mThemeList = themeList;
- }
-
- static void showThemeMenu(ConfigurationChooser configChooser, ToolItem combo,
- List<String> themeList) {
- MenuManager manager = new MenuManager();
-
- // First show the currently selected theme (grayed out since you can't
- // reselect it)
- Configuration configuration = configChooser.getConfiguration();
- String currentTheme = configuration.getTheme();
- String currentName = null;
- if (currentTheme != null) {
- currentName = ResourceHelper.styleToTheme(currentTheme);
- SelectThemeAction action = new SelectThemeAction(configChooser,
- currentName,
- currentTheme,
- true /* selected */);
- action.setEnabled(false);
- manager.add(action);
- manager.add(new Separator());
- }
-
- String preferred = configuration.computePreferredTheme();
- if (preferred != null && !preferred.equals(currentTheme)) {
- manager.add(new SelectThemeAction(configChooser,
- ResourceHelper.styleToTheme(preferred),
- preferred, false /* selected */));
- manager.add(new Separator());
- }
-
- IAndroidTarget target = configuration.getTarget();
- int apiLevel = target != null ? target.getVersion().getApiLevel() : 1;
- boolean hasHolo = apiLevel >= 11; // Honeycomb
- boolean hasDeviceDefault = apiLevel >= 14; // ICS
-
- // TODO: Add variations of the current theme here, e.g.
- // if you're using Theme.Holo, add Theme.Holo.Dialog, Theme.Holo.Panel,
- // Theme.Holo.Wallpaper etc
-
- manager.add(new ThemeMenuAction(MENU_PROJECT, "Project Themes",
- configChooser, themeList));
- manager.add(new ThemeMenuAction(MENU_MANIFEST, "Manifest Themes",
- configChooser, themeList));
-
- manager.add(new Separator());
-
- if (hasHolo) {
- manager.add(new ThemeMenuAction(MENU_HOLO, "Holo",
- configChooser, themeList));
- manager.add(new ThemeMenuAction(MENU_HOLO_LIGHT, "Holo.Light",
- configChooser, themeList));
- }
- if (hasDeviceDefault) {
- manager.add(new ThemeMenuAction(MENU_DEVICE, "DeviceDefault",
- configChooser, themeList));
- manager.add(new ThemeMenuAction(MENU_DEVICE_LIGHT, "DeviceDefault.Light",
- configChooser, themeList));
- }
- manager.add(new ThemeMenuAction(MENU_THEME, "Theme",
- configChooser, themeList));
- manager.add(new ThemeMenuAction(MENU_THEME_LIGHT, "Theme.Light",
- configChooser, themeList));
-
- // TODO: Add generic types like Wallpaper, Dialog, Alert, etc here, with
- // submenus for picking it within each theme category?
-
- manager.add(new Separator());
- manager.add(new ThemeMenuAction(MENU_ALL, "All",
- configChooser, themeList));
-
- if (currentTheme != null) {
- assert currentName != null;
- manager.add(new Separator());
- String title = String.format("Open %1$s Declaration...", currentName);
- manager.add(new OpenThemeAction(title, configChooser.getEditedFile(), currentTheme));
- }
-
- Menu menu = manager.createContextMenu(configChooser.getShell());
-
- Rectangle bounds = combo.getBounds();
- Point location = new Point(bounds.x, bounds.y + bounds.height);
- location = combo.getParent().toDisplay(location);
- menu.setLocation(location.x, location.y);
- menu.setVisible(true);
- }
-
- @Override
- protected void addMenuItems(Menu menu) {
- switch (mType) {
- case MENU_ALL:
- addMenuItems(menu, mThemeList);
- break;
-
- case MENU_MANIFEST: {
- IProject project = mConfigChooser.getEditedFile().getProject();
- ManifestInfo manifest = ManifestInfo.get(project);
- Configuration configuration = mConfigChooser.getConfiguration();
- String activity = configuration.getActivity();
- if (activity != null) {
- ActivityAttributes attributes = manifest.getActivityAttributes(activity);
- if (attributes != null) {
- String theme = attributes.getTheme();
- if (theme != null) {
- addMenuItem(menu, theme, isSelectedTheme(theme));
- }
- }
- }
-
- String manifestTheme = manifest.getManifestTheme();
- boolean found = false;
- Set<String> allThemes = new HashSet<String>();
- if (manifestTheme != null) {
- found = true;
- allThemes.add(manifestTheme);
- }
- for (ActivityAttributes info : manifest.getActivityAttributesMap().values()) {
- if (info.getTheme() != null) {
- found = true;
- allThemes.add(info.getTheme());
- }
- }
- List<String> sorted = new ArrayList<String>(allThemes);
- Collections.sort(sorted);
- String current = configuration.getTheme();
- for (String theme : sorted) {
- boolean selected = theme.equals(current);
- addMenuItem(menu, theme, selected);
- }
- if (!found) {
- addDisabledMessageItem("No themes are registered in the manifest");
- }
- break;
- }
- case MENU_PROJECT: {
- int size = mThemeList.size();
- List<String> themes = new ArrayList<String>(size);
- for (int i = 0; i < size; i++) {
- String theme = mThemeList.get(i);
- if (ResourceHelper.isProjectStyle(theme)) {
- themes.add(theme);
- }
- }
- if (themes.isEmpty()) {
- addDisabledMessageItem("There are no local theme styles in the project");
- } else {
- addMenuItems(menu, themes);
- }
- break;
- }
- case MENU_THEME: {
- // Can't just use the usual filterThemes() call here because we need
- // to exclude on multiple prefixes: Holo, DeviceDefault, Light, ...
- List<String> themes = new ArrayList<String>(mThemeList.size());
- for (String theme : mThemeList) {
- if (theme.startsWith(THEME_PREFIX)
- && !theme.startsWith(LIGHT_PREFIX)
- && !theme.startsWith(HOLO_PREFIX)
- && !theme.startsWith(DEVICE_PREFIX)) {
- themes.add(theme);
- }
- }
-
- addMenuItems(menu, themes);
- break;
- }
- case MENU_THEME_LIGHT:
- addMenuItems(menu, filterThemes(LIGHT_PREFIX, null));
- break;
- case MENU_HOLO:
- addMenuItems(menu, filterThemes(HOLO_PREFIX, HOLO_LIGHT_PREFIX));
- break;
- case MENU_HOLO_LIGHT:
- addMenuItems(menu, filterThemes(HOLO_LIGHT_PREFIX, null));
- break;
- case MENU_DEVICE:
- addMenuItems(menu, filterThemes(DEVICE_PREFIX, DEVICE_LIGHT_PREFIX));
- break;
- case MENU_DEVICE_LIGHT:
- addMenuItems(menu, filterThemes(DEVICE_LIGHT_PREFIX, null));
- break;
- }
- }
-
- private List<String> filterThemes(String include, String exclude) {
- List<String> themes = new ArrayList<String>(mThemeList.size());
- for (String theme : mThemeList) {
- if (theme.startsWith(include) && (exclude == null || !theme.startsWith(exclude))) {
- themes.add(theme);
- }
- }
-
- return themes;
- }
-
- private void addMenuItems(Menu menu, List<String> themes) {
- String current = mConfigChooser.getConfiguration().getTheme();
- for (String theme : themes) {
- addMenuItem(menu, theme, theme.equals(current));
- }
- }
-
- private boolean isSelectedTheme(String theme) {
- return theme.equals(mConfigChooser.getConfiguration().getTheme());
- }
-
- private void addMenuItem(Menu menu, String theme, boolean selected) {
- String title = ResourceHelper.styleToTheme(theme);
- SelectThemeAction action = new SelectThemeAction(mConfigChooser, title, theme, selected);
- new ActionContributionItem(action).fill(menu, -1);
- }
-
- private static class OpenThemeAction extends Action {
- private final String mTheme;
- private final IFile mFile;
-
- private OpenThemeAction(String title, IFile file, String theme) {
- super(title, IAction.AS_PUSH_BUTTON);
- mFile = file;
- mTheme = theme;
- }
-
- @Override
- public void run() {
- IProject project = mFile.getProject();
- IHyperlink[] links = Hyperlinks.getResourceLinks(null, mTheme, project, null);
- if (links != null && links.length > 0) {
- IHyperlink link = links[0];
- link.open();
- }
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/VaryingConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/VaryingConfiguration.java
deleted file mode 100644
index f472cd6b3..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/VaryingConfiguration.java
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * 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.rendering.api.Capability;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.resources.Density;
-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.Hardware;
-import com.android.sdklib.devices.Screen;
-import com.android.sdklib.devices.State;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * An {@linkplain VaryingConfiguration} 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, and the overridden value
- * will always <b>differ</b> from the inherited value!
- * <p>
- * For example, a {@linkplain VaryingConfiguration} may state that it
- * overrides the locale, and if the inherited locale is "en", then the returned
- * locale from the {@linkplain VaryingConfiguration} may be for example "nb",
- * but never "en".
- * <p>
- * The configuration will attempt to make its changed inherited value to be as
- * different as possible from the inherited value. Thus, a configuration which
- * overrides the device will probably return a phone-sized screen if the
- * inherited device is a tablet, or vice versa.
- */
-public class VaryingConfiguration extends NestedConfiguration {
- /** Variation version; see {@link #setVariation(int)} */
- private int mVariation;
-
- /** Variation version count; see {@link #setVariationCount(int)} */
- private int mVariationCount;
-
- /** Bitmask of attributes to be varied/alternated from the parent */
- private int mAlternate;
-
- /**
- * Constructs a new {@linkplain VaryingConfiguration}.
- * Construct via
- *
- * @param chooser the associated chooser
- * @param configuration the configuration to inherit from
- */
- private VaryingConfiguration(
- @NonNull ConfigurationChooser chooser,
- @NonNull Configuration configuration) {
- super(chooser, configuration);
- }
-
- /**
- * 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 VaryingConfiguration create(@NonNull ConfigurationChooser chooser,
- @NonNull Configuration parent) {
- return new VaryingConfiguration(chooser, parent);
- }
-
- /**
- * Creates a new {@linkplain VaryingConfiguration} that has the same overriding
- * attributes as the given other {@linkplain VaryingConfiguration}.
- *
- * @param other the configuration to copy overrides from
- * @param parent the parent to tie the configuration to for inheriting values
- * @return a new configuration
- */
- @NonNull
- public static VaryingConfiguration create(
- @NonNull VaryingConfiguration other,
- @NonNull Configuration parent) {
- VaryingConfiguration configuration =
- new VaryingConfiguration(other.mConfigChooser, parent);
- initFrom(configuration, other, other, false);
- configuration.mAlternate = other.mAlternate;
- configuration.mVariation = other.mVariation;
- configuration.mVariationCount = other.mVariationCount;
- configuration.syncFolderConfig();
-
- return configuration;
- }
-
- /**
- * Returns the alternate flags for this configuration. Corresponds to
- * the {@code CFG_} flags in {@link ConfigurationClient}.
- *
- * @return the bitmask
- */
- public int getAlternateFlags() {
- return mAlternate;
- }
-
- @Override
- public void syncFolderConfig() {
- super.syncFolderConfig();
- updateDisplayName();
- }
-
- /**
- * Sets the variation version for this
- * {@linkplain VaryingConfiguration}. There might be multiple
- * {@linkplain VaryingConfiguration} instances inheriting from a
- * {@link Configuration}. The variation version allows them to choose
- * different complementing values, so they don't all flip to the same other
- * (out of multiple choices) value. The {@link #setVariationCount(int)}
- * value can be used to determine how to partition the buckets of values.
- * Also updates the variation count if necessary.
- *
- * @param variation variation version
- */
- public void setVariation(int variation) {
- mVariation = variation;
- mVariationCount = Math.max(mVariationCount, variation + 1);
- }
-
- /**
- * Sets the number of {@link VaryingConfiguration} variations mapped
- * to the same parent configuration as this one. See
- * {@link #setVariation(int)} for details.
- *
- * @param count the total number of variation versions
- */
- public void setVariationCount(int count) {
- mVariationCount = count;
- }
-
- /**
- * Updates the display name in this configuration based on the values and override settings
- */
- public void updateDisplayName() {
- setDisplayName(computeDisplayName());
- }
-
- @Override
- @NonNull
- public Locale getLocale() {
- if (isOverridingLocale()) {
- return super.getLocale();
- }
- Locale locale = mParent.getLocale();
- if (isAlternatingLocale() && locale != null) {
- List<Locale> locales = mConfigChooser.getLocaleList();
- for (Locale l : locales) {
- // TODO: Try to be smarter about which one we pick; for example, try
- // to pick a language that is substantially different from the inherited
- // language, such as either with the strings of the largest or shortest
- // length, or perhaps based on some geography or population metrics
- if (!l.equals(locale)) {
- locale = l;
- break;
- }
- }
- }
-
- return locale;
- }
-
- @Override
- @Nullable
- public IAndroidTarget getTarget() {
- if (isOverridingTarget()) {
- return super.getTarget();
- }
- IAndroidTarget target = mParent.getTarget();
- if (isAlternatingTarget() && target != null) {
- List<IAndroidTarget> targets = mConfigChooser.getTargetList();
- if (!targets.isEmpty()) {
- // Pick a different target: if you're showing the most recent render target,
- // then pick the lowest supported target, and vice versa
- IAndroidTarget mostRecent = targets.get(targets.size() - 1);
- if (target.equals(mostRecent)) {
- // Find oldest supported
- ManifestInfo info = ManifestInfo.get(mConfigChooser.getProject());
- int minSdkVersion = info.getMinSdkVersion();
- for (IAndroidTarget t : targets) {
- if (t.getVersion().getApiLevel() >= minSdkVersion) {
- target = t;
- break;
- }
- }
- } else {
- target = mostRecent;
- }
- }
- }
-
- return target;
- }
-
- // Cached values, key=parent's device, cached value=device
- private Device mPrevParentDevice;
- private Device mPrevDevice;
-
- @Override
- @Nullable
- public Device getDevice() {
- if (isOverridingDevice()) {
- return super.getDevice();
- }
- Device device = mParent.getDevice();
- if (isAlternatingDevice() && device != null) {
- if (device == mPrevParentDevice) {
- return mPrevDevice;
- }
-
- mPrevParentDevice = device;
-
- // Pick a different device
- Collection<Device> devices = mConfigChooser.getDevices();
-
- // Divide up the available devices into {@link #mVariationCount} + 1 buckets
- // (the + 1 is for the bucket now taken up by the inherited value).
- // Then assign buckets to each {@link #mVariation} version, and pick one
- // from the bucket assigned to this current configuration's variation version.
-
- // I could just divide up the device list count, but that would treat a lot of
- // very similar phones as having the same kind of variety as the 7" and 10"
- // tablets which are sitting right next to each other in the device list.
- // Instead, do this by screen size.
-
-
- double smallest = 100;
- double biggest = 1;
- for (Device d : devices) {
- double size = getScreenSize(d);
- if (size < 0) {
- continue; // no data
- }
- if (size >= biggest) {
- biggest = size;
- }
- if (size <= smallest) {
- smallest = size;
- }
- }
-
- int bucketCount = mVariationCount + 1;
- double inchesPerBucket = (biggest - smallest) / bucketCount;
-
- double overriddenSize = getScreenSize(device);
- int overriddenBucket = (int) ((overriddenSize - smallest) / inchesPerBucket);
- int bucket = (mVariation < overriddenBucket) ? mVariation : mVariation + 1;
- double from = inchesPerBucket * bucket + smallest;
- double to = from + inchesPerBucket;
- if (biggest - to < 0.1) {
- to = biggest + 0.1;
- }
-
- boolean canScaleNinePatch = supports(Capability.FIXED_SCALABLE_NINE_PATCH);
- for (Device d : devices) {
- double size = getScreenSize(d);
- if (size >= from && size < to) {
- if (!canScaleNinePatch) {
- Density density = getDensity(d);
- if (density == Density.TV || density == Density.LOW) {
- continue;
- }
- }
-
- device = d;
- break;
- }
- }
-
- mPrevDevice = device;
- }
-
- return device;
- }
-
- /**
- * Returns the density of the given device
- *
- * @param device the device to check
- * @return the density or null
- */
- @Nullable
- private static Density getDensity(@NonNull Device device) {
- Hardware hardware = device.getDefaultHardware();
- if (hardware != null) {
- Screen screen = hardware.getScreen();
- if (screen != null) {
- return screen.getPixelDensity();
- }
- }
-
- return null;
- }
-
- /**
- * Returns the diagonal length of the given device
- *
- * @param device the device to check
- * @return the diagonal length or -1
- */
- private static double getScreenSize(@NonNull Device device) {
- Hardware hardware = device.getDefaultHardware();
- if (hardware != null) {
- Screen screen = hardware.getScreen();
- if (screen != null) {
- return screen.getDiagonalLength();
- }
- }
-
- return -1;
- }
-
- @Override
- @Nullable
- public State getDeviceState() {
- if (isOverridingDeviceState()) {
- return super.getDeviceState();
- }
- State state = mParent.getDeviceState();
- if (isAlternatingDeviceState() && state != null) {
- State alternate = getNextDeviceState(state);
-
- return alternate;
- } else {
- if ((isAlternatingDevice() || isOverridingDevice()) && state != null) {
- // If the device differs, I need to look up a suitable equivalent state
- // on our device
- Device device = getDevice();
- if (device != null) {
- return device.getState(state.getName());
- }
- }
-
- return state;
- }
- }
-
- @Override
- @NonNull
- public NightMode getNightMode() {
- if (isOverridingNightMode()) {
- return super.getNightMode();
- }
- NightMode nightMode = mParent.getNightMode();
- if (isAlternatingNightMode() && nightMode != null) {
- nightMode = nightMode == NightMode.NIGHT ? NightMode.NOTNIGHT : NightMode.NIGHT;
- return nightMode;
- } else {
- return nightMode;
- }
- }
-
- @Override
- @NonNull
- public UiMode getUiMode() {
- if (isOverridingUiMode()) {
- return super.getUiMode();
- }
- UiMode uiMode = mParent.getUiMode();
- if (isAlternatingUiMode() && uiMode != null) {
- // TODO: Use manifest's supports screen to decide which are most relevant
- // (as well as which available configuration qualifiers are present in the
- // layout)
- UiMode[] values = UiMode.values();
- uiMode = values[(uiMode.ordinal() + 1) % values.length];
- return uiMode;
- } else {
- return uiMode;
- }
- }
-
- @Override
- @Nullable
- public String computeDisplayName() {
- return computeDisplayName(getOverrideFlags() | mAlternate, this);
- }
-
- /**
- * Sets whether the locale should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateLocale(boolean alternate) {
- mAlternate |= CFG_LOCALE;
- }
-
- /**
- * Returns true if the locale is alternated
- *
- * @return true if the locale is alternated
- */
- public final boolean isAlternatingLocale() {
- return (mAlternate & CFG_LOCALE) != 0;
- }
-
- /**
- * Sets whether the rendering target should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateTarget(boolean alternate) {
- mAlternate |= CFG_TARGET;
- }
-
- /**
- * Returns true if the target is alternated
- *
- * @return true if the target is alternated
- */
- public final boolean isAlternatingTarget() {
- return (mAlternate & CFG_TARGET) != 0;
- }
-
- /**
- * Sets whether the device should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateDevice(boolean alternate) {
- mAlternate |= CFG_DEVICE;
- }
-
- /**
- * Returns true if the device is alternated
- *
- * @return true if the device is alternated
- */
- public final boolean isAlternatingDevice() {
- return (mAlternate & CFG_DEVICE) != 0;
- }
-
- /**
- * Sets whether the device state should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateDeviceState(boolean alternate) {
- mAlternate |= CFG_DEVICE_STATE;
- }
-
- /**
- * Returns true if the device state is alternated
- *
- * @return true if the device state is alternated
- */
- public final boolean isAlternatingDeviceState() {
- return (mAlternate & CFG_DEVICE_STATE) != 0;
- }
-
- /**
- * Sets whether the night mode should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateNightMode(boolean alternate) {
- mAlternate |= CFG_NIGHT_MODE;
- }
-
- /**
- * Returns true if the night mode is alternated
- *
- * @return true if the night mode is alternated
- */
- public final boolean isAlternatingNightMode() {
- return (mAlternate & CFG_NIGHT_MODE) != 0;
- }
-
- /**
- * Sets whether the UI mode should be alternated by this configuration
- *
- * @param alternate if true, alternate the inherited value
- */
- public void setAlternateUiMode(boolean alternate) {
- mAlternate |= CFG_UI_MODE;
- }
-
- /**
- * Returns true if the UI mode is alternated
- *
- * @return true if the UI mode is alternated
- */
- public final boolean isAlternatingUiMode() {
- return (mAlternate & CFG_UI_MODE) != 0;
- }
-
-} \ No newline at end of file