diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java | 1333 |
1 files changed, 0 insertions, 1333 deletions
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 deleted file mode 100644 index 5621d5f17..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderPreview.java +++ /dev/null @@ -1,1333 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.eclipse.org/org/documents/epl-v10.php - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.ide.eclipse.adt.internal.editors.layout.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.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; -import com.android.ide.common.rendering.api.RenderSession; -import com.android.ide.common.rendering.api.ResourceValue; -import com.android.ide.common.rendering.api.Result; -import com.android.ide.common.rendering.api.Result.Status; -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.ScreenOrientationQualifier; -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.descriptors.DocumentDescriptor; -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.editors.uimodel.UiDocumentNode; -import com.android.ide.eclipse.adt.internal.resources.ResourceHelper; -import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; -import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; -import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.io.IFileWrapper; -import com.android.io.IAbstractFile; -import com.android.resources.Density; -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; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.jobs.IJobChangeEvent; -import org.eclipse.core.runtime.jobs.IJobChangeListener; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jface.dialogs.InputDialog; -import org.eclipse.jface.window.Window; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.graphics.Region; -import org.eclipse.swt.widgets.Display; -import org.eclipse.ui.ISharedImages; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.progress.UIJob; -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; - -/** - * Represents a preview rendering of a given configuration - */ -public class RenderPreview implements IJobChangeListener { - /** Whether previews should use large shadows */ - static final boolean LARGE_SHADOWS = false; - - /** - * Still doesn't work; get exceptions from layoutlib: - * java.lang.IllegalStateException: After scene creation, #init() must be called - * at com.android.layoutlib.bridge.impl.RenderAction.acquire(RenderAction.java:151) - * <p> - * TODO: Investigate. - */ - private static final boolean RENDER_ASYNC = false; - - /** - * Height of the toolbar shown over a preview during hover. Needs to be - * large enough to accommodate icons below. - */ - private static final int HEADER_HEIGHT = 20; - - /** 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; - private static final Image CLOSE_ICON; - private static final int EDIT_ICON_WIDTH; - private static final int ZOOM_IN_ICON_WIDTH; - private static final int ZOOM_OUT_ICON_WIDTH; - private static final int CLOSE_ICON_WIDTH; - static { - ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); - IconFactory icons = IconFactory.getInstance(); - CLOSE_ICON = sharedImages.getImage(ISharedImages.IMG_ETOOL_DELETE); - EDIT_ICON = icons.getIcon("editPreview"); //$NON-NLS-1$ - ZOOM_IN_ICON = icons.getIcon("zoomplus"); //$NON-NLS-1$ - ZOOM_OUT_ICON = icons.getIcon("zoomminus"); //$NON-NLS-1$ - CLOSE_ICON_WIDTH = CLOSE_ICON.getImageData().width; - EDIT_ICON_WIDTH = EDIT_ICON.getImageData().width; - ZOOM_IN_ICON_WIDTH = ZOOM_IN_ICON.getImageData().width; - ZOOM_OUT_ICON_WIDTH = ZOOM_OUT_ICON.getImageData().width; - } - - /** 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 @NonNull SoftReference<ResourceResolver> mResourceResolver = - new SoftReference<ResourceResolver>(null); - private @Nullable Job mJob; - private @Nullable Image mThumbnail; - private @Nullable String mDisplayName; - private int mWidth; - private int mHeight; - private int mX; - private int mY; - private int mTitleHeight; - private double mScale = 1.0; - private double mAspectRatio; - - /** If non null, points to a separate file containing the source */ - private @Nullable IFile mAlternateInput; - - /** If included within another layout, the name of that outer layout */ - private @Nullable Reference mIncludedWithin; - - /** Whether the mouse is actively hovering over this preview */ - private boolean mActive; - - /** - * Whether this preview cannot be rendered because of a model error - such - * as an invalid configuration, a missing resource, an error in the XML - * markup, etc. If non null, contains the error message (or a blank string - * if not known), and null if the render was successful. - */ - private String mError; - - /** Whether in the current layout, this preview is visible */ - private boolean mVisible; - - /** Whether the configuration has changed and needs to be refreshed the next time - * this preview made visible. This corresponds to the change flags in - * {@link ConfigurationClient}. */ - private int mDirty; - - /** - * Creates a new {@linkplain RenderPreview} - * - * @param manager the manager - * @param canvas canvas where preview is painted - * @param configuration the associated configuration - * @param width the initial width to use for the preview - * @param height the initial height to use for the preview - */ - private RenderPreview( - @NonNull RenderPreviewManager manager, - @NonNull LayoutCanvas canvas, - @NonNull Configuration configuration) { - mManager = manager; - mCanvas = canvas; - mConfiguration = configuration; - 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; - } - - /** - * Sets the configuration to use for this preview - * - * @param configuration the new configuration - */ - public void setConfiguration(@NonNull Configuration configuration) { - mConfiguration = configuration; - } - - /** - * Gets the scale being applied to the thumbnail - * - * @return the scale being applied to the thumbnail - */ - public double getScale() { - return mScale; - } - - /** - * Sets the scale to apply to the thumbnail - * - * @param scale the factor to scale the thumbnail picture by - */ - public void setScale(double scale) { - disposeThumbnail(); - mScale = scale; - } - - /** - * Returns the aspect ratio of this render preview - * - * @return the aspect ratio - */ - public double getAspectRatio() { - return mAspectRatio; - } - - /** - * Returns whether the preview is actively hovered - * - * @return whether the mouse is hovering over the preview - */ - public boolean isActive() { - return mActive; - } - - /** - * Sets whether the preview is actively hovered - * - * @param active if the mouse is hovering over the preview - */ - public void setActive(boolean active) { - mActive = active; - } - - /** - * Returns whether the preview is visible. Previews that are off - * screen are typically marked invisible during layout, which means we don't - * have to expend effort computing preview thumbnails etc - * - * @return true if the preview is visible - */ - public boolean isVisible() { - return mVisible; - } - - /** - * Returns whether this preview represents a forked layout - * - * @return true if this preview represents a separate file - */ - public boolean isForked() { - return mAlternateInput != null || mIncludedWithin != null; - } - - /** - * 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 the file or null for non-forked layouts - */ - @Nullable - public IFile getAlternateInput() { - if (mAlternateInput != null) { - return mAlternateInput; - } else if (mIncludedWithin != null) { - return mIncludedWithin.getFile(); - } - - return null; - } - - /** - * Returns the area of this render preview, PRIOR to scaling - * - * @return the area (width times height without scaling) - */ - int getArea() { - return mWidth * mHeight; - } - - /** - * Sets whether the preview is visible. Previews that are off - * screen are typically marked invisible during layout, which means we don't - * have to expend effort computing preview thumbnails etc - * - * @param visible whether this preview is visible - */ - public void setVisible(boolean visible) { - if (visible != mVisible) { - mVisible = visible; - if (mVisible) { - if (mDirty != 0) { - // Just made the render preview visible: - configurationChanged(mDirty); // schedules render - } else { - updateForkStatus(); - mManager.scheduleRender(this); - } - } else { - dispose(); - } - } - } - - /** - * Sets the layout position relative to the top left corner of the preview - * area, in control coordinates - */ - void setPosition(int x, int y) { - mX = x; - mY = y; - } - - /** - * Gets the layout X position relative to the top left corner of the preview - * area, in control coordinates - */ - int getX() { - return mX; - } - - /** - * Gets the layout Y position relative to the top left corner of the preview - * area, in control coordinates - */ - int getY() { - return mY; - } - - /** Determine whether this configuration has a better match in a different layout file */ - private void updateForkStatus() { - 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) { - if (!chooser.isBestMatchFor(editedFile, config)) { - ProjectResources resources = chooser.getResources(); - if (resources != null) { - ResourceFile best = resources.getMatchingFile(editedFile.getName(), - ResourceType.LAYOUT, config); - if (best != null) { - IAbstractFile file = best.getFile(); - if (file instanceof IFileWrapper) { - mAlternateInput = ((IFileWrapper) file).getIFile(); - } else if (file instanceof File) { - mAlternateInput = AdtUtils.fileToIFile(((File) file)); - } - } - } - if (mAlternateInput != null) { - mAlternateConfiguration = Configuration.create(mConfiguration, - mAlternateInput); - } - } - } - } - - /** - * Creates a new {@linkplain RenderPreview} - * - * @param manager the manager - * @param configuration the associated configuration - * @return a new configuration - */ - @NonNull - public static RenderPreview create( - @NonNull RenderPreviewManager manager, - @NonNull Configuration configuration) { - LayoutCanvas canvas = manager.getCanvas(); - return new RenderPreview(manager, canvas, configuration); - } - - /** - * Throws away this preview: cancels any pending rendering jobs and disposes - * of image resources etc - */ - public void dispose() { - disposeThumbnail(); - - if (mJob != null) { - mJob.cancel(); - mJob = null; - } - } - - /** Disposes the thumbnail rendering. */ - void disposeThumbnail() { - if (mThumbnail != null) { - mThumbnail.dispose(); - mThumbnail = null; - } - } - - /** - * Returns the display name of this preview - * - * @return the name of the preview - */ - @NonNull - public String getDisplayName() { - if (mDisplayName == null) { - String displayName = getConfiguration().getDisplayName(); - if (displayName == null) { - // No display name: this must be the configuration used by default - // for the view which is originally displayed (before adding thumbnails), - // and you've switched away to something else; now we need to display a name - // for this original configuration. For now, just call it "Original" - return "Original"; - } - - return displayName; - } - - return mDisplayName; - } - - /** - * Sets the display name of this preview. By default, the display name is - * the display name of the configuration, but it can be overridden by calling - * this setter (which only sets the preview name, without editing the configuration.) - * - * @param displayName the new display name - */ - public void setDisplayName(@NonNull String displayName) { - mDisplayName = displayName; - } - - /** - * Sets an inclusion context to use for this layout, if any. This will render - * the configuration preview as the outer layout with the current layout - * embedded within. - * - * @param includedWithin a reference to a layout which includes this one - */ - public void setIncludedWithin(Reference includedWithin) { - mIncludedWithin = includedWithin; - } - - /** - * Request a new render after the given delay - * - * @param delay the delay to wait before starting the render job - */ - public void render(long delay) { - Job job = mJob; - if (job != null) { - job.cancel(); - } - if (RENDER_ASYNC) { - job = new AsyncRenderJob(); - } else { - job = new RenderJob(); - } - job.schedule(delay); - job.addJobChangeListener(this); - mJob = job; - } - - /** Render immediately */ - private void renderSync() { - GraphicalEditorPart editor = mCanvas.getEditorDelegate().getGraphicalEditor(); - if (editor.getReadyLayoutLib(false /*displayError*/) == null) { - // Don't attempt to render when there is no ready layout library: most likely - // the targets are loading/reloading. - return; - } - - disposeThumbnail(); - - Configuration configuration = - mAlternateInput != null && mAlternateConfiguration != null - ? mAlternateConfiguration : mConfiguration; - ResourceResolver resolver = getResourceResolver(configuration); - RenderService renderService = RenderService.create(editor, configuration, resolver); - - if (mIncludedWithin != null) { - renderService.setIncludedWithin(mIncludedWithin); - } - - if (mAlternateInput != null) { - IAndroidTarget target = editor.getRenderingTarget(); - AndroidTargetData data = null; - if (target != null) { - Sdk sdk = Sdk.getCurrent(); - if (sdk != null) { - data = sdk.getTargetData(target); - } - } - - // Construct UI model from XML - DocumentDescriptor documentDescriptor; - if (data == null) { - documentDescriptor = new DocumentDescriptor("temp", null);//$NON-NLS-1$ - } else { - documentDescriptor = data.getLayoutDescriptors().getDescriptor(); - } - UiDocumentNode model = (UiDocumentNode) documentDescriptor.createUiNode(); - model.setEditor(mCanvas.getEditorDelegate().getEditor()); - model.setUnknownDescriptorProvider(editor.getModel().getUnknownDescriptorProvider()); - - Document document = DomUtilities.getDocument(mAlternateInput); - if (document == null) { - mError = "No document"; - createErrorThumbnail(); - return; - } - model.loadFromXmlNode(document); - renderService.setModel(model); - } else { - renderService.setModel(editor.getModel()); - } - RenderLogger log = editor.createRenderLogger(getDisplayName()); - renderService.setLog(log); - RenderSession session = renderService.createRenderSession(); - Result render = session.render(1000); - - if (DUMP_RENDER_DIAGNOSTICS) { - if (log.hasProblems() || !render.isSuccess()) { - AdtPlugin.log(IStatus.ERROR, "Found problems rendering preview " - + getDisplayName() + ": " - + render.getErrorMessage() + " : " - + log.getProblems(false)); - Throwable exception = render.getException(); - if (exception != null) { - AdtPlugin.log(exception, "Failure rendering preview " + getDisplayName()); - } - } - } - - if (render.isSuccess()) { - mError = null; - } else { - mError = render.getErrorMessage(); - if (mError == null) { - mError = ""; - } - } - - if (render.getStatus() == Status.ERROR_TIMEOUT) { - // TODO: Special handling? schedule update again later - return; - } - if (render.isSuccess()) { - BufferedImage image = session.getImage(); - if (image != null) { - createThumbnail(image); - } - } - - if (mError != null) { - createErrorThumbnail(); - } - } - - private ResourceResolver getResourceResolver(Configuration configuration) { - ResourceResolver resourceResolver = mResourceResolver.get(); - if (resourceResolver != null) { - return resourceResolver; - } - - GraphicalEditorPart graphicalEditor = mCanvas.getEditorDelegate().getGraphicalEditor(); - String theme = configuration.getTheme(); - if (theme == null) { - return null; - } - - Map<ResourceType, Map<String, ResourceValue>> configuredFrameworkRes = null; - Map<ResourceType, Map<String, ResourceValue>> configuredProjectRes = null; - - FolderConfiguration config = configuration.getFullConfig(); - IAndroidTarget target = graphicalEditor.getRenderingTarget(); - ResourceRepository frameworkRes = null; - if (target != null) { - Sdk sdk = Sdk.getCurrent(); - if (sdk == null) { - return null; - } - AndroidTargetData data = sdk.getTargetData(target); - - if (data != null) { - // TODO: SHARE if possible - frameworkRes = data.getFrameworkResources(); - configuredFrameworkRes = frameworkRes.getConfiguredResources(config); - } else { - return null; - } - } else { - return null; - } - assert configuredFrameworkRes != null; - - - // get the resources of the file's project. - ProjectResources projectRes = ResourceManager.getInstance().getProjectResources( - graphicalEditor.getProject()); - configuredProjectRes = projectRes.getConfiguredResources(config); - - if (!theme.startsWith(PREFIX_RESOURCE_REF)) { - if (frameworkRes.hasResourceItem(ANDROID_STYLE_RESOURCE_PREFIX + theme)) { - theme = ANDROID_STYLE_RESOURCE_PREFIX + theme; - } else { - theme = STYLE_RESOURCE_PREFIX + theme; - } - } - - resourceResolver = ResourceResolver.create( - configuredProjectRes, configuredFrameworkRes, - ResourceHelper.styleToTheme(theme), - ResourceHelper.isProjectStyle(theme)); - mResourceResolver = new SoftReference<ResourceResolver>(resourceResolver); - return resourceResolver; - } - - /** - * Sets the new image of the preview and generates a thumbnail - * - * @param image the full size image - */ - void createThumbnail(BufferedImage image) { - if (image == null) { - mThumbnail = null; - 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) { - if (LARGE_SHADOWS) { - image = ImageUtils.scale(image, scale, scale, - shadowSize, shadowSize); - if (drawShadows) { - ImageUtils.drawRectangleShadow(image, 0, 0, - image.getWidth() - shadowSize, - image.getHeight() - shadowSize); - } - } else { - image = ImageUtils.scale(image, scale, scale, - shadowSize, shadowSize); - if (drawShadows) { - ImageUtils.drawSmallRectangleShadow(image, 0, 0, - image.getWidth() - shadowSize, - image.getHeight() - shadowSize); - } - } - } - - mThumbnail = SwtUtils.convertToSwt(mCanvas.getDisplay(), image, - true /* transferAlpha */, -1); - } - - void createErrorThumbnail() { - int shadowSize = LARGE_SHADOWS ? SHADOW_SIZE : SMALL_SHADOW_SIZE; - int width = getWidth(); - int height = getHeight(); - BufferedImage image = new BufferedImage(width + shadowSize, height + shadowSize, - BufferedImage.TYPE_INT_ARGB); - - Graphics2D g = image.createGraphics(); - g.setColor(new java.awt.Color(0xfffbfcc6)); - g.fillRect(0, 0, width, height); - - g.dispose(); - - ImageOverlay imageOverlay = mCanvas.getImageOverlay(); - boolean drawShadows = imageOverlay == null || imageOverlay.getShowDropShadow(); - if (drawShadows) { - if (LARGE_SHADOWS) { - ImageUtils.drawRectangleShadow(image, 0, 0, - image.getWidth() - SHADOW_SIZE, - image.getHeight() - SHADOW_SIZE); - } else { - ImageUtils.drawSmallRectangleShadow(image, 0, 0, - image.getWidth() - SMALL_SHADOW_SIZE, - image.getHeight() - SMALL_SHADOW_SIZE); - } - } - - mThumbnail = SwtUtils.convertToSwt(mCanvas.getDisplay(), image, - true /* transferAlpha */, -1); - } - - private static double getScale(int width, int height) { - int maxWidth = RenderPreviewManager.getMaxWidth(); - int maxHeight = RenderPreviewManager.getMaxHeight(); - if (width > 0 && height > 0 - && (width > maxWidth || height > maxHeight)) { - if (width >= height) { // landscape - return maxWidth / (double) width; - } else { // portrait - return maxHeight / (double) height; - } - } - - return 1.0; - } - - /** - * Returns the width of the preview, in pixels - * - * @return the width in pixels - */ - public int getWidth() { - return (int) (mWidth * mScale * RenderPreviewManager.getScale()); - } - - /** - * Returns the height of the preview, in pixels - * - * @return the height in pixels - */ - public int getHeight() { - return (int) (mHeight * mScale * RenderPreviewManager.getScale()); - } - - /** - * Handles clicks within the preview (x and y are positions relative within the - * preview - * - * @param x the x coordinate within the preview where the click occurred - * @param y the y coordinate within the preview where the click occurred - * @return true if this preview handled (and therefore consumed) the click - */ - public boolean click(int x, int y) { - if (y >= mTitleHeight && y < mTitleHeight + HEADER_HEIGHT) { - int left = 0; - left += CLOSE_ICON_WIDTH; - if (x <= left) { - // Delete - mManager.deletePreview(this); - return true; - } - left += ZOOM_IN_ICON_WIDTH; - if (x <= left) { - // Zoom in - mScale = mScale * (1 / 0.5); - if (Math.abs(mScale-1.0) < 0.0001) { - mScale = 1.0; - } - - render(0); - mManager.layout(true); - mCanvas.redraw(); - return true; - } - left += ZOOM_OUT_ICON_WIDTH; - if (x <= left) { - // Zoom out - mScale = mScale * (0.5 / 1); - if (Math.abs(mScale-1.0) < 0.0001) { - mScale = 1.0; - } - render(0); - - mManager.layout(true); - mCanvas.redraw(); - return true; - } - left += EDIT_ICON_WIDTH; - if (x <= left) { - // Edit. For now, just rename - InputDialog d = new InputDialog( - AdtPlugin.getShell(), - "Rename Preview", // title - "Name:", - getDisplayName(), - null); - if (d.open() == Window.OK) { - String newName = d.getValue(); - mConfiguration.setDisplayName(newName); - if (mDescription != null) { - mManager.rename(mDescription, newName); - } - mCanvas.redraw(); - } - - return true; - } - - // Clicked anywhere else on header - // Perhaps open Edit dialog here? - } - - mManager.switchTo(this); - return true; - } - - /** - * Paints the preview at the given x/y position - * - * @param gc the graphics context to paint it into - * @param x the x coordinate to paint the preview at - * @param y the y coordinate to paint the preview at - */ - void paint(GC gc, int x, int y) { - mTitleHeight = paintTitle(gc, x, y, true /*showFile*/); - y += mTitleHeight; - y += 2; - - int width = getWidth(); - int height = getHeight(); - if (mThumbnail != null && mError == null) { - gc.drawImage(mThumbnail, x, y); - - if (mActive) { - int oldWidth = gc.getLineWidth(); - gc.setLineWidth(3); - gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_LIST_SELECTION)); - gc.drawRectangle(x - 1, y - 1, width + 2, height + 2); - gc.setLineWidth(oldWidth); - } - } else if (mError != null) { - if (mThumbnail != null) { - gc.drawImage(mThumbnail, x, y); - } else { - gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BORDER)); - gc.drawRectangle(x, y, width, height); - } - - gc.setClipping(x, y, width, height); - Image icon = IconFactory.getInstance().getIcon("renderError"); //$NON-NLS-1$ - ImageData data = icon.getImageData(); - int prevAlpha = gc.getAlpha(); - int alpha = 96; - if (mThumbnail != null) { - alpha -= 32; - } - gc.setAlpha(alpha); - gc.drawImage(icon, x + (width - data.width) / 2, y + (height - data.height) / 2); - - String msg = mError; - Density density = mConfiguration.getDensity(); - if (density == Density.TV || density == Density.LOW) { - msg = "Broken rendering library; unsupported DPI. Try using the SDK manager " + - "to get updated layout libraries."; - } - int charWidth = gc.getFontMetrics().getAverageCharWidth(); - int charsPerLine = (width - 10) / charWidth; - msg = SdkUtils.wrap(msg, charsPerLine, null); - gc.setAlpha(255); - gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK)); - gc.drawText(msg, x + 5, y + HEADER_HEIGHT, true); - gc.setAlpha(prevAlpha); - gc.setClipping((Region) null); - } else { - gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BORDER)); - gc.drawRectangle(x, y, width, height); - - Image icon = IconFactory.getInstance().getIcon("refreshPreview"); //$NON-NLS-1$ - ImageData data = icon.getImageData(); - int prevAlpha = gc.getAlpha(); - gc.setAlpha(96); - gc.drawImage(icon, x + (width - data.width) / 2, - y + (height - data.height) / 2); - gc.setAlpha(prevAlpha); - } - - if (mActive) { - int left = x ; - int prevAlpha = gc.getAlpha(); - gc.setAlpha(208); - Color bg = mCanvas.getDisplay().getSystemColor(SWT.COLOR_WHITE); - gc.setBackground(bg); - gc.fillRectangle(left, y, x + width - left, HEADER_HEIGHT); - gc.setAlpha(prevAlpha); - - y += 2; - - // Paint icons - gc.drawImage(CLOSE_ICON, left, y); - left += CLOSE_ICON_WIDTH; - - gc.drawImage(ZOOM_IN_ICON, left, y); - left += ZOOM_IN_ICON_WIDTH; - - gc.drawImage(ZOOM_OUT_ICON, left, y); - left += ZOOM_OUT_ICON_WIDTH; - - gc.drawImage(EDIT_ICON, left, y); - left += EDIT_ICON_WIDTH; - } - } - - /** - * 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 - */ - 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; - - 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)); - Point extent = gc.textExtent(displayName); - int labelLeft = Math.max(x, x + (width - extent.x) / 2); - Image icon = null; - Locale locale = mConfiguration.getLocale(); - if (locale != null && (locale.hasLanguage() || locale.hasRegion()) - && (!(mConfiguration instanceof NestedConfiguration) - || ((NestedConfiguration) mConfiguration).isOverridingLocale())) { - icon = locale.getFlagImage(); - } - - 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, - labelTop - (extent.y - flagHeight) / 2, true); - } else { - gc.drawText(displayName, labelLeft, labelTop, true); - } - - labelTop += extent.y; - titleHeight += fontHeight; - } - - 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; - - int labelLeft = Math.max(x, x + (width - extent.x - flagWidth - 1) / 2); - - 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); - - titleHeight += Math.max(titleHeight, icon.getImageData().height); - } - - gc.setClipping((Region) null); - - return titleHeight; - } - - /** - * Notifies that the preview's configuration has changed. - * - * @param flags the change flags, a bitmask corresponding to the - * {@code CHANGE_} constants in {@link ConfigurationClient} - */ - public void configurationChanged(int flags) { - if (!mVisible) { - mDirty |= flags; - return; - } - - 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(); - - // 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 { - 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 (width != mWidth || height != mHeight) { - mWidth = width; - mHeight = height; - - Image thumbnail = mThumbnail; - mThumbnail = null; - if (thumbnail != null) { - thumbnail.dispose(); - } - if (mHeight != 0) { - mAspectRatio = mWidth / (double) mHeight; - } - } - } - - /** - * Returns the configuration associated with this preview - * - * @return the configuration - */ - @NonNull - public Configuration getConfiguration() { - return mConfiguration; - } - - // ---- Implements IJobChangeListener ---- - - @Override - public void aboutToRun(IJobChangeEvent event) { - } - - @Override - public void awake(IJobChangeEvent event) { - } - - @Override - public void done(IJobChangeEvent event) { - mJob = null; - } - - @Override - public void running(IJobChangeEvent event) { - } - - @Override - public void scheduled(IJobChangeEvent event) { - } - - @Override - public void sleeping(IJobChangeEvent event) { - } - - // ---- Delayed Rendering ---- - - private final class RenderJob extends UIJob { - public RenderJob() { - super("RenderPreview"); - setSystem(true); - setUser(false); - } - - @Override - public IStatus runInUIThread(IProgressMonitor monitor) { - mJob = null; - if (!mCanvas.isDisposed()) { - renderSync(); - mCanvas.redraw(); - return org.eclipse.core.runtime.Status.OK_STATUS; - } - - return org.eclipse.core.runtime.Status.CANCEL_STATUS; - } - - @Override - public Display getDisplay() { - if (mCanvas.isDisposed()) { - return null; - } - return mCanvas.getDisplay(); - } - } - - private final class AsyncRenderJob extends Job { - public AsyncRenderJob() { - super("RenderPreview"); - setSystem(true); - setUser(false); - } - - @Override - protected IStatus run(IProgressMonitor monitor) { - mJob = null; - - if (mCanvas.isDisposed()) { - return org.eclipse.core.runtime.Status.CANCEL_STATUS; - } - - renderSync(); - - // Update display - mCanvas.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - mCanvas.redraw(); - } - }); - - return org.eclipse.core.runtime.Status.OK_STATUS; - } - } - - /** - * Sets the input file to use for rendering. If not set, this will just be - * the same file as the configuration chooser. This is used to render other - * layouts, such as variations of the currently edited layout, which are - * not kept in sync with the main layout. - * - * @param file the file to set as input - */ - public void setAlternateInput(@Nullable IFile file) { - mAlternateInput = file; - } - - /** Corresponding description for this preview if it is a manually added preview */ - private @Nullable ConfigurationDescription mDescription; - - /** - * Sets the description of this preview, if this preview is a manually added preview - * - * @param description the description of this preview - */ - public void setDescription(@Nullable ConfigurationDescription description) { - mDescription = description; - } - - /** - * Returns the description of this preview, if this preview is a manually added preview - * - * @return the description - */ - @Nullable - public ConfigurationDescription getDescription() { - return mDescription; - } - - @Override - public String toString() { - return getDisplayName() + ':' + mConfiguration; - } - - /** Sorts render previews into increasing aspect ratio order */ - static Comparator<RenderPreview> INCREASING_ASPECT_RATIO = new Comparator<RenderPreview>() { - @Override - public int compare(RenderPreview preview1, RenderPreview preview2) { - return (int) Math.signum(preview1.mAspectRatio - preview2.mAspectRatio); - } - }; - /** Sorts render previews into visual order: row by row, column by column */ - static Comparator<RenderPreview> VISUAL_ORDER = new Comparator<RenderPreview>() { - @Override - public int compare(RenderPreview preview1, RenderPreview preview2) { - int delta = preview1.mY - preview2.mY; - if (delta == 0) { - delta = preview1.mX - preview2.mX; - } - return delta; - } - }; -} |