aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidOutlineConfiguration.java37
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidQuickOutlineConfiguration.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidXmlEditor.java15
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java27
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java90
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/XmlEditorMultiOutline.java221
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlDelegate.java16
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java12
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java156
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java7
11 files changed, 565 insertions, 68 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index e5e8229..f7fd525 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -622,7 +622,10 @@
<quickOutlineConfiguration
class="com.android.ide.eclipse.adt.internal.editors.AndroidQuickOutlineConfiguration"
- target="com.android.ide.eclipse.adt.internal.editors.CommonXmlEditor" />
+ target="org.eclipse.core.runtime.xml" />
+ <contentOutlineConfiguration
+ class="com.android.ide.eclipse.adt.internal.editors.AndroidOutlineConfiguration"
+ target="org.eclipse.core.runtime.xml" />
<provisionalConfiguration
type="org.eclipse.jface.text.quickassist.IQuickAssistProcessor"
class="com.android.ide.eclipse.adt.internal.editors.formatting.XmlQuickAssistManager"
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidOutlineConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidOutlineConfiguration.java
new file mode 100644
index 0000000..6061d92
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidOutlineConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors;
+
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.wst.xml.ui.views.contentoutline.XMLContentOutlineConfiguration;
+
+/**
+ * Custom version of {@link XMLContentOutlineConfiguration} which adds in icons and
+ * details such as id or name, to the labels.
+ */
+public class AndroidOutlineConfiguration extends XMLContentOutlineConfiguration {
+ /** Constructs a new {@link AndroidOutlineConfiguration} */
+ public AndroidOutlineConfiguration() {
+ }
+
+ @Override
+ public ILabelProvider getLabelProvider(TreeViewer viewer) {
+ return new OutlineLabelProvider();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidQuickOutlineConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidQuickOutlineConfiguration.java
index 7b8b2ac..0a8e9dc 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidQuickOutlineConfiguration.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidQuickOutlineConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,61 +16,20 @@
package com.android.ide.eclipse.adt.internal.editors;
-import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
-import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
-import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
-
import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.wst.xml.ui.internal.contentoutline.JFaceNodeLabelProvider;
import org.eclipse.wst.xml.ui.internal.quickoutline.XMLQuickOutlineConfiguration;
-import org.w3c.dom.Element;
/**
* Custom version of {@link XMLQuickOutlineConfiguration} which adds in icons and
* details such as id or name, to the labels.
*/
-@SuppressWarnings("restriction")
public class AndroidQuickOutlineConfiguration extends XMLQuickOutlineConfiguration {
+ /** Constructs a new {@link AndroidQuickOutlineConfiguration} */
public AndroidQuickOutlineConfiguration() {
}
@Override
public ILabelProvider getLabelProvider() {
- return new JFaceNodeLabelProvider() {
- @Override
- public Image getImage(Object element) {
- if (element instanceof Element) {
- Element e = (Element) element;
- String tagName = e.getTagName();
- IconFactory factory = IconFactory.getInstance();
- Image img = factory.getIcon(tagName);
- if (img != null) {
- return img;
- }
- }
- return super.getImage(element);
- }
-
- @Override
- public String getText(Object element) {
- String text = super.getText(element);
- if (element instanceof Element) {
- Element e = (Element) element;
- String id = e.getAttributeNS(ANDROID_URI, ATTR_ID);
- if (id == null || id.length() == 0) {
- id = e.getAttributeNS(ANDROID_URI, ATTR_NAME);
- }
- if (id == null || id.length() == 0) {
- id = e.getAttribute(ATTR_NAME);
- }
- if (id != null && id.length() > 0) {
- return text + ": " + id; //$NON-NLS-1$
- }
- }
- return text;
- }
- };
+ return new OutlineLabelProvider();
}
-
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidXmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidXmlEditor.java
index 7c57549..58e156e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidXmlEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidXmlEditor.java
@@ -76,6 +76,7 @@ import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.internal.browser.WorkbenchBrowserSupport;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.WorkbenchPart;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelStateListener;
@@ -273,6 +274,10 @@ public abstract class AndroidXmlEditor extends FormEditor implements IResourceCh
};
}
+ if (result == null && adapter == IContentOutlinePage.class) {
+ return getStructuredTextEditor().getAdapter(adapter);
+ }
+
return result;
}
@@ -416,7 +421,6 @@ public abstract class AndroidXmlEditor extends FormEditor implements IResourceCh
}
}
-
/**
* Notifies this multi-page editor that the page with the given id has been
* activated. This method is called when the user selects a different tab.
@@ -445,6 +449,15 @@ public abstract class AndroidXmlEditor extends FormEditor implements IResourceCh
}
/**
+ * Returns true if the active page is the editor page
+ *
+ * @return true if the active page is the editor page
+ */
+ public boolean isEditorPageActive() {
+ return getActivePage() == mTextPageIndex;
+ }
+
+ /**
* Notifies this listener that some resource changes
* are happening, or have already happened.
*
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
index ca13d38..22aa687 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
@@ -18,6 +18,7 @@
package com.android.ide.eclipse.adt.internal.editors;
import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.sdklib.SdkConstants;
@@ -181,10 +182,13 @@ public class IconFactory {
* in the editor's "icons" directory. If it doesn't exist, the
* fallback will be used instead.
* @param fallback the fallback icon name to use if the primary icon does
- * not exist.
- * @return the icon, which should not be disposed by the caller
+ * not exist, or null if the method should return null if the
+ * image does not exist
+ * @return the icon, which should not be disposed by the caller, or null
+ * if the image does not exist *and*
*/
- public Image getIcon(String osName, String fallback) {
+ @Nullable
+ public Image getIcon(@NonNull String osName, @Nullable String fallback) {
String key = osName;
Image icon = mIconMap.get(key);
if (icon == null && !mIconMap.containsKey(key)) {
@@ -200,21 +204,26 @@ public class IconFactory {
}
/**
- * Returns an icon of the given name, or if that image does not exist and icon
- * of the given fallback name.
+ * Returns an icon of the given name, or if that image does not exist and
+ * icon of the given fallback name.
*
* @param key the icon name
- * @param fallbackKey the fallback image to use if the primary key does not exist
- * @return the image descriptor
+ * @param fallbackKey the fallback image to use if the primary key does not
+ * exist
+ * @return the image descriptor, or null if the image does not exist and the
+ * fallbackKey is null
*/
- @NonNull
- public ImageDescriptor getImageDescriptor(@NonNull String key, @NonNull String fallbackKey) {
+ @Nullable
+ public ImageDescriptor getImageDescriptor(@NonNull String key, @Nullable String fallbackKey) {
ImageDescriptor id = mImageDescMap.get(key);
if (id == null && !mImageDescMap.containsKey(key)) {
id = AbstractUIPlugin.imageDescriptorFromPlugin(
AdtPlugin.PLUGIN_ID,
String.format("/icons/%1$s.png", key)); //$NON-NLS-1$
if (id == null) {
+ if (fallbackKey == null) {
+ return null;
+ }
id = getImageDescriptor(fallbackKey);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java
new file mode 100644
index 0000000..ea3f066
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/OutlineLabelProvider.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors;
+
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_SRC;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT;
+import static com.android.ide.common.layout.LayoutConstants.DRAWABLE_PREFIX;
+import static com.android.ide.common.layout.LayoutConstants.LAYOUT_PREFIX;
+
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.wst.xml.ui.internal.contentoutline.JFaceNodeLabelProvider;
+import org.w3c.dom.Element;
+
+/** Label provider for the XML outlines and quick outlines: Use our own icons,
+ * when available, and and include the most important attribute (id, name, or text) */
+@SuppressWarnings("restriction") // XML UI API
+class OutlineLabelProvider extends JFaceNodeLabelProvider {
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof Element) {
+ Element e = (Element) element;
+ String tagName = e.getTagName();
+ IconFactory factory = IconFactory.getInstance();
+ Image img = factory.getIcon(tagName, null);
+ if (img != null) {
+ return img;
+ }
+ }
+ return super.getImage(element);
+ }
+
+ @Override
+ public String getText(Object element) {
+ String text = super.getText(element);
+ if (element instanceof Element) {
+ Element e = (Element) element;
+ String id = e.getAttributeNS(ANDROID_URI, ATTR_ID);
+ if (id == null || id.length() == 0) {
+ id = e.getAttributeNS(ANDROID_URI, ATTR_NAME);
+ if (id == null || id.length() == 0) {
+ id = e.getAttribute(ATTR_NAME);
+ if (id == null || id.length() == 0) {
+ id = e.getAttributeNS(ANDROID_URI, ATTR_TEXT);
+ if (id != null && id.length() > 15) {
+ id = id.substring(0, 12) + "...";
+ }
+ if (id == null || id.length() == 0) {
+ id = e.getAttributeNS(ANDROID_URI, ATTR_SRC);
+ if (id != null && id.length() > 0) {
+ if (id.startsWith(DRAWABLE_PREFIX)) {
+ id = id.substring(DRAWABLE_PREFIX.length());
+ }
+ } else {
+ id = e.getAttribute(LayoutDescriptors.ATTR_LAYOUT);
+ if (id != null && id.length() > 0) {
+ if (id.startsWith(LAYOUT_PREFIX)) {
+ id = id.substring(LAYOUT_PREFIX.length());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (id != null && id.length() > 0) {
+ return text + ": " + id; //$NON-NLS-1$
+ }
+ }
+ return text;
+ }
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/XmlEditorMultiOutline.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/XmlEditorMultiOutline.java
new file mode 100644
index 0000000..4ccab2d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/XmlEditorMultiOutline.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.internal.editors;
+
+import com.android.ide.eclipse.adt.AdtPlugin;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.eclipse.ui.part.Page;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Outline used for XML editors that have multiple pages with separate outlines:
+ * switches between them
+ * <p>
+ * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=1917
+ * <p>
+ * Modeled after .org.eclipse.pde.internal.ui.editor.PDEMultiPageContentOutline
+ */
+public class XmlEditorMultiOutline extends Page implements IContentOutlinePage,
+ ISelectionChangedListener {
+ private boolean mDisposed;
+ private PageBook mPageBook;
+ private IContentOutlinePage mCurrentPage;
+ private IActionBars mActionBars;
+ private IContentOutlinePage mEmptyPage;
+ private List<ISelectionChangedListener> mListeners;
+ private ISelection mSelection;
+
+ public XmlEditorMultiOutline() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mPageBook;
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mPageBook = new PageBook(parent, SWT.NONE);
+ }
+
+ @Override
+ public void dispose() {
+ mDisposed = true;
+ mListeners = null;
+ if (mPageBook != null && !mPageBook.isDisposed()) {
+ mPageBook.dispose();
+ mPageBook = null;
+ }
+ if (mEmptyPage != null) {
+ mEmptyPage.dispose();
+ mEmptyPage = null;
+ }
+ }
+
+ public boolean isDisposed() {
+ return mDisposed;
+ }
+
+ @Override
+ public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager,
+ IStatusLineManager statusLineManager) {
+ }
+
+ @Override
+ public void setActionBars(IActionBars actionBars) {
+ mActionBars = actionBars;
+ if (mCurrentPage != null) {
+ setPageActive(mCurrentPage);
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ if (mCurrentPage != null) {
+ mCurrentPage.setFocus();
+ }
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (mListeners == null) {
+ mListeners = new ArrayList<ISelectionChangedListener>();
+ }
+ mListeners.add(listener);
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ mListeners.remove(listener);
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return mSelection;
+ }
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ setSelection(event.getSelection());
+ }
+
+ public void setPageActive(IContentOutlinePage page) {
+ if (page == null) {
+ if (mEmptyPage == null) {
+ mEmptyPage = new EmptyPage();
+ }
+ page = mEmptyPage;
+ }
+ if (mCurrentPage != null) {
+ mCurrentPage.removeSelectionChangedListener(this);
+ }
+ page.addSelectionChangedListener(this);
+ mCurrentPage = page;
+ // Still initializing?
+ if (mPageBook == null) {
+ return;
+ }
+ Control control = page.getControl();
+ if (control == null || control.isDisposed()) {
+ if (page instanceof IPageBookViewPage) {
+ try {
+ ((IPageBookViewPage) page).init(getSite());
+ } catch (PartInitException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+ page.createControl(mPageBook);
+ page.setActionBars(mActionBars);
+ control = page.getControl();
+ }
+ mPageBook.showPage(control);
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ mSelection = selection;
+ if (mListeners != null) {
+ SelectionChangedEvent e = new SelectionChangedEvent(this, selection);
+ for (int i = 0; i < mListeners.size(); i++) {
+ mListeners.get(i).selectionChanged(e);
+ }
+ }
+ }
+
+ private static class EmptyPage implements IContentOutlinePage {
+ private Composite mControl;
+
+ private EmptyPage() {
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ mControl = new Composite(parent, SWT.NULL);
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public Control getControl() {
+ return mControl;
+ }
+
+ @Override
+ public void setActionBars(IActionBars actionBars) {
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return StructuredSelection.EMPTY;
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ }
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlDelegate.java
index a664800..08bdcf9 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlDelegate.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlDelegate.java
@@ -29,8 +29,10 @@ import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.part.EditorActionBarContributor;
import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.part.MultiPageEditorPart;
import org.w3c.dom.Document;
/**
@@ -201,4 +203,18 @@ public abstract class CommonXmlDelegate {
public boolean delegateSupportsFormatOnGuiEdit() {
return false;
}
+
+ /**
+ * Called after the editor's active page has been set.
+ *
+ * @param superReturned the return value from
+ * {@link MultiPageEditorPart#setActivePage(int)}
+ * @param pageIndex the index of the page to be activated; the index must be
+ * valid
+ * @return the page, or null
+ * @see MultiPageEditorPart#setActivePage(int)
+ */
+ public IFormPage delegatePostSetActivePage(IFormPage superReturned, String pageIndex) {
+ return superReturned;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
index 96ce82b..68c7807 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
@@ -47,6 +47,7 @@ import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IShowEditorInput;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.ide.IDE;
import org.w3c.dom.Document;
@@ -372,6 +373,17 @@ public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInpu
}
}
+ @Override
+ public IFormPage setActivePage(String pageId) {
+ IFormPage page = super.setActivePage(pageId);
+
+ if (mDelegate != null) {
+ return mDelegate.delegatePostSetActivePage(page, pageId);
+ }
+
+ return page;
+ }
+
/* Implements showEditorInput(...) in IShowEditorInput */
@Override
public void showEditorInput(IEditorInput editorInput) {
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
index 9c7189b..df39a3d 100644
--- 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
@@ -16,11 +16,13 @@
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.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;
@@ -51,19 +53,25 @@ 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.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPartListener;
+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;
@@ -103,8 +111,24 @@ public class LayoutEditorDelegate extends CommonXmlDelegate
private GraphicalEditorPart mGraphicalEditor;
private int mGraphicalEditorIndex;
+
/** Implementation of the {@link IContentOutlinePage} for this editor */
- private IContentOutlinePage mOutline;
+ 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;
@@ -402,16 +426,60 @@ public class LayoutEditorDelegate extends CommonXmlDelegate
*/
@Override
public Object delegateGetAdapter(Class<?> adapter) {
- // For the outline, force it to come from the Graphical Editor.
- // This fixes the case where a layout file is opened in XML view first and the outline
- // gets stuck in the XML outline.
- if (IContentOutlinePage.class == adapter && mGraphicalEditor != null) {
+ 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;
+ }
+ }
+ }
- if (mOutline == null && mGraphicalEditor != null) {
- mOutline = new OutlinePage(mGraphicalEditor);
+ // Use a multiplexing outline: workaround for
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=1917
+ if (mMultiOutline == null || mMultiOutline.isDisposed()) {
+ mMultiOutline = new XmlEditorMultiOutline();
+ updateOutline(getEditor().getActivePageInstance());
}
- return mOutline;
+ return mMultiOutline;
}
if (IPropertySheetPage.class == adapter && mGraphicalEditor != null) {
@@ -426,6 +494,60 @@ public class LayoutEditorDelegate extends CommonXmlDelegate
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() &&
@@ -454,6 +576,24 @@ public class LayoutEditorDelegate extends CommonXmlDelegate
}
}
+ @Override
+ public void delegatePostPageChange(int newPageIndex) {
+ super.delegatePostPageChange(newPageIndex);
+
+ 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
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
index e45803a..8913850 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java
@@ -91,7 +91,6 @@ import org.eclipse.ui.actions.ContributionItemFactory;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.w3c.dom.Node;
import java.util.HashSet;
@@ -305,10 +304,8 @@ public class LayoutCanvas extends Canvas {
// --- setup outline ---
// Get the outline associated with this editor, if any and of the right type.
- Object outline = editorDelegate == null ? null :
- editorDelegate.delegateGetAdapter(IContentOutlinePage.class);
- if (outline instanceof OutlinePage) {
- mOutlinePage = (OutlinePage) outline;
+ if (editorDelegate != null) {
+ mOutlinePage = editorDelegate.getGraphicalOutline();
}
}