aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java2937
1 files changed, 0 insertions, 2937 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
deleted file mode 100644
index 0f5762da6..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ /dev/null
@@ -1,2937 +0,0 @@
-/*
- * Copyright (C) 2009 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_PKG;
-import static com.android.SdkConstants.ANDROID_STRING_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_CONTEXT;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.FD_GEN_SOURCES;
-import static com.android.SdkConstants.GRID_LAYOUT;
-import static com.android.SdkConstants.SCROLL_VIEW;
-import static com.android.SdkConstants.STRING_PREFIX;
-import static com.android.SdkConstants.VALUE_FALSE;
-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.common.rendering.RenderSecurityManager.ENABLED_PROPERTY;
-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;
-import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.STATE_OPEN;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ide.common.layout.BaseLayoutRule;
-import com.android.ide.common.rendering.LayoutLibrary;
-import com.android.ide.common.rendering.RenderSecurityException;
-import com.android.ide.common.rendering.RenderSecurityManager;
-import com.android.ide.common.rendering.StaticRenderSession;
-import com.android.ide.common.rendering.api.Capability;
-import com.android.ide.common.rendering.api.LayoutLog;
-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.SessionParams.RenderingMode;
-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.sdk.LoadStatus;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.IPageImageProvider;
-import com.android.ide.eclipse.adt.internal.editors.IconFactory;
-import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate;
-import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ChangeFlags;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutReloadMonitor.ILayoutReloadListener;
-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;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.PaletteControl.PalettePage;
-import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
-import com.android.ide.eclipse.adt.internal.editors.layout.properties.PropertyFactory;
-import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener;
-import com.android.resources.Density;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-import com.android.sdklib.IAndroidTarget;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.QualifiedName;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.jdt.core.IClasspathEntry;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaModelMarker;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IPackageFragment;
-import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.internal.ui.preferences.BuildPathsPropertyPage;
-import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction;
-import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
-import org.eclipse.jface.action.MenuManager;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.ISelectionProvider;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.jface.window.Window;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.SashForm;
-import org.eclipse.swt.custom.StyleRange;
-import org.eclipse.swt.custom.StyledText;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.text.edits.MalformedTreeException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
-import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.INullSelectionListener;
-import org.eclipse.ui.ISelectionListener;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.IWorkbenchPartSite;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.PreferencesUtil;
-import org.eclipse.ui.ide.IDE;
-import org.eclipse.ui.part.EditorPart;
-import org.eclipse.ui.part.FileEditorInput;
-import org.eclipse.ui.part.IPageSite;
-import org.eclipse.ui.part.PageBookView;
-import org.eclipse.wb.core.controls.flyout.FlyoutControlComposite;
-import org.eclipse.wb.core.controls.flyout.IFlyoutListener;
-import org.eclipse.wb.core.controls.flyout.PluginFlyoutPreferences;
-import org.eclipse.wb.internal.core.editor.structure.PageSiteComposite;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Graphical layout editor part, version 2.
- * <p/>
- * The main component of the editor part is the {@link LayoutCanvasViewer}, which
- * actually delegates its work to the {@link LayoutCanvas} control.
- * <p/>
- * The {@link LayoutCanvasViewer} is set as the site's {@link ISelectionProvider}:
- * when the selection changes in the canvas, it is thus broadcasted to anyone listening
- * on the site's selection service.
- * <p/>
- * This part is also an {@link ISelectionListener}. It listens to the site's selection
- * service and thus receives selection changes from itself as well as the associated
- * outline and property sheet (these are registered by {@link LayoutEditorDelegate#delegateGetAdapter(Class)}).
- *
- * @since GLE2
- */
-public class GraphicalEditorPart extends EditorPart
- implements IPageImageProvider, INullSelectionListener, IFlyoutListener,
- ConfigurationClient {
-
- /*
- * Useful notes:
- * To understand Drag & drop:
- * http://www.eclipse.org/articles/Article-Workbench-DND/drag_drop.html
- *
- * To understand the site's selection listener, selection provider, and the
- * confusion of different-yet-similarly-named interfaces, consult this:
- * http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html
- *
- * To summarize the selection mechanism:
- * - The workbench site selection service can be seen as "centralized"
- * service that registers selection providers and selection listeners.
- * - The editor part and the outline are selection providers.
- * - The editor part, the outline and the property sheet are listeners
- * which all listen to each others indirectly.
- */
-
- /** Property key for the window preferences for the structure flyout */
- private static final String PREF_STRUCTURE = "design.structure"; //$NON-NLS-1$
-
- /** Property key for the window preferences for the palette flyout */
- private static final String PREF_PALETTE = "design.palette"; //$NON-NLS-1$
-
- /**
- * Session-property on files which specifies the initial config state to be used on
- * this file
- */
- public final static QualifiedName NAME_INITIAL_STATE =
- new QualifiedName(AdtPlugin.PLUGIN_ID, "initialstate");//$NON-NLS-1$
-
- /**
- * Session-property on files which specifies the inclusion-context (reference to another layout
- * which should be "including" this layout) when the file is opened
- */
- public final static QualifiedName NAME_INCLUDE =
- new QualifiedName(AdtPlugin.PLUGIN_ID, "includer");//$NON-NLS-1$
-
- /** Reference to the layout editor */
- private final LayoutEditorDelegate mEditorDelegate;
-
- /** Reference to the file being edited. Can also be used to access the {@link IProject}. */
- private IFile mEditedFile;
-
- /** The configuration chooser at the top of the layout editor. */
- private ConfigurationChooser mConfigChooser;
-
- /** The sash that splits the palette from the error view.
- * The error view is shown only when needed. */
- private SashForm mSashError;
-
- /** The palette displayed on the left of the sash. */
- private PaletteControl mPalette;
-
- /** The layout canvas displayed to the right of the sash. */
- private LayoutCanvasViewer mCanvasViewer;
-
- /** The Rules Engine associated with this editor. It is project-specific. */
- private RulesEngine mRulesEngine;
-
- /** Styled text displaying the most recent error in the error view. */
- private StyledText mErrorLabel;
-
- /**
- * The resource reference to a file that should surround this file (e.g. include this file
- * visually), or null if not applicable
- */
- private Reference mIncludedWithin;
-
- private Map<ResourceType, Map<String, ResourceValue>> mConfiguredFrameworkRes;
- private Map<ResourceType, Map<String, ResourceValue>> mConfiguredProjectRes;
- private ProjectCallback mProjectCallback;
- private boolean mNeedsRecompute = false;
- private TargetListener mTargetListener;
- private ResourceResolver mResourceResolver;
- private ReloadListener mReloadListener;
- private int mMinSdkVersion;
- private int mTargetSdkVersion;
- private LayoutActionBar mActionBar;
- private OutlinePage mOutlinePage;
- private FlyoutControlComposite mStructureFlyout;
- private FlyoutControlComposite mPaletteComposite;
- private PropertyFactory mPropertyFactory;
- private boolean mRenderedOnce;
- private final Object mCredential = new Object();
-
- /**
- * Flags which tracks whether this editor is currently active which is set whenever
- * {@link #activated()} is called and clear whenever {@link #deactivated()} is called.
- * This is used to suppress repeated calls to {@link #activate()} to avoid doing
- * unnecessary work.
- */
- private boolean mActive;
-
- /**
- * Constructs a new {@link GraphicalEditorPart}
- *
- * @param editorDelegate the associated XML editor delegate
- */
- public GraphicalEditorPart(@NonNull LayoutEditorDelegate editorDelegate) {
- mEditorDelegate = editorDelegate;
- setPartName("Graphical Layout");
- }
-
- // ------------------------------------
- // Methods overridden from base classes
- //------------------------------------
-
- /**
- * Initializes the editor part with a site and input.
- * {@inheritDoc}
- */
- @Override
- public void init(IEditorSite site, IEditorInput input) throws PartInitException {
- setSite(site);
- useNewEditorInput(input);
-
- if (mTargetListener == null) {
- mTargetListener = new TargetListener();
- AdtPlugin.getDefault().addTargetListener(mTargetListener);
-
- // Trigger a check to see if the SDK needs to be reloaded (which will
- // invoke onSdkLoaded asynchronously as needed).
- AdtPlugin.getDefault().refreshSdk();
- }
- }
-
- private void useNewEditorInput(IEditorInput input) throws PartInitException {
- // The contract of init() mentions we need to fail if we can't understand the input.
- if (!(input instanceof FileEditorInput)) {
- throw new PartInitException("Input is not of type FileEditorInput: " + //$NON-NLS-1$
- input == null ? "null" : input.toString()); //$NON-NLS-1$
- }
- }
-
- @Override
- public Image getPageImage() {
- return IconFactory.getInstance().getIcon("editor_page_design"); //$NON-NLS-1$
- }
-
- @Override
- public void createPartControl(Composite parent) {
-
- Display d = parent.getDisplay();
-
- GridLayout gl = new GridLayout(1, false);
- parent.setLayout(gl);
- gl.marginHeight = gl.marginWidth = 0;
-
- // Check whether somebody has requested an initial state for the newly opened file.
- // The initial state is a serialized version of the state compatible with
- // {@link ConfigurationComposite#CONFIG_STATE}.
- String initialState = null;
- IFile file = mEditedFile;
- if (file == null) {
- IEditorInput input = mEditorDelegate.getEditor().getEditorInput();
- if (input instanceof FileEditorInput) {
- file = ((FileEditorInput) input).getFile();
- }
- }
-
- if (file != null) {
- try {
- initialState = (String) file.getSessionProperty(NAME_INITIAL_STATE);
- if (initialState != null) {
- // Only use once
- file.setSessionProperty(NAME_INITIAL_STATE, null);
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, "Can't read session property %1$s", NAME_INITIAL_STATE);
- }
- }
-
- IPreferenceStore preferenceStore = AdtPlugin.getDefault().getPreferenceStore();
- PluginFlyoutPreferences preferences;
- preferences = new PluginFlyoutPreferences(preferenceStore, PREF_PALETTE);
- preferences.initializeDefaults(DOCK_WEST, STATE_OPEN, 200);
- mPaletteComposite = new FlyoutControlComposite(parent, SWT.NONE, preferences);
- mPaletteComposite.setTitleText("Palette");
- mPaletteComposite.setMinWidth(100);
- Composite paletteParent = mPaletteComposite.getFlyoutParent();
- Composite editorParent = mPaletteComposite.getClientParent();
- mPaletteComposite.setListener(this);
-
- mPaletteComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
-
- PageSiteComposite paletteComposite = new PageSiteComposite(paletteParent, SWT.BORDER);
- paletteComposite.setTitleText("Palette");
- paletteComposite.setTitleImage(IconFactory.getInstance().getIcon("palette"));
- PalettePage decor = new PalettePage(this);
- paletteComposite.setPage(decor);
- mPalette = (PaletteControl) decor.getControl();
- decor.createToolbarItems(paletteComposite.getToolBar());
-
- // Create the shared structure+editor area
- preferences = new PluginFlyoutPreferences(preferenceStore, PREF_STRUCTURE);
- preferences.initializeDefaults(DOCK_EAST, STATE_OPEN, 300);
- mStructureFlyout = new FlyoutControlComposite(editorParent, SWT.NONE, preferences);
- mStructureFlyout.setTitleText("Structure");
- mStructureFlyout.setMinWidth(150);
- mStructureFlyout.setListener(this);
-
- Composite layoutBarAndCanvas = new Composite(mStructureFlyout.getClientParent(), SWT.NONE);
- GridLayout gridLayout = new GridLayout(1, false);
- gridLayout.horizontalSpacing = 0;
- gridLayout.verticalSpacing = 0;
- gridLayout.marginWidth = 0;
- gridLayout.marginHeight = 0;
- layoutBarAndCanvas.setLayout(gridLayout);
-
- mConfigChooser = new ConfigurationChooser(this, layoutBarAndCanvas, initialState);
- mConfigChooser.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-
- mActionBar = new LayoutActionBar(layoutBarAndCanvas, SWT.NONE, this);
- GridData detailsData = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1);
- mActionBar.setLayoutData(detailsData);
- if (file != null) {
- mActionBar.updateErrorIndicator(file);
- }
-
- mSashError = new SashForm(layoutBarAndCanvas, SWT.VERTICAL | SWT.BORDER);
- mSashError.setLayoutData(new GridData(GridData.FILL_BOTH));
-
- mCanvasViewer = new LayoutCanvasViewer(mEditorDelegate, mRulesEngine, mSashError, SWT.NONE);
- mSashError.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
-
- mErrorLabel = new StyledText(mSashError, SWT.READ_ONLY | SWT.WRAP | SWT.V_SCROLL);
- mErrorLabel.setEditable(false);
- mErrorLabel.setBackground(d.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
- mErrorLabel.setForeground(d.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
- mErrorLabel.addMouseListener(new ErrorLabelListener());
-
- mSashError.setWeights(new int[] { 80, 20 });
- mSashError.setMaximizedControl(mCanvasViewer.getControl());
-
- // Create the structure views. We really should do this *lazily*, but that
- // seems to cause a bug: property sheet won't update. Track this down later.
- createStructureViews(mStructureFlyout.getFlyoutParent(), false);
- showStructureViews(false, false, false);
-
- // Initialize the state
- reloadPalette();
-
- IWorkbenchPartSite site = getSite();
- site.setSelectionProvider(mCanvasViewer);
- site.getPage().addSelectionListener(this);
- }
-
- private void createStructureViews(Composite parent, boolean createPropertySheet) {
- mOutlinePage = new OutlinePage(this);
- mOutlinePage.setShowPropertySheet(createPropertySheet);
- mOutlinePage.setShowHeader(true);
-
- IPageSite pageSite = new IPageSite() {
-
- @Override
- public IWorkbenchPage getPage() {
- return getSite().getPage();
- }
-
- @Override
- public ISelectionProvider getSelectionProvider() {
- return getSite().getSelectionProvider();
- }
-
- @Override
- public Shell getShell() {
- return getSite().getShell();
- }
-
- @Override
- public IWorkbenchWindow getWorkbenchWindow() {
- return getSite().getWorkbenchWindow();
- }
-
- @Override
- public void setSelectionProvider(ISelectionProvider provider) {
- getSite().setSelectionProvider(provider);
- }
-
- @Override
- public Object getAdapter(Class adapter) {
- return getSite().getAdapter(adapter);
- }
-
- @Override
- public Object getService(Class api) {
- return getSite().getService(api);
- }
-
- @Override
- public boolean hasService(Class api) {
- return getSite().hasService(api);
- }
-
- @Override
- public void registerContextMenu(String menuId, MenuManager menuManager,
- ISelectionProvider selectionProvider) {
- }
-
- @Override
- public IActionBars getActionBars() {
- return null;
- }
- };
- mOutlinePage.init(pageSite);
- mOutlinePage.createControl(parent);
- mOutlinePage.addSelectionChangedListener(new ISelectionChangedListener() {
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- getCanvasControl().getSelectionManager().setSelection(event.getSelection());
- }
- });
- }
-
- /** Shows the embedded (within the layout editor) outline and or properties */
- void showStructureViews(final boolean showOutline, final boolean showProperties,
- final boolean updateLayout) {
- Display display = mConfigChooser.getDisplay();
- if (display.getThread() != Thread.currentThread()) {
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- if (!mConfigChooser.isDisposed()) {
- showStructureViews(showOutline, showProperties, updateLayout);
- }
- }
-
- });
- return;
- }
-
- boolean show = showOutline || showProperties;
-
- Control[] children = mStructureFlyout.getFlyoutParent().getChildren();
- if (children.length == 0) {
- if (show) {
- createStructureViews(mStructureFlyout.getFlyoutParent(), showProperties);
- }
- return;
- }
-
- mOutlinePage.setShowPropertySheet(showProperties);
-
- Control control = children[0];
- if (show != control.getVisible()) {
- control.setVisible(show);
- mOutlinePage.setActive(show); // disable/re-enable listeners etc
- if (show) {
- ISelection selection = getCanvasControl().getSelectionManager().getSelection();
- mOutlinePage.selectionChanged(getEditorDelegate().getEditor(), selection);
- }
- if (updateLayout) {
- mStructureFlyout.layout();
- }
- // TODO: *dispose* the non-showing widgets to save memory?
- }
- }
-
- /**
- * Returns the property factory associated with this editor
- *
- * @return the factory
- */
- @NonNull
- public PropertyFactory getPropertyFactory() {
- if (mPropertyFactory == null) {
- mPropertyFactory = new PropertyFactory(this);
- }
-
- return mPropertyFactory;
- }
-
- /**
- * Invoked by {@link LayoutCanvas} to set the model (a.k.a. the root view info).
- *
- * @param rootViewInfo The root of the view info hierarchy. Can be null.
- */
- public void setModel(CanvasViewInfo rootViewInfo) {
- if (mOutlinePage != null) {
- mOutlinePage.setModel(rootViewInfo);
- }
- }
-
- /**
- * Listens to workbench selections that does NOT come from {@link LayoutEditorDelegate}
- * (those are generated by ourselves).
- * <p/>
- * Selection can be null, as indicated by this class implementing
- * {@link INullSelectionListener}.
- */
- @Override
- public void selectionChanged(IWorkbenchPart part, ISelection selection) {
- Object delegate = part instanceof IEditorPart ?
- LayoutEditorDelegate.fromEditor((IEditorPart) part) : null;
- if (delegate == null) {
- if (part instanceof PageBookView) {
- PageBookView pbv = (PageBookView) part;
- org.eclipse.ui.part.IPage currentPage = pbv.getCurrentPage();
- if (currentPage instanceof OutlinePage) {
- LayoutCanvas canvas = getCanvasControl();
- if (canvas != null && canvas.getOutlinePage() != currentPage) {
- // The notification is not for this view; ignore
- // (can happen when there are multiple pages simultaneously
- // visible)
- return;
- }
- }
- }
- mCanvasViewer.setSelection(selection);
- }
- }
-
- @Override
- public void dispose() {
- getSite().getPage().removeSelectionListener(this);
- getSite().setSelectionProvider(null);
-
- if (mTargetListener != null) {
- AdtPlugin.getDefault().removeTargetListener(mTargetListener);
- mTargetListener = null;
- }
-
- if (mReloadListener != null) {
- LayoutReloadMonitor.getMonitor().removeListener(mReloadListener);
- mReloadListener = null;
- }
-
- if (mCanvasViewer != null) {
- mCanvasViewer.dispose();
- mCanvasViewer = null;
- }
- super.dispose();
- }
-
- /**
- * Select the visual element corresponding to the given XML node
- * @param xmlNode The Node whose element we want to select
- */
- public void select(Node xmlNode) {
- mCanvasViewer.getCanvas().getSelectionManager().select(xmlNode);
- }
-
- // ---- Implements ConfigurationClient ----
- @Override
- public void aboutToChange(int flags) {
- if ((flags & CFG_TARGET) != 0) {
- IAndroidTarget oldTarget = mConfigChooser.getConfiguration().getTarget();
- preRenderingTargetChangeCleanUp(oldTarget);
- }
- }
-
- @Override
- public boolean changed(int flags) {
- mConfiguredFrameworkRes = mConfiguredProjectRes = null;
- mResourceResolver = null;
-
- if (mEditedFile == null) {
- return true;
- }
-
- // Before doing the normal process, test for the following case.
- // - the editor is being opened (or reset for a new input)
- // - the file being opened is not the best match for any possible configuration
- // - another random compatible config was chosen in the config composite.
- // The result is that 'match' will not be the file being edited, but because this is not
- // due to a config change, we should not trigger opening the actual best match (also,
- // because the editor is still opening the MatchingStrategy woudln't answer true
- // and the best match file would open in a different editor).
- // So the solution is that if the editor is being created, we just call recomputeLayout
- // without looking for a better matching layout file.
- if (mEditorDelegate.getEditor().isCreatingPages()) {
- recomputeLayout();
- } else {
- boolean affectsFileSelection = (flags & Configuration.MASK_FILE_ATTRS) != 0;
- IFile best = null;
- // get the resources of the file's project.
- if (affectsFileSelection) {
- best = ConfigurationMatcher.getBestFileMatch(mConfigChooser);
- }
- if (best != null) {
- if (!best.equals(mEditedFile)) {
- try {
- // tell the editor that the next replacement file is due to a config
- // change.
- mEditorDelegate.setNewFileOnConfigChange(true);
-
- boolean reuseEditor = AdtPrefs.getPrefs().isSharedLayoutEditor();
- if (!reuseEditor) {
- String data = ConfigurationDescription.getDescription(best);
- if (data == null) {
- // Not previously opened: duplicate the current state as
- // much as possible
- data = mConfigChooser.getConfiguration().toPersistentString();
- ConfigurationDescription.setDescription(best, data);
- }
- }
-
- // ask the IDE to open the replacement file.
- IDE.openEditor(getSite().getWorkbenchWindow().getActivePage(), best,
- CommonXmlEditor.ID);
-
- // we're done!
- return reuseEditor;
- } catch (PartInitException e) {
- // FIXME: do something!
- }
- }
-
- // at this point, we have not opened a new file.
-
- // Store the state in the current file
- mConfigChooser.saveConstraints();
-
- // Even though the layout doesn't change, the config changed, and referenced
- // resources need to be updated.
- recomputeLayout();
- } else if (affectsFileSelection) {
- // display the error.
- Configuration configuration = mConfigChooser.getConfiguration();
- FolderConfiguration currentConfig = configuration.getFullConfig();
- displayError(
- "No resources match the configuration\n" +
- " \n" +
- "\t%1$s\n" +
- " \n" +
- "Change the configuration or create:\n" +
- " \n" +
- "\tres/%2$s/%3$s\n" +
- " \n" +
- "You can also click the 'Create New...' item in the configuration " +
- "dropdown menu above.",
- 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 & CFG_TARGET) != 0) {
- Configuration configuration = mConfigChooser.getConfiguration();
- IAndroidTarget target = configuration.getTarget();
- Sdk current = Sdk.getCurrent();
- if (current != null) {
- AndroidTargetData targetData = current.getTargetData(target);
- updateCapabilities(targetData);
- }
- }
-
- 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
- if (mActionBar.isZoomingAllowed()) {
- getCanvasControl().setFitScale(true, true /*allowZoomIn*/);
- }
- }
-
- reloadPalette();
-
- getCanvasControl().getPreviewManager().configurationChanged(flags);
-
- return true;
- }
-
- @Override
- public void setActivity(@NonNull String activity) {
- ManifestInfo manifest = ManifestInfo.get(mEditedFile.getProject());
- String pkg = manifest.getPackage();
- if (activity.startsWith(pkg) && activity.length() > pkg.length()
- && activity.charAt(pkg.length()) == '.') {
- activity = activity.substring(pkg.length());
- }
- CommonXmlEditor editor = getEditorDelegate().getEditor();
- Element element = editor.getUiRootNode().getXmlDocument().getDocumentElement();
- AdtUtils.setToolsAttribute(editor,
- element, "Choose Activity", ATTR_CONTEXT,
- activity, false /*reveal*/, false /*append*/);
- }
-
- /**
- * Returns a {@link ProjectResources} for the framework resources based on the current
- * configuration selection.
- * @return the framework resources or null if not found.
- */
- @Override
- @Nullable
- public ResourceRepository getFrameworkResources() {
- return getFrameworkResources(getRenderingTarget());
- }
-
- /**
- * Returns a {@link ProjectResources} for the framework resources of a given
- * target.
- * @param target the target for which to return the framework resources.
- * @return the framework resources or null if not found.
- */
- @Override
- @Nullable
- public ResourceRepository getFrameworkResources(@Nullable IAndroidTarget target) {
- if (target != null) {
- AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
-
- if (data != null) {
- return data.getFrameworkResources();
- }
- }
-
- return null;
- }
-
- @Override
- @Nullable
- public ProjectResources getProjectResources() {
- if (mEditedFile != null) {
- ResourceManager manager = ResourceManager.getInstance();
- return manager.getProjectResources(mEditedFile.getProject());
- }
-
- return null;
- }
-
-
- @Override
- @NonNull
- public Map<ResourceType, Map<String, ResourceValue>> getConfiguredFrameworkResources() {
- if (mConfiguredFrameworkRes == null && mConfigChooser != null) {
- ResourceRepository frameworkRes = getFrameworkResources();
-
- if (frameworkRes == null) {
- AdtPlugin.log(IStatus.ERROR, "Failed to get ProjectResource for the framework");
- } else {
- // get the framework resource values based on the current config
- mConfiguredFrameworkRes = frameworkRes.getConfiguredResources(
- mConfigChooser.getConfiguration().getFullConfig());
- }
- }
-
- return mConfiguredFrameworkRes;
- }
-
- @Override
- @NonNull
- public Map<ResourceType, Map<String, ResourceValue>> getConfiguredProjectResources() {
- if (mConfiguredProjectRes == null && mConfigChooser != null) {
- ProjectResources project = getProjectResources();
-
- // get the project resource values based on the current config
- mConfiguredProjectRes = project.getConfiguredResources(
- mConfigChooser.getConfiguration().getFullConfig());
- }
-
- return mConfiguredProjectRes;
- }
-
- @Override
- public void createConfigFile() {
- LayoutCreatorDialog dialog = new LayoutCreatorDialog(mConfigChooser.getShell(),
- mEditedFile.getName(), mConfigChooser.getConfiguration().getFullConfig());
- if (dialog.open() != Window.OK) {
- return;
- }
-
- FolderConfiguration config = new FolderConfiguration();
- dialog.getConfiguration(config);
-
- // Creates a new layout file from the specified {@link FolderConfiguration}.
- CreateNewConfigJob job = new CreateNewConfigJob(this, mEditedFile, config);
- job.schedule();
- }
-
- /**
- * Returns the resource name of the file that is including this current layout, if any
- * (may be null)
- *
- * @return the resource name of an including layout, or null
- */
- @Override
- public Reference getIncludedWithin() {
- return mIncludedWithin;
- }
-
- @Override
- @Nullable
- public LayoutCanvas getCanvas() {
- return getCanvasControl();
- }
-
- /**
- * Listens to target changed in the current project, to trigger a new layout rendering.
- */
- private class TargetListener implements ITargetChangeListener {
-
- @Override
- public void onProjectTargetChange(IProject changedProject) {
- if (changedProject != null && changedProject.equals(getProject())) {
- updateEditor();
- }
- }
-
- @Override
- public void onTargetLoaded(IAndroidTarget loadedTarget) {
- IAndroidTarget target = getRenderingTarget();
- if (target != null && target.equals(loadedTarget)) {
- updateEditor();
- }
- }
-
- @Override
- public void onSdkLoaded() {
- // get the current rendering target to unload it
- IAndroidTarget oldTarget = getRenderingTarget();
- preRenderingTargetChangeCleanUp(oldTarget);
-
- computeSdkVersion();
-
- // get the project target
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(mEditedFile.getProject());
- if (target != null) {
- mConfigChooser.onSdkLoaded(target);
- changed(CFG_FOLDER | CFG_TARGET);
- }
- }
- }
-
- private void updateEditor() {
- mEditorDelegate.getEditor().commitPages(false /* onSave */);
-
- // because the target changed we must reset the configured resources.
- mConfiguredFrameworkRes = mConfiguredProjectRes = null;
- mResourceResolver = null;
-
- // make sure we remove the custom view loader, since its parent class loader is the
- // bridge class loader.
- mProjectCallback = null;
-
- // recreate the ui root node always, this will also call onTargetChange
- // on the config composite
- mEditorDelegate.delegateInitUiRootNode(true /*force*/);
- }
-
- private IProject getProject() {
- return getEditorDelegate().getEditor().getProject();
- }
- }
-
- /** Refresh the configured project resources associated with this editor */
- public void refreshProjectResources() {
- mConfiguredProjectRes = null;
- mResourceResolver = null;
- }
-
- /**
- * Returns the currently edited file
- *
- * @return the currently edited file, or null
- */
- public IFile getEditedFile() {
- return mEditedFile;
- }
-
- /**
- * Returns the project for the currently edited file, or null
- *
- * @return the project containing the edited file, or null
- */
- public IProject getProject() {
- if (mEditedFile != null) {
- return mEditedFile.getProject();
- } else {
- return null;
- }
- }
-
- // ----------------
-
- /**
- * Save operation in the Graphical Editor Part.
- * <p/>
- * In our workflow, the model is owned by the Structured XML Editor.
- * The graphical layout editor just displays it -- thus we don't really
- * save anything here.
- * <p/>
- * This must NOT call the parent editor part. At the contrary, the parent editor
- * part will call this *after* having done the actual save operation.
- * <p/>
- * The only action this editor must do is mark the undo command stack as
- * being no longer dirty.
- */
- @Override
- public void doSave(IProgressMonitor monitor) {
- // TODO implement a command stack
-// getCommandStack().markSaveLocation();
-// firePropertyChange(PROP_DIRTY);
- }
-
- /**
- * Save operation in the Graphical Editor Part.
- * <p/>
- * In our workflow, the model is owned by the Structured XML Editor.
- * The graphical layout editor just displays it -- thus we don't really
- * save anything here.
- */
- @Override
- public void doSaveAs() {
- // pass
- }
-
- /**
- * In our workflow, the model is owned by the Structured XML Editor.
- * The graphical layout editor just displays it -- thus we don't really
- * save anything here.
- */
- @Override
- public boolean isDirty() {
- return false;
- }
-
- /**
- * In our workflow, the model is owned by the Structured XML Editor.
- * The graphical layout editor just displays it -- thus we don't really
- * save anything here.
- */
- @Override
- public boolean isSaveAsAllowed() {
- return false;
- }
-
- @Override
- public void setFocus() {
- // TODO Auto-generated method stub
-
- }
-
- /**
- * Responds to a page change that made the Graphical editor page the activated page.
- */
- public void activated() {
- if (!mActive) {
- mActive = true;
-
- syncDockingState();
- mActionBar.updateErrorIndicator();
-
- boolean changed = mConfigChooser.syncRenderState();
- if (changed) {
- // Will also force recomputeLayout()
- return;
- }
-
- if (mNeedsRecompute) {
- recomputeLayout();
- }
-
- mCanvasViewer.getCanvas().syncPreviewMode();
- }
- }
-
- /**
- * The global docking state version. This number is incremented each time
- * the user customizes the window layout in any layout.
- */
- private static int sDockingStateVersion;
-
- /**
- * The window docking state version that this window is currently showing;
- * when a different window is reconfigured, the global version number is
- * incremented, and when this window is shown, and the current version is
- * less than the global version, the window layout will be synced.
- */
- private int mDockingStateVersion;
-
- /**
- * Syncs the window docking state.
- * <p>
- * The layout editor lets you change the docking state -- e.g. you can minimize the
- * palette, and drag the structure view to the bottom, and so on. When you restart
- * the IDE, the window comes back up with your customized state.
- * <p>
- * <b>However</b>, when you have multiple editor files open, if you minimize the palette
- * in one editor and then switch to another, the other editor will have the old window
- * state. That's because each editor has its own set of windows.
- * <p>
- * This method fixes this. Whenever a window is shown, this method is called, and the
- * docking state is synced such that the editor will match the current persistent docking
- * state.
- */
- private void syncDockingState() {
- if (mDockingStateVersion == sDockingStateVersion) {
- // No changes to apply
- return;
- }
- mDockingStateVersion = sDockingStateVersion;
-
- IPreferenceStore preferenceStore = AdtPlugin.getDefault().getPreferenceStore();
- PluginFlyoutPreferences preferences;
- preferences = new PluginFlyoutPreferences(preferenceStore, PREF_PALETTE);
- mPaletteComposite.apply(preferences);
- preferences = new PluginFlyoutPreferences(preferenceStore, PREF_STRUCTURE);
- mStructureFlyout.apply(preferences);
- mPaletteComposite.layout();
- mStructureFlyout.layout();
- mPaletteComposite.redraw(); // the structure view is nested within the palette
- }
-
- /**
- * Responds to a page change that made the Graphical editor page the deactivated page
- */
- public void deactivated() {
- mActive = false;
-
- LayoutCanvas canvas = getCanvasControl();
- if (canvas != null) {
- canvas.deactivated();
- }
- }
-
- /**
- * Opens and initialize the editor with a new file.
- * @param file the file being edited.
- */
- public void openFile(IFile file) {
- mEditedFile = file;
- mConfigChooser.setFile(mEditedFile);
-
- if (mReloadListener == null) {
- mReloadListener = new ReloadListener();
- LayoutReloadMonitor.getMonitor().addListener(mEditedFile.getProject(), mReloadListener);
- }
-
- if (mRulesEngine == null) {
- mRulesEngine = new RulesEngine(this, mEditedFile.getProject());
- if (mCanvasViewer != null) {
- mCanvasViewer.getCanvas().setRulesEngine(mRulesEngine);
- }
- }
-
- // Pick up hand-off data: somebody requesting this file to be opened may have
- // requested that it should be opened as included within another file
- if (mEditedFile != null) {
- try {
- mIncludedWithin = (Reference) mEditedFile.getSessionProperty(NAME_INCLUDE);
- if (mIncludedWithin != null) {
- // Only use once
- mEditedFile.setSessionProperty(NAME_INCLUDE, null);
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, "Can't access session property %1$s", NAME_INCLUDE);
- }
- }
-
- computeSdkVersion();
- }
-
- /**
- * Resets the editor with a replacement file.
- * @param file the replacement file.
- */
- public void replaceFile(IFile file) {
- mEditedFile = file;
- mConfigChooser.replaceFile(mEditedFile);
- computeSdkVersion();
- }
-
- /**
- * Resets the editor with a replacement file coming from a config change in the config
- * selector.
- * @param file the replacement file.
- */
- public void changeFileOnNewConfig(IFile file) {
- mEditedFile = file;
- mConfigChooser.changeFileOnNewConfig(mEditedFile);
- }
-
- /**
- * Responds to a target change for the project of the edited file
- */
- public void onTargetChange() {
- AndroidTargetData targetData = mConfigChooser.onXmlModelLoaded();
- updateCapabilities(targetData);
-
- changed(CFG_FOLDER | CFG_TARGET);
- }
-
- /** Updates the capabilities for the given target data (which may be null) */
- private void updateCapabilities(AndroidTargetData targetData) {
- if (targetData != null) {
- LayoutLibrary layoutLib = targetData.getLayoutLibrary();
- if (mIncludedWithin != null && !layoutLib.supports(Capability.EMBEDDED_LAYOUT)) {
- showIn(null);
- }
- }
- }
-
- /**
- * Returns the {@link CommonXmlDelegate} for this editor
- *
- * @return the {@link CommonXmlDelegate} for this editor
- */
- @NonNull
- public LayoutEditorDelegate getEditorDelegate() {
- return mEditorDelegate;
- }
-
- /**
- * Returns the {@link RulesEngine} associated with this editor
- *
- * @return the {@link RulesEngine} associated with this editor, never null
- */
- public RulesEngine getRulesEngine() {
- return mRulesEngine;
- }
-
- /**
- * Return the {@link LayoutCanvas} associated with this editor
- *
- * @return the associated {@link LayoutCanvas}
- */
- public LayoutCanvas getCanvasControl() {
- if (mCanvasViewer != null) {
- return mCanvasViewer.getCanvas();
- }
- return null;
- }
-
- /**
- * Returns the {@link UiDocumentNode} for the XML model edited by this editor
- *
- * @return the associated model
- */
- public UiDocumentNode getModel() {
- return mEditorDelegate.getUiRootNode();
- }
-
- /**
- * Callback for XML model changed. Only update/recompute the layout if the editor is visible
- */
- public void onXmlModelChanged() {
- // To optimize the rendering when the user is editing in the XML pane, we don't
- // refresh the editor if it's not the active part.
- //
- // This behavior is acceptable when the editor is the single "full screen" part
- // (as in this case active means visible.)
- // Unfortunately this breaks in 2 cases:
- // - when performing a drag'n'drop from one editor to another, the target is not
- // properly refreshed before it becomes active.
- // - when duplicating the editor window and placing both editors side by side (xml in one
- // and canvas in the other one), the canvas may not be refreshed when the XML is edited.
- //
- // TODO find a way to really query whether the pane is visible, not just active.
-
- if (mEditorDelegate.isGraphicalEditorActive()) {
- recomputeLayout();
- } else {
- // Remember we want to recompute as soon as the editor becomes active.
- mNeedsRecompute = true;
- }
- }
-
- /**
- * Recomputes the layout
- */
- public void recomputeLayout() {
- try {
- if (!ensureFileValid()) {
- return;
- }
-
- UiDocumentNode model = getModel();
- LayoutCanvas canvas = mCanvasViewer.getCanvas();
- if (!ensureModelValid(model)) {
- // Although we display an error, we still treat an empty document as a
- // successful layout result so that we can drop new elements in it.
- //
- // For that purpose, create a special LayoutScene that has no image,
- // no root view yet indicates success and then update the canvas with it.
-
- canvas.setSession(
- new StaticRenderSession(
- Result.Status.SUCCESS.createResult(),
- null /*rootViewInfo*/, null /*image*/),
- null /*explodeNodes*/, true /* layoutlib5 */);
- return;
- }
-
- LayoutLibrary layoutLib = getReadyLayoutLib(true /*displayError*/);
-
- if (layoutLib != null) {
- // if drawing in real size, (re)set the scaling factor.
- if (mActionBar.isZoomingRealSize()) {
- mActionBar.computeAndSetRealScale(false /* redraw */);
- }
-
- IProject project = mEditedFile.getProject();
- renderWithBridge(project, model, layoutLib);
-
- canvas.getPreviewManager().renderPreviews();
- }
- } finally {
- // no matter the result, we are done doing the recompute based on the latest
- // resource/code change.
- mNeedsRecompute = false;
- }
- }
-
- /**
- * Reloads the palette
- */
- public void reloadPalette() {
- if (mPalette != null) {
- IAndroidTarget renderingTarget = getRenderingTarget();
- if (renderingTarget != null) {
- mPalette.reloadPalette(renderingTarget);
- }
- }
- }
-
- /**
- * Returns the {@link LayoutLibrary} associated with this editor, if it has
- * been initialized already. May return null if it has not been initialized (or has
- * not finished initializing).
- *
- * @return The {@link LayoutLibrary}, or null
- */
- public LayoutLibrary getLayoutLibrary() {
- return getReadyLayoutLib(false /*displayError*/);
- }
-
- /**
- * Returns the scale to multiply pixels in the layout coordinate space with to obtain
- * the corresponding dip (device independent pixel)
- *
- * @return the scale to multiple layout coordinates with to obtain the dip position
- */
- public float getDipScale() {
- float dpi = mConfigChooser.getConfiguration().getDensity().getDpiValue();
- return Density.DEFAULT_DENSITY / dpi;
- }
-
- // --- private methods ---
-
- /**
- * Ensure that the file associated with this editor is valid (exists and is
- * synchronized). Any reasons why it is not are displayed in the editor's error area.
- *
- * @return True if the editor is valid, false otherwise.
- */
- private boolean ensureFileValid() {
- // check that the resource exists. If the file is opened but the project is closed
- // or deleted for some reason (changed from outside of eclipse), then this will
- // return false;
- if (mEditedFile.exists() == false) {
- displayError("Resource '%1$s' does not exist.",
- mEditedFile.getFullPath().toString());
- return false;
- }
-
- if (mEditedFile.isSynchronized(IResource.DEPTH_ZERO) == false) {
- String message = String.format("%1$s is out of sync. Please refresh.",
- mEditedFile.getName());
-
- displayError(message);
-
- // also print it in the error console.
- IProject iProject = mEditedFile.getProject();
- AdtPlugin.printErrorToConsole(iProject.getName(), message);
- return false;
- }
-
- return true;
- }
-
- /**
- * Returns a {@link LayoutLibrary} that is ready for rendering, or null if the bridge
- * is not available or not ready yet (due to SDK loading still being in progress etc).
- * If enabled, any reasons preventing the bridge from being returned are displayed to the
- * editor's error area.
- *
- * @param displayError whether to display the loading error or not.
- *
- * @return LayoutBridge the layout bridge for rendering this editor's scene
- */
- LayoutLibrary getReadyLayoutLib(boolean displayError) {
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = getRenderingTarget();
-
- if (target != null) {
- AndroidTargetData data = currentSdk.getTargetData(target);
- if (data != null) {
- LayoutLibrary layoutLib = data.getLayoutLibrary();
-
- if (layoutLib.getStatus() == LoadStatus.LOADED) {
- return layoutLib;
- } else if (displayError) { // getBridge() == null
- // SDK is loaded but not the layout library!
-
- // check whether the bridge managed to load, or not
- if (layoutLib.getStatus() == LoadStatus.LOADING) {
- displayError("Eclipse is loading framework information and the layout library from the SDK folder.\n%1$s will refresh automatically once the process is finished.",
- mEditedFile.getName());
- } else {
- String message = layoutLib.getLoadMessage();
- displayError("Eclipse failed to load the framework information and the layout library!" +
- message != null ? "\n" + message : "");
- }
- }
- } else { // data == null
- // It can happen that the workspace refreshes while the SDK is loading its
- // data, which could trigger a redraw of the opened layout if some resources
- // changed while Eclipse is closed.
- // In this case data could be null, but this is not an error.
- // We can just silently return, as all the opened editors are automatically
- // refreshed once the SDK finishes loading.
- LoadStatus targetLoadStatus = currentSdk.checkAndLoadTargetData(target, null);
-
- // display error is asked.
- if (displayError) {
- String targetName = target.getName();
- switch (targetLoadStatus) {
- case LOADING:
- String s;
- if (currentSdk.getTarget(getProject()) == target) {
- s = String.format(
- "The project target (%1$s) is still loading.",
- targetName);
- } else {
- s = String.format(
- "The rendering target (%1$s) is still loading.",
- targetName);
- }
- s += "\nThe layout will refresh automatically once the process is finished.";
- displayError(s);
-
- break;
- case FAILED: // known failure
- case LOADED: // success but data isn't loaded?!?!
- displayError("The project target (%s) was not properly loaded.",
- targetName);
- break;
- }
- }
- }
-
- } else if (displayError) { // target == null
- displayError("The project target is not set. Right click project, choose Properties | Android.");
- }
- } else if (displayError) { // currentSdk == null
- displayError("Eclipse is loading the SDK.\n%1$s will refresh automatically once the process is finished.",
- mEditedFile.getName());
- }
-
- return null;
- }
-
- /**
- * Returns the {@link IAndroidTarget} used for the rendering.
- * <p/>
- * This first looks for the rendering target setup in the config UI, and if nothing has
- * been setup yet, returns the target of the project.
- *
- * @return an IAndroidTarget object or null if no target is setup and the project has no
- * target set.
- *
- */
- public IAndroidTarget getRenderingTarget() {
- // if the SDK is null no targets are loaded.
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk == null) {
- return null;
- }
-
- // attempt to get a target from the configuration selector.
- IAndroidTarget renderingTarget = mConfigChooser.getConfiguration().getTarget();
- if (renderingTarget != null) {
- return renderingTarget;
- }
-
- // fall back to the project target
- if (mEditedFile != null) {
- return currentSdk.getTarget(mEditedFile.getProject());
- }
-
- return null;
- }
-
- /**
- * Returns whether the current rendering target supports the given capability
- *
- * @param capability the capability to be looked up
- * @return true if the current rendering target supports the given capability
- */
- public boolean renderingSupports(Capability capability) {
- IAndroidTarget target = getRenderingTarget();
- if (target != null) {
- AndroidTargetData targetData = Sdk.getCurrent().getTargetData(target);
- LayoutLibrary layoutLib = targetData.getLayoutLibrary();
- return layoutLib.supports(capability);
- }
-
- return false;
- }
-
- private boolean ensureModelValid(UiDocumentNode model) {
- // check there is actually a model (maybe the file is empty).
- if (model.getUiChildren().size() == 0) {
- if (mEditorDelegate.getEditor().isCreatingPages()) {
- displayError("Loading editor");
- return false;
- }
- displayError(
- "No XML content. Please add a root view or layout to your document.");
- return false;
- }
-
- return true;
- }
-
- /**
- * Creates a {@link RenderService} associated with this editor
- * @return the render service
- */
- @NonNull
- public RenderService createRenderService() {
- return RenderService.create(this, mCredential);
- }
-
- /**
- * Creates a {@link RenderLogger} associated with this editor
- * @param name the name of the logger
- * @return the new logger
- */
- @NonNull
- public RenderLogger createRenderLogger(String name) {
- return new RenderLogger(name, mCredential);
- }
-
- /**
- * Creates a {@link RenderService} associated with this editor
- *
- * @param configuration the configuration to use (and fallback to editor for the rest)
- * @param resolver a resource resolver to use to look up resources
- * @return the render service
- */
- @NonNull
- public RenderService createRenderService(Configuration configuration,
- ResourceResolver resolver) {
- return RenderService.create(this, configuration, resolver, mCredential);
- }
-
- private void renderWithBridge(IProject iProject, UiDocumentNode model,
- LayoutLibrary layoutLib) {
- LayoutCanvas canvas = getCanvasControl();
- Set<UiElementNode> explodeNodes = canvas.getNodesToExplode();
- RenderLogger logger = createRenderLogger(mEditedFile.getName());
- RenderingMode renderingMode = RenderingMode.NORMAL;
- // FIXME set the rendering mode using ViewRule or something.
- List<UiElementNode> children = model.getUiChildren();
- if (children.size() > 0 &&
- children.get(0).getDescriptor().getXmlLocalName().equals(SCROLL_VIEW)) {
- renderingMode = RenderingMode.V_SCROLL;
- }
-
- RenderSession session = RenderService.create(this, mCredential)
- .setModel(model)
- .setLog(logger)
- .setRenderingMode(renderingMode)
- .setIncludedWithin(mIncludedWithin)
- .setNodesToExpand(explodeNodes)
- .createRenderSession();
-
- boolean layoutlib5 = layoutLib.supports(Capability.EMBEDDED_LAYOUT);
- canvas.setSession(session, explodeNodes, layoutlib5);
-
- // update the UiElementNode with the layout info.
- if (session != null && session.getResult().isSuccess() == false) {
- // An error was generated. Print it (and any other accumulated warnings)
- String errorMessage = session.getResult().getErrorMessage();
- Throwable exception = session.getResult().getException();
- if (exception != null && errorMessage == null) {
- errorMessage = exception.toString();
- }
- if (exception != null || (errorMessage != null && errorMessage.length() > 0)) {
- logger.error(null, errorMessage, exception, null /*data*/);
- } else if (!logger.hasProblems()) {
- logger.error(null, "Unexpected error in rendering, no details given",
- null /*data*/);
- }
- // These errors will be included in the log warnings which are
- // displayed regardless of render success status below
- }
-
- // We might have detected some missing classes and swapped them by a mock view,
- // or run into fidelity warnings or missing resources, so emit all these
- // warnings
- Set<String> missingClasses = mProjectCallback.getMissingClasses();
- Set<String> brokenClasses = mProjectCallback.getUninstantiatableClasses();
- if (logger.hasProblems()) {
- displayLoggerProblems(iProject, logger);
- displayFailingClasses(missingClasses, brokenClasses, true);
- displayUserStackTrace(logger, true);
- } else if (missingClasses.size() > 0 || brokenClasses.size() > 0) {
- displayFailingClasses(missingClasses, brokenClasses, false);
- displayUserStackTrace(logger, true);
- } else if (session != null) {
- // Nope, no missing or broken classes. Clear success, congrats!
- hideError();
-
- // First time this layout is opened, run lint on the file (after a delay)
- if (!mRenderedOnce) {
- mRenderedOnce = true;
- Job job = new Job("Run Lint") {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- getEditorDelegate().delegateRunLint();
- return Status.OK_STATUS;
- }
-
- };
- job.setSystem(true);
- job.schedule(3000); // 3 seconds
- }
-
- mConfigChooser.ensureInitialized();
- }
-
- model.refreshUi();
- }
-
- /**
- * Returns the {@link ResourceResolver} for this editor
- *
- * @return the resolver used to resolve resources for the current configuration of
- * this editor, or null
- */
- public ResourceResolver getResourceResolver() {
- if (mResourceResolver == null) {
- String theme = mConfigChooser.getThemeName();
- if (theme == null) {
- displayError("Missing theme.");
- return null;
- }
- boolean isProjectTheme = mConfigChooser.getConfiguration().isProjectTheme();
-
- Map<ResourceType, Map<String, ResourceValue>> configuredProjectRes =
- getConfiguredProjectResources();
-
- // Get the framework resources
- Map<ResourceType, Map<String, ResourceValue>> frameworkResources =
- getConfiguredFrameworkResources();
-
- if (configuredProjectRes == null) {
- displayError("Missing project resources for current configuration.");
- return null;
- }
-
- if (frameworkResources == null) {
- displayError("Missing framework resources.");
- return null;
- }
-
- mResourceResolver = ResourceResolver.create(
- configuredProjectRes, frameworkResources,
- theme, isProjectTheme);
- }
-
- return mResourceResolver;
- }
-
- /** Returns a project callback, and optionally resets it */
- ProjectCallback getProjectCallback(boolean reset, LayoutLibrary layoutLibrary) {
- // Lazily create the project callback the first time we need it
- if (mProjectCallback == null) {
- ResourceManager resManager = ResourceManager.getInstance();
- IProject project = getProject();
- ProjectResources projectRes = resManager.getProjectResources(project);
- mProjectCallback = new ProjectCallback(layoutLibrary, projectRes, project,
- mCredential, this);
- } else if (reset) {
- // Also clears the set of missing/broken classes prior to rendering
- mProjectCallback.getMissingClasses().clear();
- mProjectCallback.getUninstantiatableClasses().clear();
- }
-
- return mProjectCallback;
- }
-
- /**
- * Returns the resource name of this layout, NOT including the @layout/ prefix
- *
- * @return the resource name of this layout, NOT including the @layout/ prefix
- */
- public String getLayoutResourceName() {
- return ResourceHelper.getLayoutName(mEditedFile);
- }
-
- /**
- * Cleans up when the rendering target is about to change
- * @param oldTarget the old rendering target.
- */
- private void preRenderingTargetChangeCleanUp(IAndroidTarget oldTarget) {
- // first clear the caches related to this file in the old target
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- AndroidTargetData data = currentSdk.getTargetData(oldTarget);
- if (data != null) {
- LayoutLibrary layoutLib = data.getLayoutLibrary();
-
- // layoutLib can never be null.
- layoutLib.clearCaches(mEditedFile.getProject());
- }
- }
-
- // Also remove the ProjectCallback as it caches custom views which must be reloaded
- // with the classloader of the new LayoutLib. We also have to clear it out
- // because it stores a reference to the layout library which could have changed.
- mProjectCallback = null;
-
- // FIXME: get rid of the current LayoutScene if any.
- }
-
- private class ReloadListener implements ILayoutReloadListener {
- /**
- * Called when the file changes triggered a redraw of the layout
- */
- @Override
- public void reloadLayout(final ChangeFlags flags, final boolean libraryChanged) {
- if (mConfigChooser.isDisposed()) {
- return;
- }
- Display display = mConfigChooser.getDisplay();
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- reloadLayoutSwt(flags, libraryChanged);
- }
- });
- }
-
- /** Reload layout. <b>Must be called on the SWT thread</b> */
- private void reloadLayoutSwt(ChangeFlags flags, boolean libraryChanged) {
- if (mConfigChooser.isDisposed()) {
- return;
- }
- assert mConfigChooser.getDisplay().getThread() == Thread.currentThread();
-
- boolean recompute = false;
- // we only care about the r class of the main project.
- if (flags.rClass && libraryChanged == false) {
- recompute = true;
- if (mEditedFile != null) {
- ResourceManager manager = ResourceManager.getInstance();
- ProjectResources projectRes = manager.getProjectResources(
- mEditedFile.getProject());
-
- if (projectRes != null) {
- projectRes.resetDynamicIds();
- }
- }
- }
-
- if (flags.localeList) {
- // the locale list *potentially* changed so we update the locale in the
- // config composite.
- // However there's no recompute, as it could not be needed
- // (for instance a new layout)
- // If a resource that's not a layout changed this will trigger a recompute anyway.
- mConfigChooser.updateLocales();
- }
-
- // if a resources was modified.
- if (flags.resources) {
- recompute = true;
-
- // TODO: differentiate between single and multi resource file changed, and whether
- // the resource change affects the cache.
-
- // force a reparse in case a value XML file changed.
- mConfiguredProjectRes = null;
- mResourceResolver = null;
-
- // clear the cache in the bridge in case a bitmap/9-patch changed.
- LayoutLibrary layoutLib = getReadyLayoutLib(true /*displayError*/);
- if (layoutLib != null) {
- layoutLib.clearCaches(mEditedFile.getProject());
- }
- }
-
- if (flags.code) {
- // only recompute if the custom view loader was used to load some code.
- if (mProjectCallback != null && mProjectCallback.isUsed()) {
- mProjectCallback = null;
- recompute = true;
- }
- }
-
- if (flags.manifest) {
- recompute |= computeSdkVersion();
- }
-
- if (recompute) {
- if (mEditorDelegate.isGraphicalEditorActive()) {
- recomputeLayout();
- } else {
- mNeedsRecompute = true;
- }
- }
- }
- }
-
- // ---- Error handling ----
-
- /**
- * Switches the sash to display the error label.
- *
- * @param errorFormat The new error to display if not null.
- * @param parameters String.format parameters for the error format.
- */
- private void displayError(String errorFormat, Object...parameters) {
- if (errorFormat != null) {
- mErrorLabel.setText(String.format(errorFormat, parameters));
- } else {
- mErrorLabel.setText("");
- }
- mSashError.setMaximizedControl(null);
- }
-
- /** Displays the canvas and hides the error label. */
- private void hideError() {
- mErrorLabel.setText("");
- mSashError.setMaximizedControl(mCanvasViewer.getControl());
- }
-
- /** Display the problem list encountered during a render */
- private void displayUserStackTrace(RenderLogger logger, boolean append) {
- List<Throwable> throwables = logger.getFirstTrace();
- if (throwables == null || throwables.isEmpty()) {
- return;
- }
-
- Throwable throwable = throwables.get(0);
-
- if (throwable instanceof RenderSecurityException) {
- addActionLink(mErrorLabel, ActionLinkStyleRange.LINK_DISABLE_SANDBOX,
- "\nTurn off custom view rendering sandbox\n");
-
- StringBuilder builder = new StringBuilder(200);
- String lastFailedPath = RenderSecurityManager.getLastFailedPath();
- if (lastFailedPath != null) {
- builder.append("Diagnostic info for ADT bug report:\n");
- builder.append("Failed path: ").append(lastFailedPath).append('\n');
- String tempDir = System.getProperty("java.io.tmpdir");
- builder.append("Normal temp dir: ").append(tempDir).append('\n');
- File normalized = new File(tempDir);
- builder.append("Normalized temp dir: ").append(normalized.getPath()).append('\n');
- try {
- builder.append("Canonical temp dir: ").append(normalized.getCanonicalPath())
- .append('\n');
- } catch (IOException e) {
- // ignore
- }
- builder.append("os.name: ").append(System.getProperty("os.name")).append('\n');
- builder.append("os.version: ").append(System.getProperty("os.version"));
- builder.append('\n');
- builder.append("java.runtime.version: ");
- builder.append(System.getProperty("java.runtime.version"));
- }
- if (throwable.getMessage().equals("Unable to create temporary file")) {
- String javaVersion = System.getProperty("java.version");
- if (javaVersion.startsWith("1.7.0_")) {
- int version = Integer
- .parseInt(javaVersion.substring(javaVersion.indexOf('_') + 1));
- if (version > 0 && version < 45) {
- builder.append('\n');
- builder.append("Tip: This may be caused by using an older version " +
- "of JDK 1.7.0; try using at least 1.7.0_45 (you are using " +
- javaVersion + ")");
- }
- }
- }
- if (builder.length() > 0) {
- addText(mErrorLabel, builder.toString());
- }
- }
-
- StackTraceElement[] frames = throwable.getStackTrace();
- int end = -1;
- boolean haveInterestingFrame = false;
- for (int i = 0; i < frames.length; i++) {
- StackTraceElement frame = frames[i];
- if (isInterestingFrame(frame)) {
- haveInterestingFrame = true;
- }
- String className = frame.getClassName();
- if (className.equals(
- "com.android.layoutlib.bridge.impl.RenderSessionImpl")) { //$NON-NLS-1$
- end = i;
- break;
- }
- }
-
- if (end == -1 || !haveInterestingFrame) {
- // Not a recognized stack trace range: just skip it
- return;
- }
-
- if (!append) {
- mErrorLabel.setText("\n"); //$NON-NLS-1$
- } else {
- addText(mErrorLabel, "\n\n"); //$NON-NLS-1$
- }
-
- addText(mErrorLabel, throwable.toString() + '\n');
- for (int i = 0; i < end; i++) {
- StackTraceElement frame = frames[i];
- String className = frame.getClassName();
- String methodName = frame.getMethodName();
- addText(mErrorLabel, " at " + className + '.' + methodName + '(');
- String fileName = frame.getFileName();
- if (fileName != null && !fileName.isEmpty()) {
- int lineNumber = frame.getLineNumber();
- String location = fileName + ':' + lineNumber;
- if (isInterestingFrame(frame)) {
- addActionLink(mErrorLabel, ActionLinkStyleRange.LINK_OPEN_LINE,
- location, className, methodName, fileName, lineNumber);
- } else {
- addText(mErrorLabel, location);
- }
- addText(mErrorLabel, ")\n"); //$NON-NLS-1$
- }
- }
- }
-
- private static boolean isInterestingFrame(StackTraceElement frame) {
- String className = frame.getClassName();
- return !(className.startsWith("android.") //$NON-NLS-1$
- || className.startsWith("com.android.") //$NON-NLS-1$
- || className.startsWith("java.") //$NON-NLS-1$
- || className.startsWith("javax.") //$NON-NLS-1$
- || className.startsWith("sun.")); //$NON-NLS-1$
- }
-
- /**
- * Switches the sash to display the error label to show a list of
- * missing classes and give options to create them.
- */
- private void displayFailingClasses(Set<String> missingClasses, Set<String> brokenClasses,
- boolean append) {
- if (missingClasses.size() == 0 && brokenClasses.size() == 0) {
- return;
- }
-
- if (!append) {
- mErrorLabel.setText(""); //$NON-NLS-1$
- } else {
- addText(mErrorLabel, "\n"); //$NON-NLS-1$
- }
-
- if (missingClasses.size() > 0) {
- addText(mErrorLabel, "The following classes could not be found:\n");
- for (String clazz : missingClasses) {
- addText(mErrorLabel, "- ");
- addText(mErrorLabel, clazz);
- addText(mErrorLabel, " (");
-
- IProject project = getProject();
- Collection<String> customViews = getCustomViewClassNames(project);
- addTypoSuggestions(clazz, customViews, false);
- addTypoSuggestions(clazz, customViews, true);
- addTypoSuggestions(clazz, getAndroidViewClassNames(project), false);
-
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_FIX_BUILD_PATH, "Fix Build Path", clazz);
- addText(mErrorLabel, ", ");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_EDIT_XML, "Edit XML", clazz);
- if (clazz.indexOf('.') != -1) {
- // Add "Create Class" link, but only for custom views
- addText(mErrorLabel, ", ");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_CREATE_CLASS, "Create Class", clazz);
- }
- addText(mErrorLabel, ")\n");
- }
- }
- if (brokenClasses.size() > 0) {
- addText(mErrorLabel, "The following classes could not be instantiated:\n");
-
- // Do we have a custom class (not an Android or add-ons class)
- boolean haveCustomClass = false;
-
- for (String clazz : brokenClasses) {
- addText(mErrorLabel, "- ");
- addText(mErrorLabel, clazz);
- addText(mErrorLabel, " (");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_OPEN_CLASS, "Open Class", clazz);
- addText(mErrorLabel, ", ");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_SHOW_LOG, "Show Error Log", clazz);
- addText(mErrorLabel, ")\n");
-
- if (!(clazz.startsWith("android.") || //$NON-NLS-1$
- clazz.startsWith("com.google."))) { //$NON-NLS-1$
- haveCustomClass = true;
- }
- }
-
- addText(mErrorLabel, "See the Error Log (Window > Show View) for more details.\n");
-
- if (haveCustomClass) {
- addBoldText(mErrorLabel, "Tip: Use View.isInEditMode() in your custom views "
- + "to skip code when shown in Eclipse");
- }
- }
-
- mSashError.setMaximizedControl(null);
- }
-
- private void addTypoSuggestions(String actual, Collection<String> views,
- boolean compareWithPackage) {
- if (views.size() == 0) {
- return;
- }
-
- // Look for typos and try to match with custom views and android views
- String actualBase = actual.substring(actual.lastIndexOf('.') + 1);
- int maxDistance = actualBase.length() >= 4 ? 2 : 1;
-
- if (views.size() > 0) {
- for (String suggested : views) {
- String suggestedBase = suggested.substring(suggested.lastIndexOf('.') + 1);
-
- String matchWith = compareWithPackage ? suggested : suggestedBase;
- if (Math.abs(actualBase.length() - matchWith.length()) > maxDistance) {
- // The string lengths differ more than the allowed edit distance;
- // no point in even attempting to compute the edit distance (requires
- // O(n*m) storage and O(n*m) speed, where n and m are the string lengths)
- continue;
- }
- if (LintUtils.editDistance(actualBase, matchWith) <= maxDistance) {
- // Suggest this class as a typo for the given class
- String labelClass = (suggestedBase.equals(actual) || actual.indexOf('.') != -1)
- ? suggested : suggestedBase;
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.LINK_CHANGE_CLASS_TO,
- String.format("Change to %1$s",
- // Only show full package name if class name
- // is the same
- labelClass),
- actual,
- viewNeedsPackage(suggested) ? suggested : suggestedBase);
- addText(mErrorLabel, ", ");
- }
- }
- }
- }
-
- private static Collection<String> getCustomViewClassNames(IProject project) {
- CustomViewFinder finder = CustomViewFinder.get(project);
- Collection<String> views = finder.getAllViews();
- if (views == null) {
- finder.refresh();
- views = finder.getAllViews();
- }
-
- return views;
- }
-
- private static Collection<String> getAndroidViewClassNames(IProject project) {
- Sdk currentSdk = Sdk.getCurrent();
- IAndroidTarget target = currentSdk.getTarget(project);
- if (target != null) {
- AndroidTargetData targetData = currentSdk.getTargetData(target);
- if (targetData != null) {
- LayoutDescriptors layoutDescriptors = targetData.getLayoutDescriptors();
- return layoutDescriptors.getAllViewClassNames();
- }
- }
-
- return Collections.emptyList();
- }
-
- /** Add a normal line of text to the styled text widget. */
- private void addText(StyledText styledText, String...string) {
- for (String s : string) {
- styledText.append(s);
- }
- }
-
- /** Display the problem list encountered during a render */
- private void displayLoggerProblems(IProject project, RenderLogger logger) {
- if (logger.hasProblems()) {
- mErrorLabel.setText("");
- // A common source of problems is attempting to open a layout when there are
- // compilation errors. In this case, may not have run (or may not be up to date)
- // so resources cannot be looked up etc. Explain this situation to the user.
-
- boolean hasAaptErrors = false;
- boolean hasJavaErrors = false;
- try {
- IMarker[] markers;
- markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
- if (markers.length > 0) {
- for (IMarker marker : markers) {
- String markerType = marker.getType();
- if (markerType.equals(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER)) {
- int severity = marker.getAttribute(IMarker.SEVERITY, -1);
- if (severity == IMarker.SEVERITY_ERROR) {
- hasJavaErrors = true;
- }
- } else if (markerType.equals(AdtConstants.MARKER_AAPT_COMPILE)) {
- int severity = marker.getAttribute(IMarker.SEVERITY, -1);
- if (severity == IMarker.SEVERITY_ERROR) {
- hasAaptErrors = true;
- }
- }
- }
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- if (logger.seenTagPrefix(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR)) {
- addBoldText(mErrorLabel,
- "Missing styles. Is the correct theme chosen for this layout?\n");
- addText(mErrorLabel,
- "Use the Theme combo box above the layout to choose a different layout, " +
- "or fix the theme style references.\n\n");
- }
-
- List<Throwable> trace = logger.getFirstTrace();
- if (trace != null
- && trace.toString().contains(
- "java.lang.IndexOutOfBoundsException: Index: 2, Size: 2") //$NON-NLS-1$
- && mConfigChooser.getConfiguration().getDensity() == Density.TV) {
- addBoldText(mErrorLabel,
- "It looks like you are using a render target where the layout library " +
- "does not support the tvdpi density.\n\n");
- addText(mErrorLabel, "Please try either updating to " +
- "the latest available version (using the SDK manager), or if no updated " +
- "version is available for this specific version of Android, try using " +
- "a more recent render target version.\n\n");
-
- }
-
- if (hasAaptErrors && logger.seenTagPrefix(LayoutLog.TAG_RESOURCES_PREFIX)) {
- // Text will automatically be wrapped by the error widget so no reason
- // to insert linebreaks in this error message:
- String message =
- "NOTE: This project contains resource errors, so aapt did not succeed, "
- + "which can cause rendering failures. "
- + "Fix resource problems first.\n\n";
- addBoldText(mErrorLabel, message);
- } else if (hasJavaErrors && mProjectCallback != null && mProjectCallback.isUsed()) {
- // Text will automatically be wrapped by the error widget so no reason
- // to insert linebreaks in this error message:
- String message =
- "NOTE: This project contains Java compilation errors, "
- + "which can cause rendering failures for custom views. "
- + "Fix compilation problems first.\n\n";
- addBoldText(mErrorLabel, message);
- }
-
- if (logger.seenTag(RenderLogger.TAG_MISSING_DIMENSION)) {
- List<UiElementNode> elements = UiDocumentNode.getAllElements(getModel());
- for (UiElementNode element : elements) {
- String width = element.getAttributeValue(ATTR_LAYOUT_WIDTH);
- if (width == null || width.length() == 0) {
- addSetAttributeLink(element, ATTR_LAYOUT_WIDTH);
- }
-
- String height = element.getAttributeValue(ATTR_LAYOUT_HEIGHT);
- if (height == null || height.length() == 0) {
- addSetAttributeLink(element, ATTR_LAYOUT_HEIGHT);
- }
- }
- }
-
- String problems = logger.getProblems(false /*includeFidelityWarnings*/);
- addText(mErrorLabel, problems);
-
- List<String> fidelityWarnings = logger.getFidelityWarnings();
- if (fidelityWarnings != null && fidelityWarnings.size() > 0) {
- addText(mErrorLabel,
- "The graphics preview in the layout editor may not be accurate:\n");
- for (String warning : fidelityWarnings) {
- addText(mErrorLabel, warning + ' ');
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.IGNORE_FIDELITY_WARNING,
- "(Ignore for this session)\n", warning);
- }
- }
-
- mSashError.setMaximizedControl(null);
- } else {
- mSashError.setMaximizedControl(mCanvasViewer.getControl());
- }
- }
-
- /** Appends an action link to set the given attribute on the given value */
- private void addSetAttributeLink(UiElementNode element, String attribute) {
- if (element.getXmlNode().getNodeName().equals(GRID_LAYOUT)) {
- // GridLayout does not require a layout_width or layout_height to be defined
- return;
- }
-
- String fill = VALUE_FILL_PARENT;
- // See whether we should offer match_parent instead of fill_parent
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(getProject());
- if (target.getVersion().getApiLevel() >= 8) {
- fill = VALUE_MATCH_PARENT;
- }
- }
-
- String id = element.getAttributeValue(ATTR_ID);
- if (id == null || id.length() == 0) {
- id = '<' + element.getXmlNode().getNodeName() + '>';
- } else {
- id = BaseLayoutRule.stripIdPrefix(id);
- }
-
- addText(mErrorLabel, String.format("\"%1$s\" does not set the required %2$s attribute:\n",
- id, attribute));
- addText(mErrorLabel, " (1) ");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.SET_ATTRIBUTE,
- String.format("Set to \"%1$s\"", VALUE_WRAP_CONTENT),
- element, attribute, VALUE_WRAP_CONTENT);
- addText(mErrorLabel, "\n (2) ");
- addActionLink(mErrorLabel,
- ActionLinkStyleRange.SET_ATTRIBUTE,
- String.format("Set to \"%1$s\"\n", fill),
- element, attribute, fill);
- }
-
- /** Appends the given text as a bold string in the given text widget */
- private void addBoldText(StyledText styledText, String text) {
- String s = styledText.getText();
- int start = (s == null ? 0 : s.length());
-
- styledText.append(text);
- StyleRange sr = new StyleRange();
- sr.start = start;
- sr.length = text.length();
- sr.fontStyle = SWT.BOLD;
- styledText.setStyleRange(sr);
- }
-
- /**
- * Add a URL-looking link to the styled text widget.
- * <p/>
- * A mouse-click listener is setup and it interprets the link based on the
- * action, corresponding to the value fields in {@link ActionLinkStyleRange}.
- */
- private void addActionLink(StyledText styledText, int action, String label,
- Object... data) {
- String s = styledText.getText();
- int start = (s == null ? 0 : s.length());
- styledText.append(label);
-
- StyleRange sr = new ActionLinkStyleRange(action, data);
- sr.start = start;
- sr.length = label.length();
- sr.fontStyle = SWT.NORMAL;
- sr.underlineStyle = SWT.UNDERLINE_LINK;
- sr.underline = true;
- styledText.setStyleRange(sr);
- }
-
- /**
- * Looks up the resource file corresponding to the given type
- *
- * @param type The type of resource to look up, such as {@link ResourceType#LAYOUT}
- * @param name The name of the resource (not including ".xml")
- * @param isFrameworkResource if true, the resource is a framework resource, otherwise
- * it's a project resource
- * @return the resource file defining the named resource, or null if not found
- */
- public IPath findResourceFile(ResourceType type, String name, boolean isFrameworkResource) {
- // FIXME: This code does not handle theme value resolution.
- // There is code to handle this, but it's in layoutlib; we should
- // expose that and use it here.
-
- Map<ResourceType, Map<String, ResourceValue>> map;
- map = isFrameworkResource ? mConfiguredFrameworkRes : mConfiguredProjectRes;
- if (map == null) {
- // Not yet configured
- return null;
- }
-
- Map<String, ResourceValue> layoutMap = map.get(type);
- if (layoutMap != null) {
- ResourceValue value = layoutMap.get(name);
- if (value != null) {
- String valueStr = value.getValue();
- if (valueStr.startsWith("?")) { //$NON-NLS-1$
- // FIXME: It's a reference. We should resolve this properly.
- return null;
- }
- return new Path(valueStr);
- }
- }
-
- return null;
- }
-
- /**
- * Looks up the path to the file corresponding to the given attribute value, such as
- * @layout/foo, which will return the foo.xml file in res/layout/. (The general format
- * of the resource url is {@literal @[<package_name>:]<resource_type>/<resource_name>}.
- *
- * @param url the attribute url
- * @return the path to the file defining this attribute, or null if not found
- */
- public IPath findResourceFile(String url) {
- if (!url.startsWith("@")) { //$NON-NLS-1$
- return null;
- }
- int typeEnd = url.indexOf('/', 1);
- if (typeEnd == -1) {
- return null;
- }
- int nameBegin = typeEnd + 1;
- int typeBegin = 1;
- int colon = url.lastIndexOf(':', typeEnd);
- boolean isFrameworkResource = false;
- if (colon != -1) {
- // The URL contains a package name.
- // While the url format technically allows other package names,
- // the platform apparently only supports @android for now (or if it does,
- // there are no usages in the current code base so this is not common).
- String packageName = url.substring(typeBegin, colon);
- if (ANDROID_PKG.equals(packageName)) {
- isFrameworkResource = true;
- }
-
- typeBegin = colon + 1;
- }
-
- String typeName = url.substring(typeBegin, typeEnd);
- ResourceType type = ResourceType.getEnum(typeName);
- if (type == null) {
- return null;
- }
-
- String name = url.substring(nameBegin);
- return findResourceFile(type, name, isFrameworkResource);
- }
-
- /**
- * Resolve the given @string reference into a literal String using the current project
- * configuration
- *
- * @param text the text resource reference to resolve
- * @return the resolved string, or null
- */
- public String findString(String text) {
- if (text.startsWith(STRING_PREFIX)) {
- return findString(text.substring(STRING_PREFIX.length()), false);
- } else if (text.startsWith(ANDROID_STRING_PREFIX)) {
- return findString(text.substring(ANDROID_STRING_PREFIX.length()), true);
- } else {
- return text;
- }
- }
-
- private String findString(String name, boolean isFrameworkResource) {
- Map<ResourceType, Map<String, ResourceValue>> map;
- map = isFrameworkResource ? mConfiguredFrameworkRes : mConfiguredProjectRes;
- if (map == null) {
- // Not yet configured
- return null;
- }
-
- Map<String, ResourceValue> layoutMap = map.get(ResourceType.STRING);
- if (layoutMap != null) {
- ResourceValue value = layoutMap.get(name);
- if (value != null) {
- // FIXME: This code does not handle theme value resolution.
- // There is code to handle this, but it's in layoutlib; we should
- // expose that and use it here.
- return value.getValue();
- }
- }
-
- return null;
- }
-
- /**
- * This StyleRange represents a clickable link in the render output, where various
- * actions can be taken such as creating a class, opening the project chooser to
- * adjust the build path, etc.
- */
- private class ActionLinkStyleRange extends StyleRange {
- /** Create a view class */
- private static final int LINK_CREATE_CLASS = 1;
- /** Edit the build path for the current project */
- private static final int LINK_FIX_BUILD_PATH = 2;
- /** Show the XML tab */
- private static final int LINK_EDIT_XML = 3;
- /** Open the given class */
- private static final int LINK_OPEN_CLASS = 4;
- /** Show the error log */
- private static final int LINK_SHOW_LOG = 5;
- /** Change the class reference to the given fully qualified name */
- private static final int LINK_CHANGE_CLASS_TO = 6;
- /** Ignore the given fidelity warning */
- private static final int IGNORE_FIDELITY_WARNING = 7;
- /** Set an attribute on the given XML element to a given value */
- private static final int SET_ATTRIBUTE = 8;
- /** Open the given file and line number */
- private static final int LINK_OPEN_LINE = 9;
- /** Disable sandbox */
- private static final int LINK_DISABLE_SANDBOX = 10;
-
- /** Client data: the contents depend on the specific action */
- private final Object[] mData;
- /** The action to be taken when the link is clicked */
- private final int mAction;
-
- private ActionLinkStyleRange(int action, Object... data) {
- super();
- mAction = action;
- mData = data;
- }
-
- /** Performs the click action */
- public void onClick() {
- switch (mAction) {
- case LINK_CREATE_CLASS:
- createNewClass((String) mData[0]);
- break;
- case LINK_EDIT_XML:
- mEditorDelegate.getEditor().setActivePage(AndroidXmlEditor.TEXT_EDITOR_ID);
- break;
- case LINK_FIX_BUILD_PATH:
- @SuppressWarnings("restriction")
- String id = BuildPathsPropertyPage.PROP_ID;
- PreferencesUtil.createPropertyDialogOn(
- AdtPlugin.getShell(),
- getProject(), id, null, null).open();
- break;
- case LINK_OPEN_CLASS:
- AdtPlugin.openJavaClass(getProject(), (String) mData[0]);
- break;
- case LINK_OPEN_LINE:
- boolean success = AdtPlugin.openStackTraceLine(
- (String) mData[0], // class
- (String) mData[1], // method
- (String) mData[2], // file
- (Integer) mData[3]); // line
- if (!success) {
- MessageDialog.openError(mErrorLabel.getShell(), "Not Found",
- String.format("Could not find %1$s.%2$s", mData[0], mData[1]));
- }
- break;
- case LINK_SHOW_LOG:
- IWorkbench workbench = PlatformUI.getWorkbench();
- IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
- try {
- IWorkbenchPage page = workbenchWindow.getActivePage();
- page.showView("org.eclipse.pde.runtime.LogView"); //$NON-NLS-1$
- } catch (PartInitException e) {
- AdtPlugin.log(e, null);
- }
- break;
- case LINK_CHANGE_CLASS_TO:
- // Change class reference of mData[0] to mData[1]
- // TODO: run under undo lock
- MultiTextEdit edits = new MultiTextEdit();
- ISourceViewer textViewer =
- mEditorDelegate.getEditor().getStructuredSourceViewer();
- IDocument document = textViewer.getDocument();
- String xml = document.get();
- int index = 0;
- // Replace <old with <new and </old with </new
- String prefix = "<"; //$NON-NLS-1$
- String find = prefix + mData[0];
- String replaceWith = prefix + mData[1];
- while (true) {
- index = xml.indexOf(find, index);
- if (index == -1) {
- break;
- }
- edits.addChild(new ReplaceEdit(index, find.length(), replaceWith));
- index += find.length();
- }
- index = 0;
- prefix = "</"; //$NON-NLS-1$
- find = prefix + mData[0];
- replaceWith = prefix + mData[1];
- while (true) {
- index = xml.indexOf(find, index);
- if (index == -1) {
- break;
- }
- edits.addChild(new ReplaceEdit(index, find.length(), replaceWith));
- index += find.length();
- }
- // Handle <view class="old">
- index = 0;
- prefix = "\""; //$NON-NLS-1$
- String suffix = "\""; //$NON-NLS-1$
- find = prefix + mData[0] + suffix;
- replaceWith = prefix + mData[1] + suffix;
- while (true) {
- index = xml.indexOf(find, index);
- if (index == -1) {
- break;
- }
- edits.addChild(new ReplaceEdit(index, find.length(), replaceWith));
- index += find.length();
- }
- try {
- edits.apply(document);
- } catch (MalformedTreeException e) {
- AdtPlugin.log(e, null);
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
- break;
- case IGNORE_FIDELITY_WARNING:
- RenderLogger.ignoreFidelityWarning((String) mData[0]);
- recomputeLayout();
- break;
- case SET_ATTRIBUTE: {
- final UiElementNode element = (UiElementNode) mData[0];
- final String attribute = (String) mData[1];
- final String value = (String) mData[2];
- mEditorDelegate.getEditor().wrapUndoEditXmlModel(
- String.format("Set \"%1$s\" to \"%2$s\"", attribute, value),
- new Runnable() {
- @Override
- public void run() {
- element.setAttributeValue(attribute, ANDROID_URI, value, true);
- element.commitDirtyAttributesToXml();
- }
- });
- break;
- }
- case LINK_DISABLE_SANDBOX: {
- RenderSecurityManager.sEnabled = false;
- recomputeLayout();
-
- MessageDialog.openInformation(AdtPlugin.getShell(),
- "Disabled Rendering Sandbox",
- "The custom view rendering sandbox was disabled for this session.\n\n" +
- "You can turn it off permanently by adding\n" +
- "-D" + ENABLED_PROPERTY + "=" + VALUE_FALSE + "\n" +
- "as a new line in eclipse.ini.");
-
- break;
- }
- default:
- assert false : mAction;
- break;
- }
- }
-
- @Override
- public boolean similarTo(StyleRange style) {
- // Prevent adjacent link ranges from getting merged
- return false;
- }
- }
-
- /**
- * Returns the error label for the graphical editor (which may not be visible
- * or showing errors)
- *
- * @return the error label, never null
- */
- StyledText getErrorLabel() {
- return mErrorLabel;
- }
-
- /**
- * Monitor clicks on the error label.
- * If the click happens on a style range created by
- * {@link GraphicalEditorPart#addClassLink(StyledText, String)}, we assume it's about
- * a missing class and we then proceed to display the standard Eclipse class creator wizard.
- */
- private class ErrorLabelListener extends MouseAdapter {
-
- @Override
- public void mouseUp(MouseEvent event) {
- super.mouseUp(event);
-
- if (event.widget != mErrorLabel) {
- return;
- }
-
- int offset = mErrorLabel.getCaretOffset();
-
- StyleRange r = null;
- StyleRange[] ranges = mErrorLabel.getStyleRanges();
- if (ranges != null && ranges.length > 0) {
- for (StyleRange sr : ranges) {
- if (sr.start <= offset && sr.start + sr.length > offset) {
- r = sr;
- break;
- }
- }
- }
-
- if (r instanceof ActionLinkStyleRange) {
- ActionLinkStyleRange range = (ActionLinkStyleRange) r;
- range.onClick();
- }
-
- LayoutCanvas canvas = getCanvasControl();
- canvas.updateMenuActionState();
- }
- }
-
- private void createNewClass(String fqcn) {
-
- int pos = fqcn.lastIndexOf('.');
- String packageName = pos < 0 ? "" : fqcn.substring(0, pos); //$NON-NLS-1$
- String className = pos <= 0 || pos >= fqcn.length() ? "" : fqcn.substring(pos + 1); //$NON-NLS-1$
-
- // create the wizard page for the class creation, and configure it
- NewClassWizardPage page = new NewClassWizardPage();
-
- // set the parent class
- page.setSuperClass(SdkConstants.CLASS_VIEW, true /* canBeModified */);
-
- // get the source folders as java elements.
- IPackageFragmentRoot[] roots = getPackageFragmentRoots(
- mEditorDelegate.getEditor().getProject(),
- false /*includeContainers*/, true /*skipGenFolder*/);
-
- IPackageFragmentRoot currentRoot = null;
- IPackageFragment currentFragment = null;
- int packageMatchCount = -1;
-
- for (IPackageFragmentRoot root : roots) {
- // Get the java element for the package.
- // This method is said to always return a IPackageFragment even if the
- // underlying folder doesn't exist...
- IPackageFragment fragment = root.getPackageFragment(packageName);
- if (fragment != null && fragment.exists()) {
- // we have a perfect match! we use it.
- currentRoot = root;
- currentFragment = fragment;
- packageMatchCount = -1;
- break;
- } else {
- // we don't have a match. we look for the fragment with the best match
- // (ie the closest parent package we can find)
- try {
- IJavaElement[] children;
- children = root.getChildren();
- for (IJavaElement child : children) {
- if (child instanceof IPackageFragment) {
- fragment = (IPackageFragment)child;
- if (packageName.startsWith(fragment.getElementName())) {
- // its a match. get the number of segments
- String[] segments = fragment.getElementName().split("\\."); //$NON-NLS-1$
- if (segments.length > packageMatchCount) {
- packageMatchCount = segments.length;
- currentFragment = fragment;
- currentRoot = root;
- }
- }
- }
- }
- } catch (JavaModelException e) {
- // Couldn't get the children: we just ignore this package root.
- }
- }
- }
-
- ArrayList<IPackageFragment> createdFragments = null;
-
- if (currentRoot != null) {
- // if we have a perfect match, we set it and we're done.
- if (packageMatchCount == -1) {
- page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/);
- page.setPackageFragment(currentFragment, true /* canBeModified */);
- } else {
- // we have a partial match.
- // create the package. We have to start with the first segment so that we
- // know what to delete in case of a cancel.
- try {
- createdFragments = new ArrayList<IPackageFragment>();
-
- int totalCount = packageName.split("\\.").length; //$NON-NLS-1$
- int count = 0;
- int index = -1;
- // skip the matching packages
- while (count < packageMatchCount) {
- index = packageName.indexOf('.', index+1);
- count++;
- }
-
- // create the rest of the segments, except for the last one as indexOf will
- // return -1;
- while (count < totalCount - 1) {
- index = packageName.indexOf('.', index+1);
- count++;
- createdFragments.add(currentRoot.createPackageFragment(
- packageName.substring(0, index),
- true /* force*/, new NullProgressMonitor()));
- }
-
- // create the last package
- createdFragments.add(currentRoot.createPackageFragment(
- packageName, true /* force*/, new NullProgressMonitor()));
-
- // set the root and fragment in the Wizard page
- page.setPackageFragmentRoot(currentRoot, true /* canBeModified*/);
- page.setPackageFragment(createdFragments.get(createdFragments.size()-1),
- true /* canBeModified */);
- } catch (JavaModelException e) {
- // If we can't create the packages, there's a problem.
- // We revert to the default package
- for (IPackageFragmentRoot root : roots) {
- // Get the java element for the package.
- // This method is said to always return a IPackageFragment even if the
- // underlying folder doesn't exist...
- IPackageFragment fragment = root.getPackageFragment(packageName);
- if (fragment != null && fragment.exists()) {
- page.setPackageFragmentRoot(root, true /* canBeModified*/);
- page.setPackageFragment(fragment, true /* canBeModified */);
- break;
- }
- }
- }
- }
- } else if (roots.length > 0) {
- // if we haven't found a valid fragment, we set the root to the first source folder.
- page.setPackageFragmentRoot(roots[0], true /* canBeModified*/);
- }
-
- // if we have a starting class name we use it
- if (className != null) {
- page.setTypeName(className, true /* canBeModified*/);
- }
-
- // create the action that will open it the wizard.
- OpenNewClassWizardAction action = new OpenNewClassWizardAction();
- action.setConfiguredWizardPage(page);
- action.run();
- IJavaElement element = action.getCreatedElement();
-
- if (element == null) {
- // lets delete the packages we created just for this.
- // we need to start with the leaf and go up
- if (createdFragments != null) {
- try {
- for (int i = createdFragments.size() - 1 ; i >= 0 ; i--) {
- createdFragments.get(i).delete(true /* force*/,
- new NullProgressMonitor());
- }
- } catch (JavaModelException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- /**
- * Computes and return the {@link IPackageFragmentRoot}s corresponding to the source
- * folders of the specified project.
- *
- * @param project the project
- * @param includeContainers True to include containers
- * @param skipGenFolder True to skip the "gen" folder
- * @return an array of IPackageFragmentRoot.
- */
- private IPackageFragmentRoot[] getPackageFragmentRoots(IProject project,
- boolean includeContainers, boolean skipGenFolder) {
- ArrayList<IPackageFragmentRoot> result = new ArrayList<IPackageFragmentRoot>();
- try {
- IJavaProject javaProject = JavaCore.create(project);
- IPackageFragmentRoot[] roots = javaProject.getPackageFragmentRoots();
- for (int i = 0; i < roots.length; i++) {
- if (skipGenFolder) {
- IResource resource = roots[i].getResource();
- if (resource != null && resource.getName().equals(FD_GEN_SOURCES)) {
- continue;
- }
- }
- IClasspathEntry entry = roots[i].getRawClasspathEntry();
- if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE ||
- (includeContainers &&
- entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER)) {
- result.add(roots[i]);
- }
- }
- } catch (JavaModelException e) {
- }
-
- return result.toArray(new IPackageFragmentRoot[result.size()]);
- }
-
- /**
- * Reopens this file as included within the given file (this assumes that the given
- * file has an include tag referencing this view, and the set of views that have this
- * property can be found using the {@link IncludeFinder}.
- *
- * @param includeWithin reference to a file to include as a surrounding context,
- * or null to show the file standalone
- */
- public void showIn(Reference includeWithin) {
- mIncludedWithin = includeWithin;
-
- if (includeWithin != null) {
- IFile file = includeWithin.getFile();
-
- // Update configuration
- if (file != null) {
- mConfigChooser.resetConfigFor(file);
- }
- }
- recomputeLayout();
- }
-
- /**
- * Return all resource names of a given type, either in the project or in the
- * framework.
- *
- * @param framework if true, return all the framework resource names, otherwise return
- * all the project resource names
- * @param type the type of resource to look up
- * @return a collection of resource names, never null but possibly empty
- */
- public Collection<String> getResourceNames(boolean framework, ResourceType type) {
- Map<ResourceType, Map<String, ResourceValue>> map =
- framework ? mConfiguredFrameworkRes : mConfiguredProjectRes;
- Map<String, ResourceValue> animations = map.get(type);
- if (animations != null) {
- return animations.keySet();
- } else {
- return Collections.emptyList();
- }
- }
-
- /**
- * Return this editor's current configuration
- *
- * @return the current configuration
- */
- public FolderConfiguration getConfiguration() {
- return mConfigChooser.getConfiguration().getFullConfig();
- }
-
- /**
- * Figures out the project's minSdkVersion and targetSdkVersion and return whether the values
- * have changed.
- */
- private boolean computeSdkVersion() {
- int oldMinSdkVersion = mMinSdkVersion;
- int oldTargetSdkVersion = mTargetSdkVersion;
-
- Pair<Integer, Integer> v = ManifestInfo.computeSdkVersions(mEditedFile.getProject());
- mMinSdkVersion = v.getFirst();
- mTargetSdkVersion = v.getSecond();
-
- return oldMinSdkVersion != mMinSdkVersion || oldTargetSdkVersion != mTargetSdkVersion;
- }
-
- /**
- * Returns the associated configuration chooser
- *
- * @return the configuration chooser
- */
- @NonNull
- public ConfigurationChooser getConfigurationChooser() {
- return mConfigChooser;
- }
-
- /**
- * Returns the associated layout actions bar
- *
- * @return the layout actions bar
- */
- @NonNull
- public LayoutActionBar getLayoutActionBar() {
- return mActionBar;
- }
-
- /**
- * Returns the target SDK version
- *
- * @return the target SDK version
- */
- public int getTargetSdkVersion() {
- return mTargetSdkVersion;
- }
-
- /**
- * Returns the minimum SDK version
- *
- * @return the minimum SDK version
- */
- public int getMinSdkVersion() {
- return mMinSdkVersion;
- }
-
- /** If the flyout hover is showing, dismiss it */
- public void dismissHoverPalette() {
- mPaletteComposite.dismissHover();
- }
-
- // ---- Implements IFlyoutListener ----
-
- @Override
- public void stateChanged(int oldState, int newState) {
- // Auto zoom the surface if you open or close flyout windows such as the palette
- // or the property/outline views
- if (newState == STATE_OPEN || newState == STATE_COLLAPSED && oldState == STATE_OPEN) {
- getCanvasControl().setFitScale(true /*onlyZoomOut*/, true /*allowZoomIn*/);
- }
-
- sDockingStateVersion++;
- mDockingStateVersion = sDockingStateVersion;
- }
-}