aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.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/LayoutEditorDelegate.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java1001
1 files changed, 0 insertions, 1001 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java
deleted file mode 100644
index 1015d7d86..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java
+++ /dev/null
@@ -1,1001 +0,0 @@
-/*
- * Copyright (C) 2007 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;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.annotations.VisibleForTesting.Visibility;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.XmlEditorMultiOutline;
-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.descriptors.DocumentDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.IUnknownDescriptorProvider;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.CustomViewDescriptorService;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutActionBar;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.OutlinePage;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager;
-import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
-import com.android.ide.eclipse.adt.internal.editors.layout.properties.PropertySheetPage;
-import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
-import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient;
-import com.android.ide.eclipse.adt.internal.lint.EclipseLintRunner;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.ResourceFolderType;
-import com.android.sdklib.IAndroidTarget;
-import com.android.tools.lint.client.api.IssueRegistry;
-
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.jobs.IJobChangeEvent;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.core.runtime.jobs.JobChangeAdapter;
-import org.eclipse.jface.text.source.ISourceViewer;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ISelectionChangedListener;
-import org.eclipse.jface.viewers.SelectionChangedEvent;
-import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.ISelectionListener;
-import org.eclipse.ui.ISelectionService;
-import org.eclipse.ui.IShowEditorInput;
-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.forms.editor.IFormPage;
-import org.eclipse.ui.part.FileEditorInput;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
-import org.eclipse.ui.views.properties.IPropertySheetPage;
-import org.eclipse.wst.sse.ui.StructuredTextEditor;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Multi-page form editor for /res/layout XML files.
- */
-public class LayoutEditorDelegate extends CommonXmlDelegate
- implements IShowEditorInput, CommonXmlDelegate.IActionContributorDelegate {
-
- /** The prefix for layout folders that are not the default layout folder */
- private static final String LAYOUT_FOLDER_PREFIX = "layout-"; //$NON-NLS-1$
-
- public static class Creator implements IDelegateCreator {
- @Override
- @SuppressWarnings("unchecked")
- public LayoutEditorDelegate createForFile(
- @NonNull CommonXmlEditor delegator,
- @Nullable ResourceFolderType type) {
- if (ResourceFolderType.LAYOUT == type) {
- return new LayoutEditorDelegate(delegator);
- }
-
- return null;
- }
- }
-
- /**
- * Old standalone-editor ID.
- * Use {@link CommonXmlEditor#ID} instead.
- */
- public static final String LEGACY_EDITOR_ID =
- AdtConstants.EDITORS_NAMESPACE + ".layout.LayoutEditor"; //$NON-NLS-1$
-
- /** Root node of the UI element hierarchy */
- private UiDocumentNode mUiDocRootNode;
-
- private GraphicalEditorPart mGraphicalEditor;
- private int mGraphicalEditorIndex;
-
- /** Implementation of the {@link IContentOutlinePage} for this editor */
- private OutlinePage mLayoutOutline;
-
- /** The XML editor outline */
- private IContentOutlinePage mEditorOutline;
-
- /** Multiplexing outline, used for multi-page editors that have their own outline */
- private XmlEditorMultiOutline mMultiOutline;
-
- /**
- * Temporary flag set by the editor caret listener which is used to cause
- * the next getAdapter(IContentOutlinePage.class) call to return the editor
- * outline rather than the multi-outline. See the {@link #delegateGetAdapter}
- * method for details.
- */
- private boolean mCheckOutlineAdapter;
-
- /** Custom implementation of {@link IPropertySheetPage} for this editor */
- private IPropertySheetPage mPropertyPage;
-
- private final HashMap<String, ElementDescriptor> mUnknownDescriptorMap =
- new HashMap<String, ElementDescriptor>();
-
- private EclipseLintClient mClient;
-
- /**
- * Flag indicating if the replacement file is due to a config change.
- * If false, it means the new file is due to an "open action" from the user.
- */
- private boolean mNewFileOnConfigChange = false;
-
- /**
- * Checks whether an editor part is an instance of {@link CommonXmlEditor}
- * with an associated {@link LayoutEditorDelegate} delegate.
- *
- * @param editorPart An editor part. Can be null.
- * @return The {@link LayoutEditorDelegate} delegate associated with the editor or null.
- */
- public static @Nullable LayoutEditorDelegate fromEditor(@Nullable IEditorPart editorPart) {
- if (editorPart instanceof CommonXmlEditor) {
- CommonXmlDelegate delegate = ((CommonXmlEditor) editorPart).getDelegate();
- if (delegate instanceof LayoutEditorDelegate) {
- return ((LayoutEditorDelegate) delegate);
- }
- } else if (editorPart instanceof GraphicalEditorPart) {
- GraphicalEditorPart part = (GraphicalEditorPart) editorPart;
- return part.getEditorDelegate();
- }
- return null;
- }
-
- /**
- * Creates the form editor for resources XML files.
- */
- @VisibleForTesting(visibility=Visibility.PRIVATE)
- protected LayoutEditorDelegate(CommonXmlEditor editor) {
- super(editor, new LayoutContentAssist());
- // Note that LayoutEditor has its own listeners and does not
- // need to call editor.addDefaultTargetListener().
- }
-
- /**
- * Returns the {@link RulesEngine} associated with this editor
- *
- * @return the {@link RulesEngine} associated with this editor.
- */
- public RulesEngine getRulesEngine() {
- return mGraphicalEditor.getRulesEngine();
- }
-
- /**
- * Returns the {@link GraphicalEditorPart} associated with this editor
- *
- * @return the {@link GraphicalEditorPart} associated with this editor
- */
- public GraphicalEditorPart getGraphicalEditor() {
- return mGraphicalEditor;
- }
-
- /**
- * @return The root node of the UI element hierarchy
- */
- @Override
- public UiDocumentNode getUiRootNode() {
- return mUiDocRootNode;
- }
-
- public void setNewFileOnConfigChange(boolean state) {
- mNewFileOnConfigChange = state;
- }
-
- // ---- Base Class Overrides ----
-
- @Override
- public void dispose() {
- super.dispose();
- if (mGraphicalEditor != null) {
- mGraphicalEditor.dispose();
- mGraphicalEditor = null;
- }
- }
-
- /**
- * Save the XML.
- * <p/>
- * Clients must NOT call this directly. Instead they should always
- * call {@link CommonXmlEditor#doSave(IProgressMonitor)} so that th
- * editor super class can commit the data properly.
- * <p/>
- * Here we just need to tell the graphical editor that the model has
- * been saved.
- */
- @Override
- public void delegateDoSave(IProgressMonitor monitor) {
- super.delegateDoSave(monitor);
- if (mGraphicalEditor != null) {
- mGraphicalEditor.doSave(monitor);
- }
- }
-
- /**
- * Create the various form pages.
- */
- @Override
- public void delegateCreateFormPages() {
- try {
- // get the file being edited so that it can be passed to the layout editor.
- IFile editedFile = null;
- IEditorInput input = getEditor().getEditorInput();
- if (input instanceof FileEditorInput) {
- FileEditorInput fileInput = (FileEditorInput)input;
- editedFile = fileInput.getFile();
- if (!editedFile.isAccessible()) {
- return;
- }
- } else {
- AdtPlugin.log(IStatus.ERROR,
- "Input is not of type FileEditorInput: %1$s", //$NON-NLS-1$
- input.toString());
- }
-
- // It is possible that the Layout Editor already exits if a different version
- // of the same layout is being opened (either through "open" action from
- // the user, or through a configuration change in the configuration selector.)
- if (mGraphicalEditor == null) {
-
- // Instantiate GLE v2
- mGraphicalEditor = new GraphicalEditorPart(this);
-
- mGraphicalEditorIndex = getEditor().addPage(mGraphicalEditor,
- getEditor().getEditorInput());
- getEditor().setPageText(mGraphicalEditorIndex, mGraphicalEditor.getTitle());
-
- mGraphicalEditor.openFile(editedFile);
- } else {
- if (mNewFileOnConfigChange) {
- mGraphicalEditor.changeFileOnNewConfig(editedFile);
- mNewFileOnConfigChange = false;
- } else {
- mGraphicalEditor.replaceFile(editedFile);
- }
- }
- } catch (PartInitException e) {
- AdtPlugin.log(e, "Error creating nested page"); //$NON-NLS-1$
- }
- }
-
- @Override
- public void delegatePostCreatePages() {
- // Optional: set the default page. Eventually a default page might be
- // restored by selectDefaultPage() later based on the last page used by the user.
- // For example, to make the last page the default one (rather than the first page),
- // uncomment this line:
- // setActivePage(getPageCount() - 1);
- }
-
- /* (non-java doc)
- * Change the tab/title name to include the name of the layout.
- */
- @Override
- public void delegateSetInput(IEditorInput input) {
- handleNewInput(input);
- }
-
- /*
- * (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#setInputWithNotify(org.eclipse.ui.IEditorInput)
- */
- public void delegateSetInputWithNotify(IEditorInput input) {
- handleNewInput(input);
- }
-
- /**
- * Called to replace the current {@link IEditorInput} with another one.
- * <p/>
- * This is used when {@link LayoutEditorMatchingStrategy} returned
- * <code>true</code> which means we're opening a different configuration of
- * the same layout.
- */
- @Override
- public void showEditorInput(IEditorInput editorInput) {
- if (getEditor().getEditorInput().equals(editorInput)) {
- return;
- }
-
- // Save the current editor input. This must be called on the editor itself
- // since it's the base editor that commits pending changes.
- getEditor().doSave(new NullProgressMonitor());
-
- // Get the current page
- int currentPage = getEditor().getActivePage();
-
- // Remove the pages, except for the graphical editor, which will be dynamically adapted
- // to the new model.
- // page after the graphical editor:
- int count = getEditor().getPageCount();
- for (int i = count - 1 ; i > mGraphicalEditorIndex ; i--) {
- getEditor().removePage(i);
- }
- // Pages before the graphical editor
- for (int i = mGraphicalEditorIndex - 1 ; i >= 0 ; i--) {
- getEditor().removePage(i);
- }
-
- // Set the current input. We're in the delegate, the input must
- // be set into the actual editor instance.
- getEditor().setInputWithNotify(editorInput);
-
- // Re-create or reload the pages with the default page shown as the previous active page.
- getEditor().createAndroidPages();
- getEditor().selectDefaultPage(Integer.toString(currentPage));
-
- // When changing an input file of an the editor, the titlebar is not refreshed to
- // show the new path/to/file being edited. So we force a refresh
- getEditor().firePropertyChange(IWorkbenchPart.PROP_TITLE);
- }
-
- /** Performs a complete refresh of the XML model */
- public void refreshXmlModel() {
- Document xmlDoc = mUiDocRootNode.getXmlDocument();
-
- delegateInitUiRootNode(true /*force*/);
- mUiDocRootNode.loadFromXmlNode(xmlDoc);
-
- // Update the model first, since it is used by the viewers.
- // No need to call AndroidXmlEditor.xmlModelChanged(xmlDoc) since it's
- // a no-op. Instead call onXmlModelChanged on the graphical editor.
-
- if (mGraphicalEditor != null) {
- mGraphicalEditor.onXmlModelChanged();
- }
- }
-
- /**
- * Processes the new XML Model, which XML root node is given.
- *
- * @param xml_doc The XML document, if available, or null if none exists.
- */
- @Override
- public void delegateXmlModelChanged(Document xml_doc) {
- // init the ui root on demand
- delegateInitUiRootNode(false /*force*/);
-
- mUiDocRootNode.loadFromXmlNode(xml_doc);
-
- // Update the model first, since it is used by the viewers.
- // No need to call AndroidXmlEditor.xmlModelChanged(xmlDoc) since it's
- // a no-op. Instead call onXmlModelChanged on the graphical editor.
-
- if (mGraphicalEditor != null) {
- mGraphicalEditor.onXmlModelChanged();
- }
- }
-
- /**
- * Tells the graphical editor to recompute its layout.
- */
- public void recomputeLayout() {
- mGraphicalEditor.recomputeLayout();
- }
-
- /**
- * Does this editor participate in the "format GUI editor changes" option?
- *
- * @return true since this editor supports automatically formatting XML
- * affected by GUI changes
- */
- @Override
- public boolean delegateSupportsFormatOnGuiEdit() {
- return true;
- }
-
- /**
- * Returns one of the issues for the given node (there could be more than one)
- *
- * @param node the node to look up lint issues for
- * @return the marker for one of the issues found for the given node
- */
- @Nullable
- public IMarker getIssueForNode(@Nullable UiViewElementNode node) {
- if (node == null) {
- return null;
- }
-
- if (mClient != null) {
- return mClient.getIssueForNode(node);
- }
-
- return null;
- }
-
- /**
- * Returns a collection of nodes that have one or more lint warnings
- * associated with them (retrievable via
- * {@link #getIssueForNode(UiViewElementNode)})
- *
- * @return a collection of nodes, which should <b>not</b> be modified by the
- * caller
- */
- @Nullable
- public Collection<Node> getLintNodes() {
- if (mClient != null) {
- return mClient.getIssueNodes();
- }
-
- return null;
- }
-
- @Override
- public Job delegateRunLint() {
- // We want to customize the {@link EclipseLintClient} created to run this
- // single file lint, in particular such that we can set the mode which collects
- // nodes on that lint job, such that we can quickly look up error nodes
- //Job job = super.delegateRunLint();
-
- Job job = null;
- IFile file = getEditor().getInputFile();
- if (file != null) {
- IssueRegistry registry = EclipseLintClient.getRegistry();
- List<IFile> resources = Collections.singletonList(file);
- mClient = new EclipseLintClient(registry,
- resources, getEditor().getStructuredDocument(), false /*fatal*/);
-
- mClient.setCollectNodes(true);
-
- job = EclipseLintRunner.startLint(mClient, resources, file,
- false /*show*/);
- }
-
- if (job != null) {
- GraphicalEditorPart graphicalEditor = getGraphicalEditor();
- if (graphicalEditor != null) {
- job.addJobChangeListener(new LintJobListener(graphicalEditor));
- }
- }
- return job;
- }
-
- private class LintJobListener extends JobChangeAdapter implements Runnable {
- private final GraphicalEditorPart mEditor;
- private final LayoutCanvas mCanvas;
-
- LintJobListener(GraphicalEditorPart editor) {
- mEditor = editor;
- mCanvas = editor.getCanvasControl();
- }
-
- @Override
- public void done(IJobChangeEvent event) {
- LayoutActionBar bar = mEditor.getLayoutActionBar();
- if (!bar.isDisposed()) {
- bar.updateErrorIndicator();
- }
-
- // Redraw
- if (!mCanvas.isDisposed()) {
- mCanvas.getDisplay().asyncExec(this);
- }
- }
-
- @Override
- public void run() {
- if (!mCanvas.isDisposed()) {
- mCanvas.redraw();
-
- OutlinePage outlinePage = mCanvas.getOutlinePage();
- if (outlinePage != null) {
- outlinePage.refreshIcons();
- }
- }
- }
- }
-
- /**
- * Returns the custom IContentOutlinePage or IPropertySheetPage when asked for it.
- */
- @Override
- public Object delegateGetAdapter(Class<?> adapter) {
- if (adapter == IContentOutlinePage.class) {
- // Somebody has requested the outline. Eclipse can only have a single outline page,
- // even for a multi-part editor:
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=1917
- // To work around this we use PDE's workaround of having a single multiplexing
- // outline which switches its contents between the outline pages we register
- // for it, and then on page switch we notify it to update itself.
-
- // There is one complication: The XML editor outline listens for the editor
- // selection and uses this to automatically expand its tree children and show
- // the current node containing the caret as selected. Unfortunately, this
- // listener code contains this:
- //
- // /* Bug 136310, unless this page is that part's
- // * IContentOutlinePage, ignore the selection change */
- // if (part.getAdapter(IContentOutlinePage.class) == this) {
- //
- // This means that when we return the multiplexing outline from this getAdapter
- // method, the outline no longer updates to track the selection.
- // To work around this, we use the following hack^H^H^H^H technique:
- // - Add a selection listener *before* requesting the editor outline, such
- // that the selection listener is told about the impending selection event
- // right before the editor outline hears about it. Set the flag
- // mCheckOutlineAdapter to true. (We also only set it if the editor view
- // itself is active.)
- // - In this getAdapter method, when somebody requests the IContentOutline.class,
- // see if mCheckOutlineAdapter to see if this request is *likely* coming
- // from the XML editor outline. If so, make sure it is by actually looking
- // at the signature of the caller. If it's the editor outline, then return
- // the editor outline instance itself rather than the multiplexing outline.
- if (mCheckOutlineAdapter && mEditorOutline != null) {
- mCheckOutlineAdapter = false;
- // Make *sure* this is really the editor outline calling in case
- // future versions of Eclipse changes the sequencing or dispatch of selection
- // events:
- StackTraceElement[] frames = new Throwable().fillInStackTrace().getStackTrace();
- if (frames.length > 2) {
- StackTraceElement frame = frames[2];
- if (frame.getClassName().equals(
- "org.eclipse.wst.sse.ui.internal.contentoutline." + //$NON-NLS-1$
- "ConfigurableContentOutlinePage$PostSelectionServiceListener")) { //$NON-NLS-1$
- return mEditorOutline;
- }
- }
- }
-
- // Use a multiplexing outline: workaround for
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=1917
- if (mMultiOutline == null || mMultiOutline.isDisposed()) {
- mMultiOutline = new XmlEditorMultiOutline();
- mMultiOutline.addSelectionChangedListener(new ISelectionChangedListener() {
- @Override
- public void selectionChanged(SelectionChangedEvent event) {
- ISelection selection = event.getSelection();
- getEditor().getSite().getSelectionProvider().setSelection(selection);
- if (getEditor().getIgnoreXmlUpdate()) {
- return;
- }
- SelectionManager manager =
- mGraphicalEditor.getCanvasControl().getSelectionManager();
- manager.setSelection(selection);
- }
- });
- updateOutline(getEditor().getActivePageInstance());
- }
-
- return mMultiOutline;
- }
-
- if (IPropertySheetPage.class == adapter && mGraphicalEditor != null) {
- if (mPropertyPage == null) {
- mPropertyPage = new PropertySheetPage(mGraphicalEditor);
- }
-
- return mPropertyPage;
- }
-
- // return default
- return super.delegateGetAdapter(adapter);
- }
-
- /**
- * Update the contents of the outline to show either the XML editor outline
- * or the layout editor graphical outline depending on which tab is visible
- */
- private void updateOutline(IFormPage page) {
- if (mMultiOutline == null) {
- return;
- }
-
- IContentOutlinePage outline;
- CommonXmlEditor editor = getEditor();
- if (!editor.isEditorPageActive()) {
- outline = getGraphicalOutline();
- } else {
- // Use plain XML editor outline instead
- if (mEditorOutline == null) {
- StructuredTextEditor structuredTextEditor = editor.getStructuredTextEditor();
- if (structuredTextEditor != null) {
- IWorkbenchWindow window = editor.getSite().getWorkbenchWindow();
- ISelectionService service = window.getSelectionService();
- service.addPostSelectionListener(new ISelectionListener() {
- @Override
- public void selectionChanged(IWorkbenchPart part, ISelection selection) {
- if (getEditor().isEditorPageActive()) {
- mCheckOutlineAdapter = true;
- }
- }
- });
-
- mEditorOutline = (IContentOutlinePage) structuredTextEditor.getAdapter(
- IContentOutlinePage.class);
- }
- }
-
- outline = mEditorOutline;
- }
-
- mMultiOutline.setPageActive(outline);
- }
-
- /**
- * Returns the graphical outline associated with the layout editor
- *
- * @return the outline page, never null
- */
- @NonNull
- public OutlinePage getGraphicalOutline() {
- if (mLayoutOutline == null) {
- mLayoutOutline = new OutlinePage(mGraphicalEditor);
- }
-
- return mLayoutOutline;
- }
-
- @Override
- public void delegatePageChange(int newPageIndex) {
- if (getEditor().getCurrentPage() == getEditor().getTextPageIndex() &&
- newPageIndex == mGraphicalEditorIndex) {
- // You're switching from the XML editor to the WYSIWYG editor;
- // look at the caret position and figure out which node it corresponds to
- // (if any) and if found, select the corresponding visual element.
- ISourceViewer textViewer = getEditor().getStructuredSourceViewer();
- int caretOffset = textViewer.getTextWidget().getCaretOffset();
- if (caretOffset >= 0) {
- Node node = DomUtilities.getNode(textViewer.getDocument(), caretOffset);
- if (node != null && mGraphicalEditor != null) {
- mGraphicalEditor.select(node);
- }
- }
- }
-
- super.delegatePageChange(newPageIndex);
-
- if (mGraphicalEditor != null) {
- if (newPageIndex == mGraphicalEditorIndex) {
- mGraphicalEditor.activated();
- } else {
- mGraphicalEditor.deactivated();
- }
- }
- }
-
- @Override
- public int delegateGetPersistenceCategory() {
- return AndroidXmlEditor.CATEGORY_LAYOUT;
- }
-
- @Override
- public void delegatePostPageChange(int newPageIndex) {
- super.delegatePostPageChange(newPageIndex);
-
- if (mGraphicalEditor != null) {
- LayoutCanvas canvas = mGraphicalEditor.getCanvasControl();
- if (canvas != null) {
- IActionBars bars = getEditor().getEditorSite().getActionBars();
- if (bars != null) {
- canvas.updateGlobalActions(bars);
- }
- }
- }
-
- IFormPage page = getEditor().getActivePageInstance();
- updateOutline(page);
- }
-
- @Override
- public IFormPage delegatePostSetActivePage(IFormPage superReturned, String pageIndex) {
- IFormPage page = superReturned;
- if (page != null) {
- updateOutline(page);
- }
-
- return page;
- }
-
- // ----- IActionContributorDelegate methods ----
-
- @Override
- public void setActiveEditor(IEditorPart part, IActionBars bars) {
- if (mGraphicalEditor != null) {
- LayoutCanvas canvas = mGraphicalEditor.getCanvasControl();
- if (canvas != null) {
- canvas.updateGlobalActions(bars);
- }
- }
- }
-
-
- @Override
- public void delegateActivated() {
- if (mGraphicalEditor != null) {
- if (getEditor().getActivePage() == mGraphicalEditorIndex) {
- mGraphicalEditor.activated();
- } else {
- mGraphicalEditor.deactivated();
- }
- }
- }
-
- @Override
- public void delegateDeactivated() {
- if (mGraphicalEditor != null && getEditor().getActivePage() == mGraphicalEditorIndex) {
- mGraphicalEditor.deactivated();
- }
- }
-
- @Override
- public String delegateGetPartName() {
- IEditorInput editorInput = getEditor().getEditorInput();
- if (!AdtPrefs.getPrefs().isSharedLayoutEditor()
- && editorInput instanceof IFileEditorInput) {
- IFileEditorInput fileInput = (IFileEditorInput) editorInput;
- IFile file = fileInput.getFile();
- IContainer parent = file.getParent();
- if (parent != null) {
- String parentName = parent.getName();
- if (parentName.startsWith(LAYOUT_FOLDER_PREFIX)) {
- parentName = parentName.substring(LAYOUT_FOLDER_PREFIX.length());
- return parentName + File.separatorChar + file.getName();
- }
- }
- }
-
- return super.delegateGetPartName();
- }
-
- // ---- Local Methods ----
-
- /**
- * Returns true if the Graphics editor page is visible. This <b>must</b> be
- * called from the UI thread.
- */
- public boolean isGraphicalEditorActive() {
- IWorkbenchPartSite workbenchSite = getEditor().getSite();
- IWorkbenchPage workbenchPage = workbenchSite.getPage();
-
- // check if the editor is visible in the workbench page
- if (workbenchPage.isPartVisible(getEditor())
- && workbenchPage.getActiveEditor() == getEditor()) {
- // and then if the page of the editor is visible (not to be confused with
- // the workbench page)
- return mGraphicalEditorIndex == getEditor().getActivePage();
- }
-
- return false;
- }
-
- @Override
- public void delegateInitUiRootNode(boolean force) {
- // The root UI node is always created, even if there's no corresponding XML node.
- if (mUiDocRootNode == null || force) {
- // get the target data from the opened file (and its project)
- AndroidTargetData data = getEditor().getTargetData();
-
- Document doc = null;
- if (mUiDocRootNode != null) {
- doc = mUiDocRootNode.getXmlDocument();
- }
-
- DocumentDescriptor desc;
- if (data == null) {
- desc = new DocumentDescriptor("temp", null /*children*/);
- } else {
- desc = data.getLayoutDescriptors().getDescriptor();
- }
-
- // get the descriptors from the data.
- mUiDocRootNode = (UiDocumentNode) desc.createUiNode();
- super.setUiRootNode(mUiDocRootNode);
- mUiDocRootNode.setEditor(getEditor());
-
- mUiDocRootNode.setUnknownDescriptorProvider(new IUnknownDescriptorProvider() {
- @Override
- public ElementDescriptor getDescriptor(String xmlLocalName) {
- ElementDescriptor unknown = mUnknownDescriptorMap.get(xmlLocalName);
- if (unknown == null) {
- unknown = createUnknownDescriptor(xmlLocalName);
- mUnknownDescriptorMap.put(xmlLocalName, unknown);
- }
-
- return unknown;
- }
- });
-
- onDescriptorsChanged(doc);
- }
- }
-
- /**
- * Creates a new {@link ViewElementDescriptor} for an unknown XML local name
- * (i.e. one that was not mapped by the current descriptors).
- * <p/>
- * Since we deal with layouts, we returns either a descriptor for a custom view
- * or one for the base View.
- *
- * @param xmlLocalName The XML local name to match.
- * @return A non-null {@link ViewElementDescriptor}.
- */
- private ViewElementDescriptor createUnknownDescriptor(String xmlLocalName) {
- ViewElementDescriptor desc = null;
- IEditorInput editorInput = getEditor().getEditorInput();
- if (editorInput instanceof IFileEditorInput) {
- IFileEditorInput fileInput = (IFileEditorInput)editorInput;
- IProject project = fileInput.getFile().getProject();
-
- // Check if we can find a custom view specific to this project.
- // This only works if there's an actual matching custom class in the project.
- if (xmlLocalName.indexOf('.') != -1) {
- desc = CustomViewDescriptorService.getInstance().getDescriptor(project,
- xmlLocalName);
- }
-
- if (desc == null) {
- // If we didn't find a custom view, create a synthetic one using the
- // the base View descriptor as a model.
- // This is a layout after all, so every XML node should represent
- // a view.
-
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(project);
- if (target != null) {
- AndroidTargetData data = currentSdk.getTargetData(target);
- if (data != null) {
- // data can be null when the target is still loading
- ViewElementDescriptor viewDesc =
- data.getLayoutDescriptors().getBaseViewDescriptor();
-
- desc = new ViewElementDescriptor(
- xmlLocalName, // xml local name
- xmlLocalName, // ui_name
- xmlLocalName, // canonical class name
- null, // tooltip
- null, // sdk_url
- viewDesc.getAttributes(),
- viewDesc.getLayoutAttributes(),
- null, // children
- false /* mandatory */);
- desc.setSuperClass(viewDesc);
- }
- }
- }
- }
- }
-
- if (desc == null) {
- // We can only arrive here if the SDK's android target has not finished
- // loading. Just create a dummy descriptor with no attributes to be able
- // to continue.
- desc = new ViewElementDescriptor(xmlLocalName, xmlLocalName);
- }
- return desc;
- }
-
- private void onDescriptorsChanged(Document document) {
-
- mUnknownDescriptorMap.clear();
-
- if (document != null) {
- mUiDocRootNode.loadFromXmlNode(document);
- } else {
- mUiDocRootNode.reloadFromXmlNode(mUiDocRootNode.getXmlDocument());
- }
-
- if (mGraphicalEditor != null) {
- mGraphicalEditor.onTargetChange();
- mGraphicalEditor.reloadPalette();
- mGraphicalEditor.getCanvasControl().syncPreviewMode();
- }
- }
-
- /**
- * Handles a new input, and update the part name.
- * @param input the new input.
- */
- private void handleNewInput(IEditorInput input) {
- if (input instanceof FileEditorInput) {
- FileEditorInput fileInput = (FileEditorInput) input;
- IFile file = fileInput.getFile();
- getEditor().setPartName(String.format("%1$s", file.getName()));
- }
- }
-
- /**
- * Helper method that returns a {@link ViewElementDescriptor} for the requested FQCN.
- * Will return null if we can't find that FQCN or we lack the editor/data/descriptors info.
- */
- public ViewElementDescriptor getFqcnViewDescriptor(String fqcn) {
- ViewElementDescriptor desc = null;
-
- AndroidTargetData data = getEditor().getTargetData();
- if (data != null) {
- LayoutDescriptors layoutDesc = data.getLayoutDescriptors();
- if (layoutDesc != null) {
- DocumentDescriptor docDesc = layoutDesc.getDescriptor();
- if (docDesc != null) {
- desc = internalFindFqcnViewDescriptor(fqcn, docDesc.getChildren(), null);
- }
- }
- }
-
- if (desc == null) {
- // We failed to find a descriptor for the given FQCN.
- // Let's consider custom classes and create one as needed.
- desc = createUnknownDescriptor(fqcn);
- }
-
- return desc;
- }
-
- /**
- * Internal helper to recursively search for a {@link ViewElementDescriptor} that matches
- * the requested FQCN.
- *
- * @param fqcn The target View FQCN to find.
- * @param descriptors A list of children descriptors to iterate through.
- * @param visited A set we use to remember which descriptors have already been visited,
- * necessary since the view descriptor hierarchy is cyclic.
- * @return Either a matching {@link ViewElementDescriptor} or null.
- */
- private ViewElementDescriptor internalFindFqcnViewDescriptor(String fqcn,
- ElementDescriptor[] descriptors,
- Set<ElementDescriptor> visited) {
- if (visited == null) {
- visited = new HashSet<ElementDescriptor>();
- }
-
- if (descriptors != null) {
- for (ElementDescriptor desc : descriptors) {
- if (visited.add(desc)) {
- // Set.add() returns true if this a new element that was added to the set.
- // That means we haven't visited this descriptor yet.
- // We want a ViewElementDescriptor with a matching FQCN.
- if (desc instanceof ViewElementDescriptor &&
- fqcn.equals(((ViewElementDescriptor) desc).getFullClassName())) {
- return (ViewElementDescriptor) desc;
- }
-
- // Visit its children
- ViewElementDescriptor vd =
- internalFindFqcnViewDescriptor(fqcn, desc.getChildren(), visited);
- if (vd != null) {
- return vd;
- }
- }
- }
- }
-
- return null;
- }
-}