diff options
author | Xavier Ducrohet <xav@android.com> | 2010-01-08 16:24:55 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-01-11 15:44:36 -0800 |
commit | 00515b526cb0c6e23dcc2c4eb1b2abe65006a47e (patch) | |
tree | 5b121c05b6bb6da0f2d775ec26384f71d4d46e6d | |
parent | cc2a02011f08f89cb7e9f1c129f8eb813348de38 (diff) | |
download | sdk-00515b526cb0c6e23dcc2c4eb1b2abe65006a47e.zip sdk-00515b526cb0c6e23dcc2c4eb1b2abe65006a47e.tar.gz sdk-00515b526cb0c6e23dcc2c4eb1b2abe65006a47e.tar.bz2 |
ADT/GLE: Fix config selector to not select a config that has a better match than the current file.
When replacing a file with another one (because of a user "open action")
it is possible the config selector will find the current config compatible,
even though the previous layout was a better for match for it.
The config selector now attemps to find a config for which the new
file is the best match.
Change-Id: I7d794c2a8b9a90a120970049cb402f9ee84f8749
7 files changed, 388 insertions, 219 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java index 3cfa50f..9a1430b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java @@ -103,6 +103,9 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang * SDK location change or a project target change */ private TargetChangeListener mTargetListener = null; + /** flag set during page creation */ + private boolean mIsCreatingPage = false; + /** * Creates a form editor. * <p/>The editor will setup a {@link ITargetChangeListener} and call @@ -190,10 +193,19 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang * Creates the page for the Android Editors */ protected void createAndroidPages() { + mIsCreatingPage = true; createFormPages(); createTextEditor(); createUndoRedoActions(); + mIsCreatingPage = false; + } + + /** + * Returns whether the editor is currently creating its pages. + */ + public boolean isCreatingPages() { + return mIsCreatingPage; } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java index cfb3e1c..85427a9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java @@ -29,6 +29,10 @@ import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrien import com.android.ide.eclipse.adt.internal.resources.configurations.PixelDensityQualifier.Density; import com.android.ide.eclipse.adt.internal.resources.configurations.ScreenOrientationQualifier.ScreenOrientation; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolder; +import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; +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.LayoutDevice; import com.android.ide.eclipse.adt.internal.sdk.LayoutDeviceManager; @@ -40,6 +44,10 @@ import com.android.layoutlib.api.IResourceValue; import com.android.layoutlib.api.IStyleResourceValue; import com.android.sdklib.IAndroidTarget; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IStatus; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -101,9 +109,6 @@ public class ConfigurationComposite extends Composite { private int mPlatformThemeCount = 0; private boolean mDisableUpdates = false; - /** The {@link FolderConfiguration} representing the state of the UI controls */ - private final FolderConfiguration mCurrentConfig = new FolderConfiguration(); - private List<LayoutDevice> mDeviceList; private final ArrayList<ResourceQualifier[] > mLocaleList = @@ -120,15 +125,24 @@ public class ConfigurationComposite extends Composite { */ private LayoutDevice mCurrentDevice; + private SelectionState mCurrentState = null; + + private boolean mSdkChanged = false; + /** The config listener given to the constructor. Never null. */ private final IConfigListener mListener; - private FolderConfiguration mEditedConfig; - private IAndroidTarget mTarget; - - private SelectionState mCurrentState = null; + /** The {@link FolderConfiguration} representing the state of the UI controls */ + private final FolderConfiguration mCurrentConfig = new FolderConfiguration(); - private boolean mSdkChanged = false; + /** 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 mTarget; + /** The {@link FolderConfiguration} being edited. */ + private FolderConfiguration mEditedConfig; /** * Interface implemented by the part which owns a {@link ConfigurationComposite}. @@ -356,15 +370,14 @@ public class ConfigurationComposite extends Composite { * The state of the selection of the various combos will be initialized to default values that * are compatible with the opened file. * - * @param fileConfig The {@link FolderConfiguration} of the opened file. - * @param target the {@link IAndroidTarget} of the file's project. + * @param file the file being opened * * @see #replaceFile(FolderConfiguration) * @see #changeFileOnNewConfig(FolderConfiguration) */ - public void openFile(FolderConfiguration fileConfig, IAndroidTarget target) { - mTarget = target; - mEditedConfig = fileConfig; + public void openFile(IFile file) { + mEditedFile = file; + IProject iProject = mEditedFile.getProject(); mDisableUpdates = true; // we do not want to trigger onXXXChange when setting // new values in the widgets. @@ -375,9 +388,18 @@ public class ConfigurationComposite extends Composite { // init the devices since the SDK is loaded. initDevices(); - LoadStatus targetStatus = Sdk.getCurrent().checkAndLoadTargetData(target, null); + Sdk currentSdk = Sdk.getCurrent(); + if (currentSdk != null) { + mTarget = currentSdk.getTarget(iProject); + } + + LoadStatus targetStatus = Sdk.getCurrent().checkAndLoadTargetData(mTarget, null); if (targetStatus == LoadStatus.LOADED) { + mResources = ResourceManager.getInstance().getProjectResources(iProject); + ResourceFolder resFolder = mResources.getResourceFolder((IFolder)file.getParent()); + mEditedConfig = resFolder.getConfiguration(); + // update the themes and locales. updateThemes(); updateLocales(); @@ -389,18 +411,14 @@ public class ConfigurationComposite extends Composite { setClippingSupport(bridge.apiLevel >= 4); } - // attempt to find a device that can display this particular config. - findAndSetCompatibleConfig(fileConfig); - - // find a locale matching this file config - findAndSetCompatibleLocale(fileConfig.getLanguageQualifier(), - fileConfig.getRegionQualifier()); + // attempt to find a device/locale that can display this particular config. + findAndSetCompatibleConfig(false /*favorCurrentConfig*/); // compute the final current config computeCurrentConfig(); // update the string showing the config value - updateConfigDisplay(fileConfig); + updateConfigDisplay(mEditedConfig); saveState(); } @@ -409,27 +427,31 @@ public class ConfigurationComposite extends Composite { mDisableUpdates = false; } - /** * 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. * <p/>This will NOT trigger a redraw event (will not call * {@link IConfigListener#onConfigurationChange()}.) - * + * @param file the file being opened. * @param fileConfig The {@link FolderConfiguration} of the opened file. * @param target the {@link IAndroidTarget} of the file's project. * * @see #replaceFile(FolderConfiguration) */ - public void replaceFile(FolderConfiguration fileConfig) { + public void replaceFile(IFile file) { // if there is no previous selection, revert to default mode. if (mCurrentDevice == null) { - openFile(fileConfig, mTarget); + openFile(file); return; } - mEditedConfig = fileConfig; + mEditedFile = file; + IProject iProject = mEditedFile.getProject(); + mResources = ResourceManager.getInstance().getProjectResources(iProject); + + ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); + mEditedConfig = resFolder.getConfiguration(); mDisableUpdates = true; // we do not want to trigger onXXXChange when setting // new values in the widgets. @@ -443,17 +465,13 @@ public class ConfigurationComposite extends Composite { // update the current config selection to make sure it's // compatible with the new file - adaptConfigSelectionToNewConfig(fileConfig); - - // find a locale matching this file config - findAndSetCompatibleLocale(fileConfig.getLanguageQualifier(), - fileConfig.getRegionQualifier()); + adaptConfigSelection(); // compute the final current config computeCurrentConfig(); // update the string showing the config value - updateConfigDisplay(fileConfig); + updateConfigDisplay(mEditedConfig); saveState(); } @@ -464,18 +482,22 @@ public class ConfigurationComposite extends Composite { /** * Updates the UI with a new file that was opened in response to a config change. - * @param fileConfig the file being opened. + * @param file the file being opened. * * @see #openFile(FolderConfiguration, IAndroidTarget) * @see #replaceFile(FolderConfiguration) */ - public void changeFileOnNewConfig(FolderConfiguration fileConfig) { - // there really isn't much to do since the combos were set by the user, and we don't want - // to touch them. - mEditedConfig = fileConfig; + public void changeFileOnNewConfig(IFile file) { + mEditedFile = file; + IProject iProject = mEditedFile.getProject(); + mResources = ResourceManager.getInstance().getProjectResources(iProject); + + ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); + mEditedConfig = resFolder.getConfiguration(); - // update the string showing the config value - updateConfigDisplay(fileConfig); + // All that's needed is to update the string showing the config value + // (since the config combo were chosen by the user). + updateConfigDisplay(mEditedConfig); } /** @@ -508,10 +530,22 @@ public class ConfigurationComposite extends Composite { if (mCurrentState == null) { // this means the file was opened before the target finished loaded. // This is basically an initial call to openFile that's delayed. - openFile(mEditedConfig, mTarget); + openFile(mEditedFile); return; } + // update the resource and config if they are not present + if (mResources == null) { + mResources = ResourceManager.getInstance().getProjectResources( + mEditedFile.getProject()); + } + + if (mEditedConfig == null) { + ResourceFolder resFolder = mResources.getResourceFolder( + (IFolder)mEditedFile.getParent()); + mEditedConfig = resFolder.getConfiguration(); + } + mDisableUpdates = true; // we do not want to trigger onXXXChange when setting // new values in the widgets. @@ -524,9 +558,9 @@ public class ConfigurationComposite extends Composite { // The former means the devices/configs are still there, the latter means they've // been reloaded (in #onSdkLoaded). if (mSdkChanged) { - findAndSetCompatibleConfig(mEditedConfig); + findAndSetCompatibleConfig(false /*favorCurrentConfig*/); } else { - adaptConfigSelectionToNewConfig(mEditedConfig); + adaptConfigSelection(); } // update the clipping state @@ -542,84 +576,171 @@ public class ConfigurationComposite extends Composite { } /** - * Finds a device/config that can display the given config. + * Finds a device/config that can display {@link #mEditedConfig}. * <p/>Once found the device and config combos are set to the config. - * <p/>If there is no compatible comfiguration, a custom one is created. - * @param fileConfig + * <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. */ - private void findAndSetCompatibleConfig(FolderConfiguration fileConfig) { - LayoutDevice deviceMatch = null; - String configMatchName = null; + private void findAndSetCompatibleConfig(boolean favorCurrentConfig) { + LayoutDevice anyDeviceMatch = null; // a compatible device/config/locale + String anyConfigMatchName = null; + int anyLocaleIndex = -1; + + LayoutDevice bestDeviceMatch = null; // an actual best match + String bestConfigMatchName = null; + int bestLocaleIndex = -1; + + FolderConfiguration testConfig = new FolderConfiguration(); mainloop: for (LayoutDevice device : mDeviceList) { for (Entry<String, FolderConfiguration> entry : device.getConfigs().entrySet()) { - if (fileConfig.isMatchFor(entry.getValue())) { - // this is what we want. - deviceMatch = device; - configMatchName = entry.getKey(); - break mainloop; + testConfig.set(entry.getValue()); + + // look on the locales. + for (int i = 0 ; i < mLocaleList.size() ; i++) { + ResourceQualifier[] locale = mLocaleList.get(i); + + // update the test config with the locale qualifiers + testConfig.setLanguageQualifier((LanguageQualifier)locale[LOCALE_LANG]); + testConfig.setRegionQualifier((RegionQualifier)locale[LOCALE_REGION]); + + if (mEditedConfig.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. + if (anyDeviceMatch == null) { + anyDeviceMatch = device; + anyConfigMatchName = entry.getKey(); + anyLocaleIndex = i; + } + + if (isCurrentFileBestMatchFor(testConfig)) { + // this is what we want. + bestDeviceMatch = device; + bestConfigMatchName = entry.getKey(); + bestLocaleIndex = i; + break mainloop; + } + } } } } - if (deviceMatch == null) { - // 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 config, - // and replace whatever qualifier required by the layout file. + if (bestDeviceMatch == null) { + if (favorCurrentConfig) { + // quick check + if (mEditedConfig.isMatchFor(mCurrentConfig) == false) { + 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.", + mEditedConfig.toDisplayString()), + String.format( + "Displaying it with '%1$s'", + mCurrentConfig.toDisplayString())); + } else if (anyDeviceMatch != null) { + // select the device anyway. + selectDevice(mCurrentDevice = anyDeviceMatch); + fillConfigCombo(anyConfigMatchName); + mLocaleCombo.select(anyLocaleIndex); + + // TODO: display a better warning! + computeCurrentConfig(); + AdtPlugin.printErrorToConsole(mEditedFile.getProject(), + String.format( + "'%1$s' is not a best match for any device/locale combination.", + mEditedConfig.toDisplayString()), + String.format( + "Displaying it with '%1$s'", + mCurrentConfig.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 config, + // and replace whatever qualifier required by the layout file. + } } else { - selectDevice(mCurrentDevice = deviceMatch); - fillConfigCombo(configMatchName); + selectDevice(mCurrentDevice = bestDeviceMatch); + fillConfigCombo(bestConfigMatchName); + mLocaleCombo.select(bestLocaleIndex); } } /** - * Adapts the current device/config selection so that it's compatible with a given config. + * Adapts the current device/config selection so that it's compatible with + * {@link #mEditedConfig}. * <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(FolderConfiguration)} - * @param fileConfig */ - private void adaptConfigSelectionToNewConfig(FolderConfiguration fileConfig) { + private void adaptConfigSelection() { // check the device config (ie sans locale) boolean needConfigChange = true; // if still true, we need to find another config. + boolean currentConfigIsCompatible = false; int configIndex = mDeviceConfigCombo.getSelectionIndex(); if (configIndex != -1) { String configName = mDeviceConfigCombo.getItem(configIndex); FolderConfiguration currentConfig = mCurrentDevice.getConfigs().get(configName); - if (fileConfig.isMatchFor(currentConfig)) { - needConfigChange = false; + if (mEditedConfig.isMatchFor(currentConfig)) { + currentConfigIsCompatible = true; // current config is compatible + if (isCurrentFileBestMatchFor(currentConfig)) { + needConfigChange = false; + } } } if (needConfigChange) { + // if the current config/locale isn't a correct match, then + // look for another config/locale in the same device. + FolderConfiguration testConfig = new FolderConfiguration(); + // first look in the current device. String matchName = null; + int localeIndex = -1; Map<String, FolderConfiguration> configs = mCurrentDevice.getConfigs(); - for (Entry<String, FolderConfiguration> entry : configs.entrySet()) { - if (fileConfig.isMatchFor(entry.getValue())) { - matchName = entry.getKey(); - break; + mainloop: for (Entry<String, FolderConfiguration> entry : configs.entrySet()) { + testConfig.set(entry.getValue()); + + // loop on the locales. + for (int i = 0 ; i < mLocaleList.size() ; i++) { + ResourceQualifier[] locale = mLocaleList.get(i); + + // update the test config with the locale qualifiers + testConfig.setLanguageQualifier((LanguageQualifier)locale[LOCALE_LANG]); + testConfig.setRegionQualifier((RegionQualifier)locale[LOCALE_REGION]); + + if (mEditedConfig.isMatchFor(testConfig) && + isCurrentFileBestMatchFor(testConfig)) { + matchName = entry.getKey(); + localeIndex = i; + break mainloop; + } } } if (matchName != null) { selectConfig(matchName); + mLocaleCombo.select(localeIndex); } else { - // attempt to find a device that can display this particular config. - findAndSetCompatibleConfig(fileConfig); + // no match in current device with any config/locale + // attempt to find another device that can display this particular config. + findAndSetCompatibleConfig(currentConfigIsCompatible); } } } - /** * 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. */ - private void findAndSetCompatibleLocale(ResourceQualifier language, ResourceQualifier region) { + private void setLocaleCombo(ResourceQualifier language, ResourceQualifier region) { // find the locale match. Since the locale list is based on the content of the // project resources there must be an exact match. // The only trick is that the region could be null in the fileConfig but in our @@ -751,7 +872,9 @@ public class ConfigurationComposite extends Composite { }); if (mCurrentState != null && mCurrentState.locale != null) { - findAndSetCompatibleLocale(mCurrentState.locale[LOCALE_LANG], + // FIXME: this may fails if the layout was deleted (and was the last one to have that local. + // (we have other problem in this case though) + setLocaleCombo(mCurrentState.locale[LOCALE_LANG], mCurrentState.locale[LOCALE_REGION]); } else { mLocaleCombo.select(0); @@ -874,6 +997,10 @@ public class ConfigurationComposite extends Composite { // ---- getters for the config selection values ---- + public FolderConfiguration getEditedConfig() { + return mEditedConfig; + } + public FolderConfiguration getCurrentConfig() { return mCurrentConfig; } @@ -1146,11 +1273,11 @@ public class ConfigurationComposite extends Composite { // reset the UI as if it was just a replacement file, since we can keep // the current device (and possibly config). - adaptConfigSelectionToNewConfig(mEditedConfig); + adaptConfigSelection(); } else { // find a new device/config to match the current file. - findAndSetCompatibleConfig(mEditedConfig); + findAndSetCompatibleConfig(false /*favorCurrentConfig*/); } mDisableUpdates = false; @@ -1403,5 +1530,28 @@ public class ConfigurationComposite extends Composite { mCreateButton.setEnabled(mEditedConfig.equals(mCurrentConfig) == false); } + /** + * 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. + */ + private boolean isCurrentFileBestMatchFor(FolderConfiguration config) { + ResourceFile match = mResources.getMatchingFile(mEditedFile.getName(), + ResourceFolderType.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; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java index 4bfd589..0fb008b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java @@ -44,7 +44,6 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolder; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; @@ -141,9 +140,6 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette private PaletteRoot mPaletteRoot; - /** The {@link FolderConfiguration} being edited. */ - private FolderConfiguration mEditedConfig; - private Map<String, Map<String, IResourceValue>> mConfiguredFrameworkRes; private Map<String, Map<String, IResourceValue>> mConfiguredProjectRes; private ProjectCallback mProjectCallback; @@ -595,17 +591,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette */ public void openFile(IFile file) { mEditedFile = file; - - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); - mEditedConfig = resFolder.getConfiguration(); - - IAndroidTarget target = null; - Sdk currentSdk = Sdk.getCurrent(); - if (currentSdk != null) { - target = currentSdk.getTarget(mEditedFile.getProject()); - } - - mConfigComposite.openFile(mEditedConfig, target); + mConfigComposite.openFile(mEditedFile); } /** @@ -616,12 +602,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette resetInput(); mEditedFile = file; - - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); - mEditedConfig = resFolder.getConfiguration(); - - mConfigComposite.replaceFile(mEditedConfig); - onConfigurationChange(); + mConfigComposite.replaceFile(mEditedFile); } /** @@ -633,12 +614,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette resetInput(); mEditedFile = file; - - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file); - mEditedConfig = resFolder.getConfiguration(); - - mConfigComposite.changeFileOnNewConfig(mEditedConfig); - onConfigurationChange(); + mConfigComposite.changeFileOnNewConfig(mEditedFile); } public void onTargetChange() { @@ -817,55 +793,69 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette public void onConfigurationChange() { mConfiguredFrameworkRes = mConfiguredProjectRes = null; - if (mEditedFile == null || mEditedConfig == null) { + if (mEditedFile == null || mConfigComposite.getEditedConfig() == null) { return; } - // get the resources of the file's project. - ProjectResources resources = ResourceManager.getInstance().getProjectResources( - mEditedFile.getProject()); - - // from the resources, look for a matching file - ResourceFile match = null; - if (resources != null) { - match = resources.getMatchingFile(mEditedFile.getName(), - ResourceFolderType.LAYOUT, - mConfigComposite.getCurrentConfig()); - } + // Before doing the normal process, test for the following case. + // - the editor is being opened (or reset for a new input) + // - the file being opened is not the best match for any possible configuration + // - another random compatible config was chosen in the config composite. + // The result is that match will not be the file being edited, but because this is not + // due to a config change, we should not trigger opening the actual best match (also, + // because the editor is still opening the MatchingStrategy woudln't answer true + // and the best match file would open in a different editor). + // So the solution is that if the editor is being created, we just call recomputeLayout + // without looking for a better matching layout file. + if (mLayoutEditor.isCreatingPages()) { + recomputeLayout(); + } else { + // get the resources of the file's project. + ProjectResources resources = ResourceManager.getInstance().getProjectResources( + mEditedFile.getProject()); + + // from the resources, look for a matching file + ResourceFile match = null; + if (resources != null) { + match = resources.getMatchingFile(mEditedFile.getName(), + ResourceFolderType.LAYOUT, + mConfigComposite.getCurrentConfig()); + } - if (match != null) { - if (match.getFile().equals(mEditedFile) == false) { - try { - // tell the editor that the next replacement file is due to a config change. - mLayoutEditor.setNewFileOnConfigChange(true); + if (match != null) { + if (match.getFile().equals(mEditedFile) == false) { + try { + // tell the editor that the next replacement file is due to a config change. + mLayoutEditor.setNewFileOnConfigChange(true); - // ask the IDE to open the replacement file. - IDE.openEditor( - getSite().getWorkbenchWindow().getActivePage(), - match.getFile().getIFile()); + // ask the IDE to open the replacement file. + IDE.openEditor( + getSite().getWorkbenchWindow().getActivePage(), + match.getFile().getIFile()); - // we're done! - return; - } catch (PartInitException e) { - // FIXME: do something! + // we're done! + return; + } catch (PartInitException e) { + // FIXME: do something! + } } - } - // at this point, we have not opened a new file. + // at this point, we have not opened a new file. - // Even though the layout doesn't change, the config changed, and referenced - // resources need to be updated. - recomputeLayout(); - } else { - // display the error. - FolderConfiguration currentConfig = mConfigComposite.getCurrentConfig(); - String message = String.format( - "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.", - currentConfig.toDisplayString(), - currentConfig.getFolderName(ResourceFolderType.LAYOUT, - Sdk.getCurrent().getTarget(mEditedFile.getProject())), - mEditedFile.getName()); - showErrorInEditor(message); + // Even though the layout doesn't change, the config changed, and referenced + // resources need to be updated. + recomputeLayout(); + } else { + // display the error. + FolderConfiguration currentConfig = mConfigComposite.getCurrentConfig(); + String message = String.format( + "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.", + currentConfig.toDisplayString(), + currentConfig.getFolderName(ResourceFolderType.LAYOUT, + Sdk.getCurrent().getTarget(mEditedFile.getProject())), + mEditedFile.getName()); + showErrorInEditor(message); + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java index 5745b40..26d4206 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java @@ -36,7 +36,6 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration;
import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolder;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFolderType;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
@@ -137,9 +136,6 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE private StyledText mErrorLabel;
- /** The {@link FolderConfiguration} being edited. */
- private FolderConfiguration mEditedConfig;
-
private Map<String, Map<String, IResourceValue>> mConfiguredFrameworkRes;
private Map<String, Map<String, IResourceValue>> mConfiguredProjectRes;
private ProjectCallback mProjectCallback;
@@ -340,54 +336,69 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE public void onConfigurationChange() {
mConfiguredFrameworkRes = mConfiguredProjectRes = null;
- if (mEditedFile == null || mEditedConfig == null) {
+ if (mEditedFile == null || mConfigComposite.getEditedConfig() == null) {
return;
}
- // get the resources of the file's project.
- ProjectResources resources = ResourceManager.getInstance().getProjectResources(
- mEditedFile.getProject());
-
- // from the resources, look for a matching file
- ResourceFile match = null;
- if (resources != null) {
- match = resources.getMatchingFile(mEditedFile.getName(),
- ResourceFolderType.LAYOUT,
- mConfigComposite.getCurrentConfig());
- }
-
- if (match != null) {
- if (match.getFile().equals(mEditedFile) == false) {
- try {
- // tell the editor that the next replacement file is due to a config change.
- mLayoutEditor.setNewFileOnConfigChange(true);
-
- // ask the IDE to open the replacement file.
- IDE.openEditor(
- getSite().getWorkbenchWindow().getActivePage(),
- match.getFile().getIFile());
+ // Before doing the normal process, test for the following case.
+ // - the editor is being opened (or reset for a new input)
+ // - the file being opened is not the best match for any possible configuration
+ // - another random compatible config was chosen in the config composite.
+ // The result is that 'match' will not be the file being edited, but because this is not
+ // due to a config change, we should not trigger opening the actual best match (also,
+ // because the editor is still opening the MatchingStrategy woudln't answer true
+ // and the best match file would open in a different editor).
+ // So the solution is that if the editor is being created, we just call recomputeLayout
+ // without looking for a better matching layout file.
+ if (mLayoutEditor.isCreatingPages()) {
+ recomputeLayout();
+ } else {
+ // get the resources of the file's project.
+ ProjectResources resources = ResourceManager.getInstance().getProjectResources(
+ mEditedFile.getProject());
+
+ // from the resources, look for a matching file
+ ResourceFile match = null;
+ if (resources != null) {
+ match = resources.getMatchingFile(mEditedFile.getName(),
+ ResourceFolderType.LAYOUT,
+ mConfigComposite.getCurrentConfig());
+ }
- // we're done!
- return;
- } catch (PartInitException e) {
- // FIXME: do something!
+ if (match != null) {
+ if (match.getFile().equals(mEditedFile) == false) {
+ try {
+ // tell the editor that the next replacement file is due to a config
+ // change.
+ mLayoutEditor.setNewFileOnConfigChange(true);
+
+ // ask the IDE to open the replacement file.
+ IDE.openEditor(
+ getSite().getWorkbenchWindow().getActivePage(),
+ match.getFile().getIFile());
+
+ // we're done!
+ return;
+ } catch (PartInitException e) {
+ // FIXME: do something!
+ }
}
- }
- // at this point, we have not opened a new file.
+ // at this point, we have not opened a new file.
- // Even though the layout doesn't change, the config changed, and referenced
- // resources need to be updated.
- recomputeLayout();
- } else {
- // display the error.
- FolderConfiguration currentConfig = mConfigComposite.getCurrentConfig();
- displayError(
- "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.",
- currentConfig.toDisplayString(),
- currentConfig.getFolderName(ResourceFolderType.LAYOUT,
- Sdk.getCurrent().getTarget(mEditedFile.getProject())),
- mEditedFile.getName());
+ // Even though the layout doesn't change, the config changed, and referenced
+ // resources need to be updated.
+ recomputeLayout();
+ } else {
+ // display the error.
+ FolderConfiguration currentConfig = mConfigComposite.getCurrentConfig();
+ displayError(
+ "No resources match the configuration\n \n\t%1$s\n \nChange the configuration or create:\n \n\tres/%2$s/%3$s\n \nYou can also click the 'Create' button above.",
+ currentConfig.toDisplayString(),
+ currentConfig.getFolderName(ResourceFolderType.LAYOUT,
+ Sdk.getCurrent().getTarget(mEditedFile.getProject())),
+ mEditedFile.getName());
+ }
}
}
@@ -726,17 +737,7 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE */
public void openFile(IFile file) {
mEditedFile = file;
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- mEditedConfig = resFolder.getConfiguration();
-
- IAndroidTarget target = null;
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- target = currentSdk.getTarget(mEditedFile.getProject());
- }
-
- mConfigComposite.openFile(mEditedConfig, target);
+ mConfigComposite.openFile(mEditedFile);
if (mReloadListener == null) {
mReloadListener = new ReloadListener();
@@ -754,11 +755,7 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE */
public void replaceFile(IFile file) {
mEditedFile = file;
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- mEditedConfig = resFolder.getConfiguration();
-
- mConfigComposite.replaceFile(mEditedConfig);
+ mConfigComposite.replaceFile(mEditedFile);
}
/**
@@ -768,15 +765,9 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE */
public void changeFileOnNewConfig(IFile file) {
mEditedFile = file;
-
- ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
- mEditedConfig = resFolder.getConfiguration();
-
- mConfigComposite.changeFileOnNewConfig(mEditedConfig);
+ mConfigComposite.changeFileOnNewConfig(mEditedFile);
}
-
-
public void onTargetChange() {
mConfigComposite.onTargetChange();
mConfigListener.onConfigurationChange();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java index 2148068..61ffb6f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java @@ -240,8 +240,10 @@ public class GlobalProjectMonitor implements IResourceChangeListener { if (sThis != null) { ws.removeResourceChangeListener(sThis); - sThis.mFileListeners.clear(); - sThis.mProjectListeners.clear(); + synchronized (sThis) { + sThis.mFileListeners.clear(); + sThis.mProjectListeners.clear(); + } } } @@ -349,7 +351,7 @@ public class GlobalProjectMonitor implements IResourceChangeListener { /** * Processes the workspace resource change events. */ - public void resourceChanged(IResourceChangeEvent event) { + public synchronized void resourceChanged(IResourceChangeEvent event) { // notify the event listeners of a start. for (IResourceEventListener listener : mEventListeners) { listener.resourceChangeEventStart(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java index cc7c39f..143b644 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.resources.manager; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidConstants; import com.android.ide.eclipse.adt.internal.resources.ResourceType; import com.android.ide.eclipse.adt.internal.resources.configurations.FolderConfiguration; @@ -127,7 +128,9 @@ public final class ResourceManager { * @param listener the listener to be added. */ public void addListener(IResourceListener listener) { - mListeners.add(listener); + synchronized (mListeners) { + mListeners.add(listener); + } } /** @@ -135,7 +138,9 @@ public final class ResourceManager { * @param listener the listener to be removed. */ public void removeListener(IResource listener) { - mListeners.remove(listener); + synchronized (mListeners) { + mListeners.remove(listener); + } } /** @@ -617,14 +622,28 @@ public final class ResourceManager { private void notifyListenerOnFolderChange(IProject project, ResourceFolder folder, int eventType) { - for (IResourceListener listener : mListeners) { - listener.folderChanged(project, folder, eventType); + synchronized (mListeners) { + for (IResourceListener listener : mListeners) { + try { + listener.folderChanged(project, folder, eventType); + } catch (Throwable t) { + AdtPlugin.log(t, + "Failed to execute ResourceManager.IResouceListener.folderChanged()"); //$NON-NLS-1$ + } + } } } private void notifyListenerOnFileChange(IProject project, ResourceFile file, int eventType) { - for (IResourceListener listener : mListeners) { - listener.fileChanged(project, file, eventType); + synchronized (mListeners) { + for (IResourceListener listener : mListeners) { + try { + listener.fileChanged(project, file, eventType); + } catch (Throwable t) { + AdtPlugin.log(t, + "Failed to execute ResourceManager.IResouceListener.fileChanged()"); //$NON-NLS-1$ + } + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java index c11f4b8..f52a069 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/ui/ConfigurationSelector.java @@ -647,6 +647,7 @@ public class ConfigurationSelector extends Composite { super(parent, CountryCodeQualifier.NAME); mText = new Text(this, SWT.BORDER); + mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mText.addVerifyListener(new MobileCodeVerifier()); mText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { @@ -712,6 +713,7 @@ public class ConfigurationSelector extends Composite { super(parent, NetworkCodeQualifier.NAME); mText = new Text(this, SWT.BORDER); + mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mText.addVerifyListener(new MobileCodeVerifier()); mText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { @@ -1399,11 +1401,13 @@ public class ConfigurationSelector extends Composite { }; mSize1 = new Text(this, SWT.BORDER); + mSize1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSize1.addVerifyListener(new DimensionVerifier()); mSize1.addModifyListener(modifyListener); mSize1.addFocusListener(focusListener); mSize2 = new Text(this, SWT.BORDER); + mSize2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mSize2.addVerifyListener(new DimensionVerifier()); mSize2.addModifyListener(modifyListener); mSize2.addFocusListener(focusListener); @@ -1457,6 +1461,7 @@ public class ConfigurationSelector extends Composite { super(parent, VersionQualifier.NAME); mText = new Text(this, SWT.BORDER); + mText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); mText.addVerifyListener(new MobileCodeVerifier()); mText.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { |