diff options
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.java | 1001 |
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; - } -} |