diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java | 318 |
1 files changed, 318 insertions, 0 deletions
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 new file mode 100644 index 000000000..b1ce21d36 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ThemeMenuAction.java @@ -0,0 +1,318 @@ +/* + * 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(); + } + } + } +} |