aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-10-17 17:01:43 -0700
committerTor Norbye <tnorbye@google.com>2012-10-22 07:57:50 -0700
commit48ba7d81c125b6d46eb76719b62cafcd3dec3f97 (patch)
tree3d82b540517db8cf08380c84ee8822d54bc381d6 /eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2
parentea1b5a9a17274f653172bbe370f6147b57ebb579 (diff)
downloadsdk-48ba7d81c125b6d46eb76719b62cafcd3dec3f97.tar.gz
Multi-configuration editing bug fixes
This changeset fixes a number of bugs with multi configuration editing; especially around configuration switching and inheritance, as well as some memory improvements. It also synchronizes values between layout variations. If you for example have layout-land/foo.xml and layout-port/foo.xml and you change the Theme to Theme.Holo or the device to Galaxy Nexus, the configurations for both files will be updated (whether or not the files are open), and provided of course the layout folder doesn't contradict it; layout-xlarge/foo.xml would be unaffected by the above edit since Galaxy Nexus doesn't match the layout-xlarge folder. Change-Id: I5c01555aad8339f68788d8aed1f707d30993ae1b
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java42
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintOverlay.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java422
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewList.java44
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java274
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java22
7 files changed, 571 insertions, 250 deletions
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 67a890fad..445b29590 100644
--- 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
@@ -30,9 +30,11 @@ import static com.android.SdkConstants.STRING_PREFIX;
import static com.android.SdkConstants.VALUE_FILL_PARENT;
import static com.android.SdkConstants.VALUE_MATCH_PARENT;
import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser.NAME_CONFIG_STATE;
+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_TARGET;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor.viewNeedsPackage;
-
import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.DOCK_EAST;
import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.DOCK_WEST;
import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.STATE_COLLAPSED;
@@ -70,6 +72,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationDescription;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationMatcher;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
@@ -642,7 +645,7 @@ public class GraphicalEditorPart extends EditorPart
// ---- Implements ConfigurationClient ----
@Override
public void aboutToChange(int flags) {
- if ((flags & CHANGED_RENDER_TARGET) != 0) {
+ if ((flags & CFG_TARGET) != 0) {
IAndroidTarget oldTarget = mConfigChooser.getConfiguration().getTarget();
preRenderingTargetChangeCleanUp(oldTarget);
}
@@ -670,8 +673,12 @@ public class GraphicalEditorPart extends EditorPart
if (mEditorDelegate.getEditor().isCreatingPages()) {
recomputeLayout();
} else {
+ boolean affectsFileSelection = (flags & Configuration.MASK_FILE_ATTRS) != 0;
+ IFile best = null;
// get the resources of the file's project.
- IFile best = ConfigurationMatcher.getBestFileMatch(mConfigChooser);
+ if (affectsFileSelection) {
+ best = ConfigurationMatcher.getBestFileMatch(mConfigChooser);
+ }
if (best != null) {
if (!best.equals(mEditedFile)) {
try {
@@ -681,12 +688,12 @@ public class GraphicalEditorPart extends EditorPart
boolean reuseEditor = AdtPrefs.getPrefs().isSharedLayoutEditor();
if (!reuseEditor) {
- String data = AdtPlugin.getFileProperty(best, NAME_CONFIG_STATE);
+ String data = ConfigurationDescription.getDescription(best);
if (data == null) {
// Not previously opened: duplicate the current state as
// much as possible
data = mConfigChooser.getConfiguration().toPersistentString();
- AdtPlugin.setFileProperty(best, NAME_CONFIG_STATE, data);
+ ConfigurationDescription.setDescription(best, data);
}
}
@@ -709,7 +716,7 @@ public class GraphicalEditorPart extends EditorPart
// Even though the layout doesn't change, the config changed, and referenced
// resources need to be updated.
recomputeLayout();
- } else {
+ } else if (affectsFileSelection) {
// display the error.
Configuration configuration = mConfigChooser.getConfiguration();
FolderConfiguration currentConfig = configuration.getFullConfig();
@@ -727,10 +734,15 @@ public class GraphicalEditorPart extends EditorPart
currentConfig.toDisplayString(),
currentConfig.getFolderName(ResourceFolderType.LAYOUT),
mEditedFile.getName());
+ } else {
+ // Something else changed, such as the theme - just recompute existing
+ // layout
+ mConfigChooser.saveConstraints();
+ recomputeLayout();
}
}
- if ((flags & CHANGED_RENDER_TARGET) != 0) {
+ if ((flags & CFG_TARGET) != 0) {
Configuration configuration = mConfigChooser.getConfiguration();
IAndroidTarget target = configuration.getTarget();
Sdk current = Sdk.getCurrent();
@@ -740,7 +752,7 @@ public class GraphicalEditorPart extends EditorPart
}
}
- if ((flags & (CHANGED_DEVICE | CHANGED_DEVICE_CONFIG)) != 0) {
+ if ((flags & (CFG_DEVICE | CFG_DEVICE_STATE)) != 0) {
// When the device changes, zoom the view to fit, but only up to 100% (e.g. zoom
// out to fit the content, or zoom back in if we were zoomed out more from the
// previous view, but only up to 100% such that we never blow up pixels
@@ -873,6 +885,12 @@ public class GraphicalEditorPart extends EditorPart
return mIncludedWithin;
}
+ @Override
+ @Nullable
+ public LayoutCanvas getCanvas() {
+ return getCanvasControl();
+ }
+
/**
* Listens to target changed in the current project, to trigger a new layout rendering.
*/
@@ -907,7 +925,7 @@ public class GraphicalEditorPart extends EditorPart
IAndroidTarget target = currentSdk.getTarget(mEditedFile.getProject());
if (target != null) {
mConfigChooser.onSdkLoaded(target);
- changed(CHANGED_FOLDER | CHANGED_RENDER_TARGET);
+ changed(CFG_FOLDER | CFG_TARGET);
}
}
}
@@ -1168,7 +1186,7 @@ public class GraphicalEditorPart extends EditorPart
AndroidTargetData targetData = mConfigChooser.onXmlModelLoaded();
updateCapabilities(targetData);
- changed(CHANGED_FOLDER | CHANGED_RENDER_TARGET);
+ changed(CFG_FOLDER | CFG_TARGET);
}
/** Updates the capabilities for the given target data (which may be null) */
@@ -1577,6 +1595,8 @@ public class GraphicalEditorPart extends EditorPart
job.setSystem(true);
job.schedule(3000); // 3 seconds
}
+
+ mConfigChooser.ensureInitialized();
}
model.refreshUi();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
index bf648487b..4b6b803b8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
@@ -28,6 +28,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationDescription;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory;
@@ -853,7 +854,8 @@ public class LayoutCanvas extends Canvas {
int canvasWidth = canvasSize.width;
int canvasHeight = canvasSize.height;
- if (mPreviewManager.hasPreviews()) {
+ boolean hasPreviews = mPreviewManager.hasPreviews();
+ if (hasPreviews) {
canvasWidth = 2 * canvasWidth / 3;
} else {
canvasWidth -= 4;
@@ -1182,8 +1184,7 @@ public class LayoutCanvas extends Canvas {
try {
// Set initial state of a new file
// TODO: Only set rendering target portion of the state
- QualifiedName qname = ConfigurationChooser.NAME_CONFIG_STATE;
- String state = AdtPlugin.getFileProperty(leavingFile, qname);
+ String state = ConfigurationDescription.getDescription(leavingFile);
xmlFile.setSessionProperty(GraphicalEditorPart.NAME_INITIAL_STATE,
state);
} catch (CoreException e) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintOverlay.java
index 7ddb3720b..bce1512ef 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintOverlay.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LintOverlay.java
@@ -75,6 +75,12 @@ public class LintOverlay extends Overlay {
CanvasTransform mHScale = mCanvas.getHorizontalTransform();
CanvasTransform mVScale = mCanvas.getVerticalTransform();
+ // Right/bottom edges of the canvas image; don't paint overlays outside of
+ // that. (With for example RelativeLayouts with margins rendered on smaller
+ // screens than they are intended for this can happen.)
+ int maxX = mHScale.translate(0) + mHScale.getScaledImgSize();
+ int maxY = mVScale.translate(0) + mVScale.getScaledImgSize();
+
int oldAlpha = gc.getAlpha();
try {
gc.setAlpha(ALPHA);
@@ -95,6 +101,10 @@ public class LintOverlay extends Overlay {
x += w - iconWidth;
y += h - iconHeight;
+ if (x > maxX || y > maxY) {
+ continue;
+ }
+
boolean isError = false;
IMarker marker = editor.getIssueForNode(vi.getUiViewNode());
if (marker != null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java
index 07f640b64..78e670e6f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java
@@ -18,13 +18,11 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
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 static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient.CHANGED_DEVICE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient.CHANGED_FOLDER;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient.CHANGED_LOCALE;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient.CHANGED_RENDER_TARGET;
-import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient.CHANGED_THEME;
+import static com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration.MASK_RENDERING;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SHADOW_SIZE;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SMALL_SHADOW_SIZE;
+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 com.android.annotations.NonNull;
import com.android.annotations.Nullable;
@@ -36,7 +34,6 @@ import com.android.ide.common.resources.ResourceFile;
import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.common.resources.ResourceResolver;
import com.android.ide.common.resources.configuration.FolderConfiguration;
-import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtUtils;
@@ -48,6 +45,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configu
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationDescription;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Locale;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.NestedConfiguration;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.VaryingConfiguration;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
@@ -62,6 +60,9 @@ import com.android.resources.ResourceFolderType;
import com.android.resources.ResourceType;
import com.android.resources.ScreenOrientation;
import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.devices.Device;
+import com.android.sdklib.devices.Screen;
+import com.android.sdklib.devices.State;
import com.android.utils.SdkUtils;
import org.eclipse.core.resources.IFile;
@@ -88,6 +89,7 @@ import org.w3c.dom.Document;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
+import java.lang.ref.SoftReference;
import java.util.Comparator;
import java.util.Map;
@@ -116,6 +118,9 @@ public class RenderPreview implements IJobChangeListener {
/** Whether to dump out rendering failures of the previews to the log */
private static final boolean DUMP_RENDER_DIAGNOSTICS = false;
+ /** Extra error checking in debug mode */
+ private static final boolean DEBUG = false;
+
private static final Image EDIT_ICON;
private static final Image ZOOM_IN_ICON;
private static final Image ZOOM_OUT_ICON;
@@ -140,13 +145,16 @@ public class RenderPreview implements IJobChangeListener {
/** The configuration being previewed */
private @NonNull Configuration mConfiguration;
+ /** Configuration to use if we have an alternate input to be rendered */
+ private @NonNull Configuration mAlternateConfiguration;
+
/** The associated manager */
private final @NonNull RenderPreviewManager mManager;
private final @NonNull LayoutCanvas mCanvas;
- private @Nullable ResourceResolver mResourceResolver;
+
+ private @NonNull SoftReference<ResourceResolver> mResourceResolver =
+ new SoftReference<ResourceResolver>(null);
private @Nullable Job mJob;
- private @Nullable Map<ResourceType, Map<String, ResourceValue>> mConfiguredFrameworkRes;
- private @Nullable Map<ResourceType, Map<String, ResourceValue>> mConfiguredProjectRes;
private @Nullable Image mThumbnail;
private @Nullable String mDisplayName;
private int mWidth;
@@ -158,7 +166,7 @@ public class RenderPreview implements IJobChangeListener {
private double mAspectRatio;
/** If non null, points to a separate file containing the source */
- private @Nullable IFile mInput;
+ private @Nullable IFile mAlternateInput;
/** If included within another layout, the name of that outer layout */
private @Nullable Reference mIncludedWithin;
@@ -174,15 +182,6 @@ public class RenderPreview implements IJobChangeListener {
*/
private String mError;
- /**
- * Whether this preview presents a file that has been "forked" (separate,
- * not linked) from the primary layout.
- * <p>
- * TODO: Decide if this is redundant and I can just use {@link #mInput} != null
- * instead.
- */
- private boolean mForked;
-
/** Whether in the current layout, this preview is visible */
private boolean mVisible;
@@ -203,15 +202,21 @@ public class RenderPreview implements IJobChangeListener {
private RenderPreview(
@NonNull RenderPreviewManager manager,
@NonNull LayoutCanvas canvas,
- @NonNull Configuration configuration,
- int width,
- int height) {
+ @NonNull Configuration configuration) {
mManager = manager;
mCanvas = canvas;
mConfiguration = configuration;
- mWidth = width;
- mHeight = height;
- mAspectRatio = mWidth / (double) mHeight;
+ updateSize();
+
+ // Should only attempt to create configurations for fully configured devices
+ assert mConfiguration.getDevice() != null
+ && mConfiguration.getDeviceState() != null
+ && mConfiguration.getLocale() != null
+ && mConfiguration.getTarget() != null
+ && mConfiguration.getTheme() != null
+ && mConfiguration.getFullConfig() != null
+ && mConfiguration.getFullConfig().getScreenSizeQualifier() != null :
+ mConfiguration;
}
/**
@@ -281,22 +286,29 @@ public class RenderPreview implements IJobChangeListener {
}
/**
- * Sets whether this preview represents a forked layout (e.g. a layout which lives
- * in a separate file and is not connected to the main layout)
+ * Returns whether this preview represents a forked layout
*
- * @param forked true if this preview represents a separate file
+ * @return true if this preview represents a separate file
*/
- public void setForked(boolean forked) {
- mForked = forked;
+ public boolean isForked() {
+ return mAlternateInput != null || mIncludedWithin != null;
}
/**
- * Returns whether this preview represents a forked layout
+ * Returns the file to be used for this preview, or null if this is not a
+ * forked layout meaning that the file is the one used in the chooser
*
- * @return true if this preview represents a separate file
+ * @return the file or null for non-forked layouts
*/
- public boolean isForked() {
- return mForked;
+ @Nullable
+ public IFile getAlternateInput() {
+ if (mAlternateInput != null) {
+ return mAlternateInput;
+ } else if (mIncludedWithin != null) {
+ return mIncludedWithin.getFile();
+ }
+
+ return null;
}
/**
@@ -359,12 +371,15 @@ public class RenderPreview implements IJobChangeListener {
/** Determine whether this configuration has a better match in a different layout file */
private void updateForkStatus() {
- mForked = false;
- mInput = null;
ConfigurationChooser chooser = mManager.getChooser();
+ FolderConfiguration config = mConfiguration.getFullConfig();
+ if (mAlternateInput != null && chooser.isBestMatchFor(mAlternateInput, config)) {
+ return;
+ }
+
+ mAlternateInput = null;
IFile editedFile = chooser.getEditedFile();
if (editedFile != null) {
- FolderConfiguration config = mConfiguration.getFullConfig();
if (!chooser.isBestMatchFor(editedFile, config)) {
ProjectResources resources = chooser.getResources();
if (resources != null) {
@@ -373,13 +388,16 @@ public class RenderPreview implements IJobChangeListener {
if (best != null) {
IAbstractFile file = best.getFile();
if (file instanceof IFileWrapper) {
- mInput = ((IFileWrapper) file).getIFile();
+ mAlternateInput = ((IFileWrapper) file).getIFile();
} else if (file instanceof File) {
- mInput = AdtUtils.fileToIFile(((File) file));
+ mAlternateInput = AdtUtils.fileToIFile(((File) file));
}
}
}
- mForked = true;
+ if (mAlternateInput != null) {
+ mAlternateConfiguration = Configuration.create(mConfiguration,
+ mAlternateInput);
+ }
}
}
}
@@ -396,42 +414,7 @@ public class RenderPreview implements IJobChangeListener {
@NonNull RenderPreviewManager manager,
@NonNull Configuration configuration) {
LayoutCanvas canvas = manager.getCanvas();
-
- Image image = canvas.getImageOverlay().getImage();
-
- // Image size
- int screenWidth = 0;
- int screenHeight = 0;
- FolderConfiguration myconfig = configuration.getFullConfig();
- ScreenDimensionQualifier dimension = myconfig.getScreenDimensionQualifier();
- if (dimension != null) {
- screenWidth = dimension.getValue1();
- screenHeight = dimension.getValue2();
- ScreenOrientationQualifier orientation = myconfig.getScreenOrientationQualifier();
- if (orientation != null) {
- ScreenOrientation value = orientation.getValue();
- if (value == ScreenOrientation.PORTRAIT) {
- int temp = screenWidth;
- screenWidth = screenHeight;
- screenHeight = temp;
- }
- }
- } else {
- if (image != null) {
- screenWidth = image.getImageData().width;
- screenHeight = image.getImageData().height;
- }
- }
- int width = RenderPreviewManager.getMaxWidth();
- int height = RenderPreviewManager.getMaxHeight();
- if (screenWidth > 0) {
- double scale = getScale(screenWidth, screenHeight);
- width = (int) (screenWidth * scale);
- height = (int) (screenHeight * scale);
- }
-
- return new RenderPreview(manager, canvas,
- configuration, width, height);
+ return new RenderPreview(manager, canvas, configuration);
}
/**
@@ -524,16 +507,17 @@ public class RenderPreview implements IJobChangeListener {
private void renderSync() {
disposeThumbnail();
+ Configuration configuration =
+ mAlternateInput != null ? mAlternateConfiguration : mConfiguration;
GraphicalEditorPart editor = mCanvas.getEditorDelegate().getGraphicalEditor();
- ResourceResolver resolver = getResourceResolver();
- FolderConfiguration config = mConfiguration.getFullConfig();
- RenderService renderService = RenderService.create(editor, mConfiguration, resolver);
+ ResourceResolver resolver = getResourceResolver(configuration);
+ RenderService renderService = RenderService.create(editor, configuration, resolver);
if (mIncludedWithin != null) {
renderService.setIncludedWithin(mIncludedWithin);
}
- if (mInput != null) {
+ if (mAlternateInput != null) {
IAndroidTarget target = editor.getRenderingTarget();
AndroidTargetData data = null;
if (target != null) {
@@ -554,7 +538,7 @@ public class RenderPreview implements IJobChangeListener {
model.setEditor(mCanvas.getEditorDelegate().getEditor());
model.setUnknownDescriptorProvider(editor.getModel().getUnknownDescriptorProvider());
- Document document = DomUtilities.getDocument(mInput);
+ Document document = DomUtilities.getDocument(mAlternateInput);
if (document == null) {
mError = "No document";
createErrorThumbnail();
@@ -608,21 +592,22 @@ public class RenderPreview implements IJobChangeListener {
}
}
- private ResourceResolver getResourceResolver() {
- if (mResourceResolver != null) {
- return mResourceResolver;
+ private ResourceResolver getResourceResolver(Configuration configuration) {
+ ResourceResolver resourceResolver = mResourceResolver.get();
+ if (resourceResolver != null) {
+ return resourceResolver;
}
GraphicalEditorPart graphicalEditor = mCanvas.getEditorDelegate().getGraphicalEditor();
- String theme = mConfiguration.getTheme();
+ String theme = configuration.getTheme();
if (theme == null) {
return null;
}
- mConfiguredFrameworkRes = mConfiguredProjectRes = null;
- mResourceResolver = null;
+ Map<ResourceType, Map<String, ResourceValue>> configuredFrameworkRes = null;
+ Map<ResourceType, Map<String, ResourceValue>> configuredProjectRes = null;
- FolderConfiguration config = mConfiguration.getFullConfig();
+ FolderConfiguration config = configuration.getFullConfig();
IAndroidTarget target = graphicalEditor.getRenderingTarget();
ResourceRepository frameworkRes = null;
if (target != null) {
@@ -635,20 +620,20 @@ public class RenderPreview implements IJobChangeListener {
if (data != null) {
// TODO: SHARE if possible
frameworkRes = data.getFrameworkResources();
- mConfiguredFrameworkRes = frameworkRes.getConfiguredResources(config);
+ configuredFrameworkRes = frameworkRes.getConfiguredResources(config);
} else {
return null;
}
} else {
return null;
}
- assert mConfiguredFrameworkRes != null;
+ assert configuredFrameworkRes != null;
// get the resources of the file's project.
ProjectResources projectRes = ResourceManager.getInstance().getProjectResources(
graphicalEditor.getProject());
- mConfiguredProjectRes = projectRes.getConfiguredResources(config);
+ configuredProjectRes = projectRes.getConfiguredResources(config);
if (!theme.startsWith(PREFIX_RESOURCE_REF)) {
if (frameworkRes.hasResourceItem(ANDROID_STYLE_RESOURCE_PREFIX + theme)) {
@@ -658,12 +643,12 @@ public class RenderPreview implements IJobChangeListener {
}
}
- mResourceResolver = ResourceResolver.create(
- mConfiguredProjectRes, mConfiguredFrameworkRes,
+ resourceResolver = ResourceResolver.create(
+ configuredProjectRes, configuredFrameworkRes,
ResourceHelper.styleToTheme(theme),
ResourceHelper.isProjectStyle(theme));
-
- return mResourceResolver;
+ mResourceResolver = new SoftReference<ResourceResolver>(resourceResolver);
+ return resourceResolver;
}
/**
@@ -677,12 +662,17 @@ public class RenderPreview implements IJobChangeListener {
return;
}
+ ImageOverlay imageOverlay = mCanvas.getImageOverlay();
+ boolean drawShadows = imageOverlay == null || imageOverlay.getShowDropShadow();
double scale = getWidth() / (double) image.getWidth();
+ int shadowSize;
+ if (LARGE_SHADOWS) {
+ shadowSize = drawShadows ? SHADOW_SIZE : 0;
+ } else {
+ shadowSize = drawShadows ? SMALL_SHADOW_SIZE : 0;
+ }
if (scale < 1.0) {
- ImageOverlay imageOverlay = mCanvas.getImageOverlay();
- boolean drawShadows = imageOverlay == null || imageOverlay.getShowDropShadow();
if (LARGE_SHADOWS) {
- int shadowSize = drawShadows ? SHADOW_SIZE : 0;
image = ImageUtils.scale(image, scale, scale,
shadowSize, shadowSize);
if (drawShadows) {
@@ -691,7 +681,6 @@ public class RenderPreview implements IJobChangeListener {
image.getHeight() - shadowSize);
}
} else {
- int shadowSize = drawShadows ? SMALL_SHADOW_SIZE : 0;
image = ImageUtils.scale(image, scale, scale,
shadowSize, shadowSize);
if (drawShadows) {
@@ -702,16 +691,6 @@ public class RenderPreview implements IJobChangeListener {
}
}
- // Adjust size; for different aspect ratios the height might get adjusted etc
- /*
- if (LARGE_SHADOWS) {
- mWidth = image.getWidth() - SMALL_SHADOW_SIZE;
- mHeight = image.getHeight() - SMALL_SHADOW_SIZE;
- } else {
- mWidth = image.getWidth() - SHADOW_SIZE;
- mHeight = image.getHeight() - SHADOW_SIZE;
- }*/
-
mThumbnail = SwtUtils.convertToSwt(mCanvas.getDisplay(), image,
true /* transferAlpha */, -1);
}
@@ -835,6 +814,9 @@ public class RenderPreview implements IJobChangeListener {
if (d.open() == Window.OK) {
String newName = d.getValue();
mConfiguration.setDisplayName(newName);
+ if (mDescription != null) {
+ mManager.rename(mDescription, newName);
+ }
mCanvas.redraw();
}
@@ -953,17 +935,46 @@ public class RenderPreview implements IJobChangeListener {
* @param x the left edge of the preview rectangle
* @param y the top edge of the preview rectangle
*/
- int paintTitle(GC gc, int x, int y, boolean showFile) {
+ private int paintTitle(GC gc, int x, int y, boolean showFile) {
+ String displayName = getDisplayName();
+ return paintTitle(gc, x, y, showFile, displayName);
+ }
+
+ /**
+ * Paints the preview title at the given position (and returns the required
+ * height)
+ *
+ * @param gc the graphics context to paint into
+ * @param x the left edge of the preview rectangle
+ * @param y the top edge of the preview rectangle
+ * @param displayName the title string to be used
+ */
+ int paintTitle(GC gc, int x, int y, boolean showFile, String displayName) {
int titleHeight = 0;
- String displayName = getDisplayName();
+ if (showFile && mIncludedWithin != null) {
+ if (mManager.getMode() != INCLUDES) {
+ displayName = "<include>";
+ } else {
+ // Skip: just paint footer instead
+ displayName = null;
+ }
+ }
+
+ int width = getWidth();
+ int labelTop = y + 1;
+ gc.setClipping(x, labelTop, width, 100);
+
+ // Use font height rather than extent height since we want two adjacent
+ // previews (which may have different display names and therefore end
+ // up with slightly different extent heights) to have identical title
+ // heights such that they are aligned identically
+ int fontHeight = gc.getFontMetrics().getHeight();
+
if (displayName != null && displayName.length() > 0) {
gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
-
- int width = getWidth();
Point extent = gc.textExtent(displayName);
int labelLeft = Math.max(x, x + (width - extent.x) / 2);
- int labelTop = y + 1;
Image icon = null;
Locale locale = mConfiguration.getLocale();
if (locale != null && (locale.hasLanguage() || locale.hasRegion())
@@ -972,10 +983,10 @@ public class RenderPreview implements IJobChangeListener {
icon = locale.getFlagImage();
}
- gc.setClipping(x, labelTop, width, 100);
if (icon != null) {
int flagWidth = icon.getImageData().width;
int flagHeight = icon.getImageData().height;
+ labelLeft = Math.max(x + flagWidth / 2, labelLeft);
gc.drawImage(icon, labelLeft - flagWidth / 2 - 1, labelTop);
labelLeft += flagWidth / 2 + 1;
gc.drawText(displayName, labelLeft,
@@ -984,37 +995,35 @@ public class RenderPreview implements IJobChangeListener {
gc.drawText(displayName, labelLeft, labelTop, true);
}
- // Use font height rather than extent height since we want two adjacent
- // previews (which may have different display names and therefore end
- // up with slightly different extent heights) to have identical title
- // heights such that they are aligned identically
- titleHeight = gc.getFontMetrics().getHeight();
-
- if (mForked && mInput != null && showFile) {
- // Draw file flag, and parent folder name
- labelTop += extent.y;
- String fileName = mInput.getParent().getName() + File.separator + mInput.getName();
- extent = gc.textExtent(fileName);
- icon = IconFactory.getInstance().getIcon("android_file"); //$NON-NLS-1$
- int flagWidth = icon.getImageData().width;
- int flagHeight = icon.getImageData().height;
-
- labelLeft = Math.max(x, x + (width - extent.x - flagWidth - 1) / 2);
+ labelTop += extent.y;
+ titleHeight += fontHeight;
+ }
- gc.drawImage(icon, labelLeft, labelTop);
+ if (showFile && (mAlternateInput != null || mIncludedWithin != null)) {
+ // Draw file flag, and parent folder name
+ IFile file = mAlternateInput != null
+ ? mAlternateInput : mIncludedWithin.getFile();
+ String fileName = file.getParent().getName() + File.separator
+ + file.getName();
+ Point extent = gc.textExtent(fileName);
+ Image icon = IconFactory.getInstance().getIcon("android_file"); //$NON-NLS-1$
+ int flagWidth = icon.getImageData().width;
+ int flagHeight = icon.getImageData().height;
- gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GRAY));
- labelLeft += flagWidth + 1;
- labelTop -= (extent.y - flagHeight) / 2;
- gc.drawText(fileName, labelLeft, labelTop, true);
+ int labelLeft = Math.max(x, x + (width - extent.x - flagWidth - 1) / 2);
- titleHeight += Math.max(titleHeight, icon.getImageData().height);
+ gc.drawImage(icon, labelLeft, labelTop);
- }
+ gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GRAY));
+ labelLeft += flagWidth + 1;
+ labelTop -= (extent.y - flagHeight) / 2;
+ gc.drawText(fileName, labelLeft, labelTop, true);
- gc.setClipping((Region) null);
+ titleHeight += Math.max(titleHeight, icon.getImageData().height);
}
+ gc.setClipping((Region) null);
+
return titleHeight;
}
@@ -1030,43 +1039,136 @@ public class RenderPreview implements IJobChangeListener {
return;
}
- if ((flags & (CHANGED_FOLDER | CHANGED_THEME | CHANGED_DEVICE
- | CHANGED_RENDER_TARGET | CHANGED_LOCALE)) != 0) {
- mResourceResolver = null;
+ if ((flags & MASK_RENDERING) != 0) {
+ mResourceResolver.clear();
// Handle inheritance
mConfiguration.syncFolderConfig();
updateForkStatus();
+ updateSize();
+ }
+
+ // Sanity check to make sure things are working correctly
+ if (DEBUG) {
+ RenderPreviewMode mode = mManager.getMode();
+ if (mode == DEFAULT) {
+ assert mConfiguration instanceof VaryingConfiguration;
+ VaryingConfiguration config = (VaryingConfiguration) mConfiguration;
+ int alternateFlags = config.getAlternateFlags();
+ switch (alternateFlags) {
+ case Configuration.CFG_DEVICE_STATE: {
+ State configState = config.getDeviceState();
+ State chooserState = mManager.getChooser().getConfiguration()
+ .getDeviceState();
+ assert configState != null && chooserState != null;
+ assert !configState.getName().equals(chooserState.getName())
+ : configState.toString() + ':' + chooserState;
+
+ Device configDevice = config.getDevice();
+ Device chooserDevice = mManager.getChooser().getConfiguration()
+ .getDevice();
+ assert configDevice != null && chooserDevice != null;
+ assert configDevice == chooserDevice
+ : configDevice.toString() + ':' + chooserDevice;
+
+ break;
+ }
+ case Configuration.CFG_DEVICE: {
+ Device configDevice = config.getDevice();
+ Device chooserDevice = mManager.getChooser().getConfiguration()
+ .getDevice();
+ assert configDevice != null && chooserDevice != null;
+ assert configDevice != chooserDevice
+ : configDevice.toString() + ':' + chooserDevice;
+
+ State configState = config.getDeviceState();
+ State chooserState = mManager.getChooser().getConfiguration()
+ .getDeviceState();
+ assert configState != null && chooserState != null;
+ assert configState.getName().equals(chooserState.getName())
+ : configState.toString() + ':' + chooserState;
+
+ break;
+ }
+ case Configuration.CFG_LOCALE: {
+ Locale configLocale = config.getLocale();
+ Locale chooserLocale = mManager.getChooser().getConfiguration()
+ .getLocale();
+ assert configLocale != null && chooserLocale != null;
+ assert configLocale != chooserLocale
+ : configLocale.toString() + ':' + chooserLocale;
+ break;
+ }
+ default: {
+ // Some other type of override I didn't anticipate
+ assert false : alternateFlags;
+ }
+ }
+ }
+ }
+
+ mDirty = 0;
+ mManager.scheduleRender(this);
+ }
+
+ private void updateSize() {
+ Device device = mConfiguration.getDevice();
+ if (device == null) {
+ return;
+ }
+ Screen screen = device.getDefaultHardware().getScreen();
+ if (screen == null) {
+ return;
}
FolderConfiguration folderConfig = mConfiguration.getFullConfig();
ScreenOrientationQualifier qualifier = folderConfig.getScreenOrientationQualifier();
ScreenOrientation orientation = qualifier == null
? ScreenOrientation.PORTRAIT : qualifier.getValue();
- if (orientation == ScreenOrientation.LANDSCAPE
- || orientation == ScreenOrientation.SQUARE) {
- orientation = ScreenOrientation.PORTRAIT;
+
+ // compute width and height to take orientation into account.
+ int x = screen.getXDimension();
+ int y = screen.getYDimension();
+ int screenWidth, screenHeight;
+
+ if (x > y) {
+ if (orientation == ScreenOrientation.LANDSCAPE) {
+ screenWidth = x;
+ screenHeight = y;
+ } else {
+ screenWidth = y;
+ screenHeight = x;
+ }
} else {
- orientation = ScreenOrientation.LANDSCAPE;
+ if (orientation == ScreenOrientation.LANDSCAPE) {
+ screenWidth = y;
+ screenHeight = x;
+ } else {
+ screenWidth = x;
+ screenHeight = y;
+ }
+ }
+
+ int width = RenderPreviewManager.getMaxWidth();
+ int height = RenderPreviewManager.getMaxHeight();
+ if (screenWidth > 0) {
+ double scale = getScale(screenWidth, screenHeight);
+ width = (int) (screenWidth * scale);
+ height = (int) (screenHeight * scale);
}
- if ((mWidth < mHeight && orientation == ScreenOrientation.PORTRAIT)
- || (mWidth > mHeight && orientation == ScreenOrientation.LANDSCAPE)) {
+ if (width != mWidth || height != mHeight) {
+ mWidth = width;
+ mHeight = height;
+
Image thumbnail = mThumbnail;
mThumbnail = null;
if (thumbnail != null) {
thumbnail.dispose();
}
-
- // Flip icon size
- int temp = mHeight;
- mHeight = mWidth;
- mWidth = temp;
- mAspectRatio = mWidth / (double) mHeight;
+ if (mHeight != 0) {
+ mAspectRatio = mWidth / (double) mHeight;
+ }
}
-
- mDirty = 0;
-
- mManager.scheduleRender(this);
}
/**
@@ -1173,8 +1275,8 @@ public class RenderPreview implements IJobChangeListener {
*
* @param file the file to set as input
*/
- public void setInput(@Nullable IFile file) {
- mInput = file;
+ public void setAlternateInput(@Nullable IFile file) {
+ mAlternateInput = file;
}
/** Corresponding description for this preview if it is a manually added preview */
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewList.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewList.java
index 1d48f7b8f..05f1005b7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewList.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewList.java
@@ -93,7 +93,7 @@ class RenderPreviewList {
}
void save() throws IOException {
- delete();
+ deleteFile();
if (!mList.isEmpty()) {
File file = getManualFile();
save(file);
@@ -147,23 +147,37 @@ class RenderPreviewList {
ConfigurationChooser chooser = canvas.getEditorDelegate().getGraphicalEditor()
.getConfigurationChooser();
+ Configuration chooserConfig = chooser.getConfiguration();
for (ConfigurationDescription description : mList) {
Configuration configuration = Configuration.create(chooser);
+ configuration.setDisplayName(description.displayName);
+ configuration.setActivity(description.activity);
+ configuration.setLocale(
+ description.locale != null ? description.locale : chooserConfig.getLocale(),
+ true);
+ // TODO: Make sure this layout isn't in some v-folder which is incompatible
+ // with this target!
+ configuration.setTarget(
+ description.target != null ? description.target : chooserConfig.getTarget(),
+ true);
+ configuration.setTheme(
+ description.theme != null ? description.theme : chooserConfig.getTheme());
+ configuration.setDevice(
+ description.device != null ? description.device : chooserConfig.getDevice(),
+ true);
+ configuration.setDeviceState(
+ description.state != null ? description.state : chooserConfig.getDeviceState(),
+ true);
+ configuration.setNightMode(
+ description.nightMode != null ? description.nightMode
+ : chooserConfig.getNightMode(), true);
+ configuration.setUiMode(
+ description.uiMode != null ? description.uiMode : chooserConfig.getUiMode(), true);
+
+ //configuration.syncFolderConfig();
configuration.getFullConfig().set(description.folder);
- if (description.target != null) {
- // TODO: Make sure this layout isn't in some v-folder which is incompatible
- // with this target!
- configuration.setTarget(description.target, true);
- }
-
- if (description.theme != null) {
- configuration.setTheme(description.theme);
- }
RenderPreview preview = RenderPreview.create(manager, configuration);
- if (description.displayName != null) {
- preview.setDisplayName(description.displayName);
- }
preview.setDescription(description);
previews.add(preview);
@@ -195,6 +209,10 @@ class RenderPreviewList {
void delete() {
mList.clear();
+ deleteFile();
+ }
+
+ private void deleteFile() {
File file = getManualFile();
if (file.exists()) {
file.delete();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
index f90e9ac1b..021443376 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreviewManager.java
@@ -16,9 +16,15 @@
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+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.MASK_ALL;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SHADOW_SIZE;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.ImageUtils.SMALL_SHADOW_SIZE;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreview.LARGE_SHADOWS;
+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.NONE;
+import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderPreviewMode.SCREENS;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
@@ -32,12 +38,14 @@ import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
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.configuration.ComplementingConfiguration;
+import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationClient;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationDescription;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Locale;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.NestedConfiguration;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.VaryingConfiguration;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.resources.Density;
@@ -58,6 +66,9 @@ import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.ide.IDE;
import java.io.IOException;
import java.util.ArrayList;
@@ -68,7 +79,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
-
/**
* Manager for the configuration previews, which handles layout computations,
* managing the image buffer cache, etc
@@ -91,7 +101,7 @@ public class RenderPreviewManager {
private int mPrevCanvasHeight;
private int mPrevImageWidth;
private int mPrevImageHeight;
- private @NonNull RenderPreviewMode mMode = RenderPreviewMode.NONE;
+ private @NonNull RenderPreviewMode mMode = NONE;
private @Nullable RenderPreview mActivePreview;
private @Nullable ScrollBarListener mListener;
private int mLayoutHeight;
@@ -189,21 +199,32 @@ public class RenderPreviewManager {
}
static int getMaxWidth() {
- return (int) sScale * MAX_WIDTH;
+ return (int) (sScale * MAX_WIDTH);
}
static int getMaxHeight() {
- return (int) sScale * MAX_HEIGHT;
+ return (int) (sScale * MAX_HEIGHT);
}
static double getScale() {
return sScale;
}
+ /**
+ * Returns whether there are any manual preview items (provided the current
+ * mode is manual previews
+ *
+ * @return true if there are items in the manual preview list
+ */
+ public boolean hasManualPreviews() {
+ assert mMode == CUSTOM;
+ return mManualList != null && !mManualList.isEmpty();
+ }
+
/** Delete all the previews */
public void deleteManualPreviews() {
disposePreviews();
- selectMode(RenderPreviewMode.NONE);
+ selectMode(NONE);
mCanvas.setFitScale(true /* onlyZoomOut */, true /*allowZoomIn*/);
if (mManualList != null) {
@@ -361,9 +382,13 @@ public class RenderPreviewManager {
}
}
- ArrayList<RenderPreview> aspectOrder = new ArrayList<RenderPreview>(mPreviews);
- Collections.sort(aspectOrder, RenderPreview.INCREASING_ASPECT_RATIO);
-
+ List<RenderPreview> aspectOrder;
+ if (!fixedOrder()) {
+ aspectOrder = new ArrayList<RenderPreview>(mPreviews);
+ Collections.sort(aspectOrder, RenderPreview.INCREASING_ASPECT_RATIO);
+ } else {
+ aspectOrder = mPreviews;
+ }
for (RenderPreview preview : aspectOrder) {
if (x > 0 && x + preview.getWidth() > availableWidth) {
@@ -423,9 +448,7 @@ public class RenderPreviewManager {
}
private boolean fixedOrder() {
- // Currently, none of the lists have fixed order. Possibly we could
- // consider mMode == RenderPreviewMode.CUSTOM to be fixed.
- return false;
+ return mMode == SCREENS;
}
/** Returns true if all the previews have the same identical size */
@@ -546,7 +569,7 @@ public class RenderPreviewManager {
renderPreviews();
}
if (mNeedZoom) {
- boolean allowZoomIn = true /*mMode == RenderPreviewMode.NONE*/;
+ boolean allowZoomIn = true /*mMode == NONE*/;
mCanvas.setFitScale(false /*onlyZoomOut*/, allowZoomIn);
mNeedZoom = false;
}
@@ -563,27 +586,59 @@ public class RenderPreviewManager {
RenderPreview preview = mCanvas.getPreview();
if (preview != null) {
- CanvasTransform hi = mHScale;
- CanvasTransform vi = mVScale;
+ String displayName = null;
+ Configuration configuration = preview.getConfiguration();
+ if (configuration instanceof VaryingConfiguration) {
+ // Use override flags from stashed preview, but configuration
+ // data from live (not varying) configured configuration
+ VaryingConfiguration cfg = (VaryingConfiguration) configuration;
+ int flags = cfg.getAlternateFlags() | cfg.getOverrideFlags();
+ displayName = NestedConfiguration.computeDisplayName(flags,
+ getChooser().getConfiguration());
+ } else if (configuration instanceof NestedConfiguration) {
+ int flags = ((NestedConfiguration) configuration).getOverrideFlags();
+ displayName = NestedConfiguration.computeDisplayName(flags,
+ getChooser().getConfiguration());
+ } else {
+ displayName = configuration.getDisplayName();
+ }
+ if (displayName != null) {
+ CanvasTransform hi = mHScale;
+ CanvasTransform vi = mVScale;
+
+ int destX = hi.translate(0);
+ int destY = vi.translate(0);
+ int destWidth = hi.getScaledImgSize();
+ int destHeight = vi.getScaledImgSize();
- int destX = hi.translate(0);
- int destY = vi.translate(0);
- int destWidth = hi.getScaledImgSize();
- int destHeight = vi.getScaledImgSize();
+ int x = destX + destWidth / 2 - preview.getWidth() / 2;
+ int y = destY + destHeight;
- int x = destX + destWidth / 2 - preview.getWidth() / 2;
- int y = destY + destHeight;
- preview.paintTitle(gc, x, y, false /*showFile*/);
+ preview.paintTitle(gc, x, y, false /*showFile*/, displayName);
+ }
}
// Zoom overlay
int x = getZoomX();
if (x > 0) {
int y = getZoomY();
+ int oldAlpha = gc.getAlpha();
+
+ // Paint background oval rectangle behind the zoom and close icons
+ gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_GRAY));
+ gc.setAlpha(128);
+ int padding = 3;
+ int arc = 5;
+ gc.fillRoundRectangle(x - padding, y - padding,
+ ZOOM_ICON_WIDTH + 2 * padding,
+ 4 * ZOOM_ICON_HEIGHT + 2 * padding, arc, arc);
+
+ gc.setAlpha(255);
IconFactory iconFactory = IconFactory.getInstance();
Image zoomOut = iconFactory.getIcon("zoomminus"); //$NON-NLS-1$);
- Image zoomIn = iconFactory.getIcon("zoomplus"); //$NON-NLS-1$);
- Image zoom100 = iconFactory.getIcon("zoom100"); //$NON-NLS-1$);
+ Image zoomIn = iconFactory.getIcon("zoomplus"); //$NON-NLS-1$);
+ Image zoom100 = iconFactory.getIcon("zoom100"); //$NON-NLS-1$);
+ Image close = iconFactory.getIcon("close"); //$NON-NLS-1$);
gc.drawImage(zoomIn, x, y);
y += ZOOM_ICON_HEIGHT;
@@ -591,8 +646,11 @@ public class RenderPreviewManager {
y += ZOOM_ICON_HEIGHT;
gc.drawImage(zoom100, x, y);
y += ZOOM_ICON_HEIGHT;
+ gc.drawImage(close, x, y);
+ y += ZOOM_ICON_HEIGHT;
+ gc.setAlpha(oldAlpha);
}
- } else if (mMode == RenderPreviewMode.CUSTOM) {
+ } else if (mMode == CUSTOM) {
int rootX = getX();
rootX += mHScale.getScaledImgSize();
rootX += 2 * PREVIEW_HGAP;
@@ -630,7 +688,7 @@ public class RenderPreviewManager {
name,
null);
if (d.open() == Window.OK) {
- selectMode(RenderPreviewMode.CUSTOM);
+ selectMode(CUSTOM);
String newName = d.getValue();
// Create a new configuration from the current settings in the composite
@@ -706,6 +764,9 @@ public class RenderPreviewManager {
createRenderTargetVariation(chooser, parent);
}
+ // Also add in include-context previews, if any
+ addIncludedInPreviews();
+
// Make a placeholder preview for the current screen, in case we switch from it
RenderPreview preview = RenderPreview.create(this, parent);
mCanvas.setPreview(preview);
@@ -717,9 +778,9 @@ public class RenderPreviewManager {
/* This is disabled for now: need to load multiple versions of layoutlib.
When I did this, there seemed to be some drug interactions between
them, and I would end up with NPEs in layoutlib code which normally works.
- ComplementingConfiguration configuration =
- ComplementingConfiguration.create(chooser, parent);
- configuration.setOverrideTarget(true);
+ VaryingConfiguration configuration =
+ VaryingConfiguration.create(chooser, parent);
+ configuration.setAlternatingTarget(true);
configuration.syncFolderConfig();
addPreview(RenderPreview.create(this, configuration));
*/
@@ -729,10 +790,10 @@ public class RenderPreviewManager {
State currentState = parent.getDeviceState();
State nextState = parent.getNextDeviceState(currentState);
if (nextState != currentState) {
- ComplementingConfiguration configuration =
- ComplementingConfiguration.create(chooser, parent);
- configuration.setOverrideDeviceState(true);
- configuration.setDeviceState(nextState, false);
+ VaryingConfiguration configuration =
+ VaryingConfiguration.create(chooser, parent);
+ configuration.setAlternateDeviceState(true);
+ configuration.syncFolderConfig();
addPreview(RenderPreview.create(this, configuration));
}
}
@@ -742,11 +803,10 @@ public class RenderPreviewManager {
for (Locale locale : chooser.getLocaleList()) {
LanguageQualifier language = locale.language;
if (!language.equals(currentLanguage)) {
- ComplementingConfiguration configuration =
- ComplementingConfiguration.create(chooser, parent);
- configuration.setOverrideLocale(true);
- Locale otherLanguage = Locale.create(language);
- configuration.setLocale(otherLanguage, false);
+ VaryingConfiguration configuration =
+ VaryingConfiguration.create(chooser, parent);
+ configuration.setAlternateLocale(true);
+ configuration.syncFolderConfig();
addPreview(RenderPreview.create(this, configuration));
break;
}
@@ -755,17 +815,17 @@ public class RenderPreviewManager {
private void createScreenVariations(Configuration parent) {
ConfigurationChooser chooser = getChooser();
- ComplementingConfiguration configuration;
+ VaryingConfiguration configuration;
- configuration = ComplementingConfiguration.create(chooser, parent);
+ configuration = VaryingConfiguration.create(chooser, parent);
configuration.setVariation(0);
- configuration.setOverrideDevice(true);
+ configuration.setAlternateDevice(true);
configuration.syncFolderConfig();
addPreview(RenderPreview.create(this, configuration));
- configuration = ComplementingConfiguration.create(chooser, parent);
+ configuration = VaryingConfiguration.create(chooser, parent);
configuration.setVariation(1);
- configuration.setOverrideDevice(true);
+ configuration.setAlternateDevice(true);
configuration.syncFolderConfig();
addPreview(RenderPreview.create(this, configuration));
}
@@ -793,11 +853,12 @@ public class RenderPreviewManager {
RenderPreviewMode newMode = AdtPrefs.getPrefs().getRenderPreviewMode();
if (newMode == mMode && !force
&& (mRevision == sRevision
- || mMode == RenderPreviewMode.NONE
- || mMode == RenderPreviewMode.CUSTOM)) {
+ || mMode == NONE
+ || mMode == CUSTOM)) {
return false;
}
+ RenderPreviewMode oldMode = mMode;
mMode = newMode;
mRevision = sRevision;
@@ -824,6 +885,9 @@ public class RenderPreviewManager {
addManualPreviews();
break;
case NONE:
+ // Can't just set mNeedZoom because with no previews, the paint
+ // method does nothing
+ mCanvas.setFitScale(false /*onlyZoomOut*/, true /*allowZoomIn*/);
break;
default:
assert false : mMode;
@@ -837,6 +901,13 @@ public class RenderPreviewManager {
mNeedLayout = mNeedRender = true;
mCanvas.redraw();
+ if (oldMode != mMode && (oldMode == NONE || mMode == NONE)) {
+ // If entering or exiting preview mode: updating padding which is compressed
+ // only in preview mode.
+ mCanvas.getHorizontalTransform().refresh();
+ mCanvas.getVerticalTransform().refresh();
+ }
+
return true;
}
@@ -983,7 +1054,8 @@ public class RenderPreviewManager {
for (final Reference reference : includedBy) {
String title = reference.getDisplayName();
- Configuration config = Configuration.create(chooser, reference.getFile());
+ Configuration config = Configuration.create(chooser.getConfiguration(),
+ reference.getFile());
RenderPreview preview = RenderPreview.create(this, config);
preview.setDisplayName(title);
preview.setIncludedWithin(reference);
@@ -1011,12 +1083,16 @@ public class RenderPreviewManager {
}
});
+ Configuration currentConfig = chooser.getConfiguration();
+
for (IFile variation : variations) {
String title = variation.getParent().getName();
- Configuration config = Configuration.create(chooser, variation);
+ Configuration config = Configuration.create(chooser.getConfiguration(), variation);
+ config.setTheme(currentConfig.getTheme());
+ config.setActivity(currentConfig.getActivity());
RenderPreview preview = RenderPreview.create(this, config);
preview.setDisplayName(title);
- preview.setInput(variation);
+ preview.setAlternateInput(variation);
addPreview(preview);
}
@@ -1063,6 +1139,20 @@ public class RenderPreviewManager {
}
}
+ void rename(ConfigurationDescription description, String newName) {
+ IProject project = getChooser().getProject();
+ if (project == null) {
+ return;
+ }
+
+ if (mManualList == null) {
+ mManualList = RenderPreviewList.get(project);
+ }
+ description.displayName = newName;
+ saveList();
+ }
+
+
/**
* Notifies that the main configuration has changed.
*
@@ -1148,6 +1238,47 @@ public class RenderPreviewManager {
* @param preview the preview to switch to
*/
public void switchTo(@NonNull RenderPreview preview) {
+ IFile input = preview.getAlternateInput();
+ if (input != null) {
+ IWorkbenchPartSite site = mCanvas.getEditorDelegate().getEditor().getSite();
+ try {
+ // This switches to the given file, but the file might not have
+ // an identical configuration to what was shown in the preview.
+ // For example, while viewing a 10" layout-xlarge file, it might
+ // show a preview for a 5" version tied to the default layout. If
+ // you click on it, it will open the default layout file, but it might
+ // be using a different screen size; any of those that match the
+ // default layout, say a 3.8".
+ //
+ // Thus, we need to also perform a screen size sync first
+ Configuration configuration = preview.getConfiguration();
+ boolean setSize = false;
+ if (configuration instanceof NestedConfiguration) {
+ NestedConfiguration nestedConfig = (NestedConfiguration) configuration;
+ setSize = nestedConfig.isOverridingDevice();
+ if (configuration instanceof VaryingConfiguration) {
+ VaryingConfiguration c = (VaryingConfiguration) configuration;
+ setSize |= c.isAlternatingDevice();
+ }
+
+ if (setSize) {
+ ConfigurationChooser chooser = getChooser();
+ IFile editedFile = chooser.getEditedFile();
+ if (editedFile != null) {
+ chooser.syncToVariations(CFG_DEVICE|CFG_DEVICE_STATE,
+ editedFile, configuration, false, false);
+ }
+ }
+ }
+
+ IDE.openEditor(site.getWorkbenchWindow().getActivePage(), input,
+ CommonXmlEditor.ID);
+ } catch (PartInitException e) {
+ AdtPlugin.log(e, null);
+ }
+ return;
+ }
+
GraphicalEditorPart editor = mCanvas.getEditorDelegate().getGraphicalEditor();
ConfigurationChooser chooser = editor.getConfigurationChooser();
@@ -1183,16 +1314,20 @@ public class RenderPreviewManager {
// Update its configuration such that it is complementing or inheriting
// from the new chosen configuration
- if (previewConfiguration instanceof ComplementingConfiguration) {
- originalConfiguration = ComplementingConfiguration.create(
- (ComplementingConfiguration) previewConfiguration,
+ if (previewConfiguration instanceof VaryingConfiguration) {
+ VaryingConfiguration varying = VaryingConfiguration.create(
+ (VaryingConfiguration) previewConfiguration,
newConfiguration);
+ varying.updateDisplayName();
+ originalConfiguration = varying;
newPreview.setConfiguration(originalConfiguration);
} else if (previewConfiguration instanceof NestedConfiguration) {
- originalConfiguration = NestedConfiguration.create(
+ NestedConfiguration nested = NestedConfiguration.create(
(NestedConfiguration) previewConfiguration,
originalConfiguration,
newConfiguration);
+ nested.setDisplayName(nested.computeDisplayName());
+ originalConfiguration = nested;
newPreview.setConfiguration(originalConfiguration);
}
@@ -1210,11 +1345,12 @@ public class RenderPreviewManager {
// Stash the corresponding preview (not active) on the canvas so we can
// retrieve it if clicking to some other preview later
mCanvas.setPreview(preview);
+ preview.setVisible(false);
// Switch to the configuration from the clicked preview (though it's
// most likely a copy, see above)
chooser.setConfiguration(newConfiguration);
- editor.recomputeLayout();
+ editor.changed(MASK_ALL);
// Scroll to the top again, if necessary
mCanvas.getVerticalBar().setSelection(mCanvas.getVerticalBar().getMinimum());
@@ -1271,7 +1407,7 @@ public class RenderPreviewManager {
private int getZoomY() {
Rectangle clientArea = mCanvas.getClientArea();
- return clientArea.y + 3;
+ return clientArea.y + 5;
}
/**
@@ -1338,13 +1474,15 @@ public class RenderPreviewManager {
if (x > 0) {
if (mousePos.x >= x && mousePos.x <= x + ZOOM_ICON_WIDTH) {
int y = getZoomY();
- if (mousePos.y >= y && mousePos.y <= y + 3 * ZOOM_ICON_HEIGHT) {
+ if (mousePos.y >= y && mousePos.y <= y + 4 * ZOOM_ICON_HEIGHT) {
if (mousePos.y < y + ZOOM_ICON_HEIGHT) {
zoomIn();
} else if (mousePos.y < y + 2 * ZOOM_ICON_HEIGHT) {
zoomOut();
- } else {
+ } else if (mousePos.y < y + 3 * ZOOM_ICON_HEIGHT) {
zoomReset();
+ } else {
+ selectMode(NONE);
}
return true;
}
@@ -1530,4 +1668,28 @@ public class RenderPreviewManager {
mCanvas.redraw();
}
}
+
+ /**
+ * Notifies the {@linkplain RenderPreviewManager} that the configuration used
+ * in the main chooser has been changed. This may require updating parent references
+ * in the preview configurations inheriting from it.
+ *
+ * @param oldConfiguration the previous configuration
+ * @param newConfiguration the new configuration in the chooser
+ */
+ public void updateChooserConfig(
+ @NonNull Configuration oldConfiguration,
+ @NonNull Configuration newConfiguration) {
+ if (hasPreviews()) {
+ for (RenderPreview preview : mPreviews) {
+ Configuration configuration = preview.getConfiguration();
+ if (configuration instanceof NestedConfiguration) {
+ NestedConfiguration nestedConfig = (NestedConfiguration) configuration;
+ if (nestedConfig.getParent() == oldConfiguration) {
+ nestedConfig.setParent(newConfiguration);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
index 0dd81b28a..170e27d79 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
@@ -53,15 +53,18 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.devices.Device;
+import com.google.common.io.Files;
import org.eclipse.core.resources.IProject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -130,7 +133,9 @@ public class RenderService {
mImageFactory = canvas.getImageOverlay();
FolderConfiguration folderConfig = configuration.getFullConfig();
- mHardwareConfigHelper = new HardwareConfigHelper(configuration.getDevice());
+ Device device = configuration.getDevice();
+ assert device != null;
+ mHardwareConfigHelper = new HardwareConfigHelper(device);
mHardwareConfigHelper.setOrientation(
folderConfig.getScreenOrientationQualifier().getValue());
@@ -373,17 +378,20 @@ public class RenderService {
File layoutFile = new File(contextLayout.getValue());
if (layoutFile.isFile()) {
try {
+ byte[] bytes = Files.toByteArray(layoutFile);
+
// Get the name of the layout actually being edited, without the extension
// as it's what IXmlPullParser.getParser(String) will receive.
String queryLayoutName = mEditor.getLayoutResourceName();
mProjectCallback.setLayoutParser(queryLayoutName, modelParser);
topParser = new ContextPullParser(mProjectCallback, layoutFile);
topParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- topParser.setInput(new FileInputStream(layoutFile), "UTF-8"); //$NON-NLS-1$
+ InputStream inputStream = new ByteArrayInputStream(bytes);
+ topParser.setInput(inputStream, "UTF-8"); //$NON-NLS-1$
+ } catch (IOException e) {
+ AdtPlugin.log(e, null);
} catch (XmlPullParserException e) {
- AdtPlugin.log(e, ""); //$NON-NLS-1$
- } catch (FileNotFoundException e) {
- // this will not happen since we check above.
+ AdtPlugin.log(e, null);
}
}
}