aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-04-16 13:52:02 -0700
committerTor Norbye <tnorbye@google.com>2012-04-19 14:07:57 -0700
commit5cae1eabc82d4fcd106897abb9acbd482ad2f849 (patch)
treefa6fa5ee6b661eedba52bcee188f79d02b6f28b8 /eclipse
parent1f59a8c5333ad020b391dd9d6d065a7ec51164d1 (diff)
downloadsdk-5cae1eabc82d4fcd106897abb9acbd482ad2f849.zip
sdk-5cae1eabc82d4fcd106897abb9acbd482ad2f849.tar.gz
sdk-5cae1eabc82d4fcd106897abb9acbd482ad2f849.tar.bz2
Improved layout window management
This changeset improves the way the layout editor handles windows. In particular, it attempts to make the property sheet and the outline more visible. Specifically: * It adds the WindowBuilder docking support, which offers several new features: (1) You can collapse and expand the palette and structure views. If you hover over a collapsed palette (for example) it temporarily opens, and when you drag from it over to the canvas it collapses again. (2) The initial size is pixel based rather than percentage based, so the default palette size is more reasonable on large displays (it used to always take 20%, which was fine on a small screen but a waste on larger screens). (3) You can drag & drop to reconfigure the layout a bit. (This is fairly limited though; in particular, you cannot drag these views out of the editor area and mix them with Eclipse views.) * When the property sheet view is not shown anywhere else, it is shown as part of the outline instead (sharing the vertical space). This works better for the new property sheet implementation since it works better as a vertical window than a horizontal window. * When the outline is not shown anywhere else, it is shown in a new composite window *inside* the editor area. This mode is also entered when you temporarily maximize the layout editor window. * The layout canvas is auto-fit-zoomed when you enter and exit maximized mode, as well as when you open or close docked windows within the editor. The goal is for these changes to offer a good layout editing experience with the outline views and property sheets *without* using a new perspective for layout editing. Note that this is not identical to what WindowBuilder does; they always embed both the palette and the structure views within the editor area, which means the structure view is typically redundant with the outline view on the right unless you maximize the view. With the approach above hopefully we'll avoid that case and you'll always see the views without redundancy (and therefore with more available space for the layouts). Change-Id: I0d338b2781b9732e992f088fcc4e1ba46ff0954f
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/dictionary.txt1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/components_view.pngbin0 -> 340 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/editor_palette.pngbin430 -> 0 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/palette.pngbin0 -> 804 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/properties_view.pngbin0 -> 454 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java233
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutCanvas.java28
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutWindowCoordinator.java318
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java198
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java39
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertyFactory.java17
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertySheetPage.java53
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/DecorComposite.java89
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/IDecorContent.java62
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java16
17 files changed, 842 insertions, 216 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index c4d9746..f0432c6 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -95,6 +95,7 @@ equidistant
exec
fallback
flux
+flyout
foo
foreach
fqcn
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/components_view.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/components_view.png
new file mode 100644
index 0000000..9f9755f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/components_view.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/editor_palette.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/editor_palette.png
deleted file mode 100644
index c682f57..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/icons/editor_palette.png
+++ /dev/null
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/palette.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/palette.png
new file mode 100644
index 0000000..fd7ca1c
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/palette.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/properties_view.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/properties_view.png
new file mode 100644
index 0000000..8df5d2d
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/properties_view.png
Binary files differ
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 5f2b79b..9e821ad 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
@@ -158,6 +158,9 @@ public class LayoutEditorDelegate extends CommonXmlDelegate
if (delegate instanceof LayoutEditorDelegate) {
return ((LayoutEditorDelegate) delegate);
}
+ } else if (editorPart instanceof GraphicalEditorPart) {
+ GraphicalEditorPart part = (GraphicalEditorPart) editorPart;
+ return part.getEditorDelegate();
}
return null;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
index 1f4729c..d8a45b6 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GestureManager.java
@@ -581,6 +581,7 @@ public class GestureManager {
@Override
public void dragEnter(DropTargetEvent event) {
mCanvas.showInvisibleViews(true);
+ mCanvas.getEditorDelegate().getGraphicalEditor().dismissHoverPalette();
if (mCurrentGesture == null) {
Gesture newGesture = mZombieGesture;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index b43cff9..06cce40 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -30,7 +30,12 @@ import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor.viewNeedsPackage;
import static com.android.sdklib.SdkConstants.FD_GEN_SOURCES;
+import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.DOCK_EAST;
+import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.DOCK_WEST;
+import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.STATE_COLLAPSED;
+import static org.eclipse.wb.core.controls.flyout.IFlyoutPreferences.STATE_OPEN;
+import com.android.annotations.NonNull;
import com.android.ide.common.api.Rect;
import com.android.ide.common.layout.BaseLayoutRule;
import com.android.ide.common.rendering.LayoutLibrary;
@@ -61,9 +66,10 @@ import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configu
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.LayoutCreatorDialog;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.PaletteControl.PalettePage;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine;
+import com.android.ide.eclipse.adt.internal.editors.layout.properties.PropertyFactory;
import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
-import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.lint.EclipseLintClient;
@@ -106,11 +112,14 @@ import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.preferences.BuildPathsPropertyPage;
import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction;
import org.eclipse.jdt.ui.wizards.NewClassWizardPage;
+import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
@@ -122,10 +131,13 @@ import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
@@ -134,6 +146,7 @@ import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
@@ -141,8 +154,12 @@ import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.FileEditorInput;
-import org.eclipse.ui.part.IPage;
+import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.part.PageBookView;
+import org.eclipse.wb.core.controls.flyout.FlyoutControlComposite;
+import org.eclipse.wb.core.controls.flyout.IFlyoutListener;
+import org.eclipse.wb.core.controls.flyout.PluginFlyoutPreferences;
+import org.eclipse.wb.internal.core.editor.structure.PageSiteComposite;
import org.w3c.dom.Node;
import java.io.File;
@@ -173,7 +190,7 @@ import java.util.Set;
* @since GLE2
*/
public class GraphicalEditorPart extends EditorPart
- implements IPageImageProvider, INullSelectionListener {
+ implements IPageImageProvider, INullSelectionListener, IFlyoutListener {
/*
* Useful notes:
@@ -215,9 +232,6 @@ public class GraphicalEditorPart extends EditorPart
/** The configuration composite at the top of the layout editor. */
private ConfigurationComposite mConfigComposite;
- /** The sash that splits the palette from the canvas. */
- private SashForm mSashPalette;
-
/** The sash that splits the palette from the error view.
* The error view is shown only when needed. */
private SashForm mSashError;
@@ -251,6 +265,10 @@ public class GraphicalEditorPart extends EditorPart
private int mMinSdkVersion;
private int mTargetSdkVersion;
private LayoutActionBar mActionBar;
+ private OutlinePage mOutlinePage;
+ private FlyoutControlComposite mStructureFlyout;
+ private FlyoutControlComposite mPaletteComposite;
+ private PropertyFactory mPropertyFactory;
/**
* Flags which tracks whether this editor is currently active which is set whenever
@@ -334,15 +352,37 @@ public class GraphicalEditorPart extends EditorPart
mConfigComposite = new ConfigurationComposite(mConfigListener, parent,
SWT.BORDER, initialState);
-
- mSashPalette = new SashForm(parent, SWT.HORIZONTAL);
- mSashPalette.setLayoutData(new GridData(GridData.FILL_BOTH));
-
- DecorComposite paletteDecor = new DecorComposite(mSashPalette, SWT.BORDER);
- paletteDecor.setContent(new PaletteControl.PaletteDecor(this));
- mPalette = (PaletteControl) paletteDecor.getContentControl();
-
- Composite layoutBarAndCanvas = new Composite(mSashPalette, SWT.NONE);
+ PluginFlyoutPreferences preferences =
+ new PluginFlyoutPreferences(AdtPlugin.getDefault().getPreferenceStore(),
+ "design.palette"); //$NON-NLS-1$
+ preferences.initializeDefaults(DOCK_WEST, STATE_OPEN, 200);
+ mPaletteComposite = new FlyoutControlComposite(parent, SWT.NONE, preferences);
+ mPaletteComposite.setTitleText("Palette");
+ mPaletteComposite.setMinWidth(100);
+ Composite paletteParent = mPaletteComposite.getFlyoutParent();
+ Composite editorParent = mPaletteComposite.getClientParent();
+ mPaletteComposite.setListener(this);
+
+ mPaletteComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ PageSiteComposite paletteComposite = new PageSiteComposite(paletteParent, SWT.BORDER);
+ paletteComposite.setTitleText("Palette");
+ paletteComposite.setTitleImage(IconFactory.getInstance().getIcon("palette"));
+ PalettePage decor = new PalettePage(this);
+ paletteComposite.setPage(decor);
+ mPalette = (PaletteControl) decor.getControl();
+ decor.createToolbarItems(paletteComposite.getToolBar());
+
+ // Create the shared structure+editor area
+ preferences = new PluginFlyoutPreferences(AdtPlugin.getDefault().getPreferenceStore(),
+ "design.structure"); //$NON-NLS-1$
+ preferences.initializeDefaults(DOCK_EAST, STATE_OPEN, 300);
+ mStructureFlyout = new FlyoutControlComposite(editorParent, SWT.NONE, preferences);
+ mStructureFlyout.setTitleText("Structure");
+ mStructureFlyout.setMinWidth(150);
+ mStructureFlyout.setListener(this);
+
+ Composite layoutBarAndCanvas = new Composite(mStructureFlyout.getClientParent(), SWT.NONE);
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.horizontalSpacing = 0;
gridLayout.verticalSpacing = 0;
@@ -368,15 +408,156 @@ public class GraphicalEditorPart extends EditorPart
mErrorLabel.setForeground(d.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
mErrorLabel.addMouseListener(new ErrorLabelListener());
- mSashPalette.setWeights(new int[] { 20, 80 });
mSashError.setWeights(new int[] { 80, 20 });
mSashError.setMaximizedControl(mCanvasViewer.getControl());
+ // Create the structure views. We really should do this *lazily*, but that
+ // seems to cause a bug: property sheet won't update. Track this down later.
+ createStructureViews(mStructureFlyout.getFlyoutParent(), false);
+ showStructureViews(false, false, false);
+
// Initialize the state
reloadPalette();
- getSite().setSelectionProvider(mCanvasViewer);
- getSite().getPage().addSelectionListener(this);
+ IWorkbenchPartSite site = getSite();
+ site.setSelectionProvider(mCanvasViewer);
+ site.getPage().addSelectionListener(this);
+ }
+
+ private void createStructureViews(Composite parent, boolean createPropertySheet) {
+ mOutlinePage = new OutlinePage(this);
+ mOutlinePage.setShowPropertySheet(createPropertySheet);
+ mOutlinePage.setShowHeader(true);
+
+ IPageSite pageSite = new IPageSite() {
+
+ @Override
+ public IWorkbenchPage getPage() {
+ return getSite().getPage();
+ }
+
+ @Override
+ public ISelectionProvider getSelectionProvider() {
+ return getSite().getSelectionProvider();
+ }
+
+ @Override
+ public Shell getShell() {
+ return getSite().getShell();
+ }
+
+ @Override
+ public IWorkbenchWindow getWorkbenchWindow() {
+ return getSite().getWorkbenchWindow();
+ }
+
+ @Override
+ public void setSelectionProvider(ISelectionProvider provider) {
+ getSite().setSelectionProvider(provider);
+ }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ return getSite().getAdapter(adapter);
+ }
+
+ @Override
+ public Object getService(Class api) {
+ return getSite().getService(api);
+ }
+
+ @Override
+ public boolean hasService(Class api) {
+ return getSite().hasService(api);
+ }
+
+ @Override
+ public void registerContextMenu(String menuId, MenuManager menuManager,
+ ISelectionProvider selectionProvider) {
+ }
+
+ @Override
+ public IActionBars getActionBars() {
+ return null;
+ }
+ };
+ mOutlinePage.init(pageSite);
+ mOutlinePage.createControl(parent);
+ mOutlinePage.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ getCanvasControl().getSelectionManager().setSelection(event.getSelection());
+ }
+ });
+ }
+
+ /** Shows the embedded (within the layout editor) outline and or properties */
+ void showStructureViews(final boolean showOutline, final boolean showProperties,
+ final boolean updateLayout) {
+ Display display = mConfigComposite.getDisplay();
+ if (display.getThread() != Thread.currentThread()) {
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!mConfigComposite.isDisposed()) {
+ showStructureViews(showOutline, showProperties, updateLayout);
+ }
+ }
+
+ });
+ return;
+ }
+
+ boolean show = showOutline || showProperties;
+
+ Control[] children = mStructureFlyout.getFlyoutParent().getChildren();
+ if (children.length == 0) {
+ if (show) {
+ createStructureViews(mStructureFlyout.getFlyoutParent(), showProperties);
+ }
+ return;
+ }
+
+ mOutlinePage.setShowPropertySheet(showProperties);
+
+ Control control = children[0];
+ if (show != control.getVisible()) {
+ control.setVisible(show);
+ mOutlinePage.setActive(show); // disable/re-enable listeners etc
+ if (show) {
+ ISelection selection = getCanvasControl().getSelectionManager().getSelection();
+ mOutlinePage.selectionChanged(getEditorDelegate().getEditor(), selection);
+ }
+ if (updateLayout) {
+ mStructureFlyout.layout();
+ }
+ // TODO: *dispose* the non-showing widgets to save memory?
+ }
+ }
+
+ /**
+ * Returns the property factory associated with this editor
+ *
+ * @return the factory
+ */
+ @NonNull
+ public PropertyFactory getPropertyFactory() {
+ if (mPropertyFactory == null) {
+ mPropertyFactory = new PropertyFactory(this);
+ }
+
+ return mPropertyFactory;
+ }
+
+ /**
+ * Invoked by {@link LayoutCanvas} to set the model (a.k.a. the root view info).
+ *
+ * @param rootViewInfo The root of the view info hierarchy. Can be null.
+ */
+ public void setModel(CanvasViewInfo rootViewInfo) {
+ if (mOutlinePage != null) {
+ mOutlinePage.setModel(rootViewInfo);
+ }
}
/**
@@ -393,7 +574,7 @@ public class GraphicalEditorPart extends EditorPart
if (delegate == null) {
if (part instanceof PageBookView) {
PageBookView pbv = (PageBookView) part;
- IPage currentPage = pbv.getCurrentPage();
+ org.eclipse.ui.part.IPage currentPage = pbv.getCurrentPage();
if (currentPage instanceof OutlinePage) {
LayoutCanvas canvas = getCanvasControl();
if (canvas != null && canvas.getOutlinePage() != currentPage) {
@@ -2521,4 +2702,18 @@ public class GraphicalEditorPart extends EditorPart
public int getMinSdkVersion() {
return mMinSdkVersion;
}
+
+ /** If the flyout hover is showing, dismiss it */
+ public void dismissHoverPalette() {
+ mPaletteComposite.dismissHover();
+ }
+
+ @Override
+ public void stateChanged(int oldState, int newState) {
+ // Auto zoom the surface if you open or close flyout windows such as the palette
+ // or the property/outline views
+ if (newState == STATE_OPEN || newState == STATE_COLLAPSED && oldState == STATE_OPEN) {
+ getCanvasControl().setFitScale(true /*onlyZoomOut*/);
+ }
+ }
}
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 8913850..1354ebe 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
@@ -281,8 +281,12 @@ public class LayoutCanvas extends Canvas {
@Override
public void controlResized(ControlEvent e) {
super.controlResized(e);
+
mHScale.setClientSize(getClientArea().width);
mVScale.setClientSize(getClientArea().height);
+
+ // Update the zoom level in the canvas when you toggle the zoom
+ getDisplay().asyncExec(mZoomCheck);
}
});
@@ -309,7 +313,28 @@ public class LayoutCanvas extends Canvas {
}
}
- public void handleKeyPressed(KeyEvent e) {
+ private Runnable mZoomCheck = new Runnable() {
+ private Boolean mWasZoomed;
+
+ @Override
+ public void run() {
+ if (isDisposed()) {
+ return;
+ }
+
+ IEditorPart editor = getEditorDelegate().getEditor();
+ IWorkbenchPage page = editor.getSite().getPage();
+ Boolean zoomed = page.isPageZoomed();
+ if (mWasZoomed != zoomed) {
+ if (mWasZoomed != null) {
+ setFitScale(true /*onlyZoomOut*/);
+ }
+ mWasZoomed = zoomed;
+ }
+ }
+ };
+
+ void handleKeyPressed(KeyEvent e) {
// Set up backspace as an alias for the delete action within the canvas.
// On most Macs there is no delete key - though there IS a key labeled
// "Delete" and it sends a backspace key code! In short, for Macs we should
@@ -565,6 +590,7 @@ public class LayoutCanvas extends Canvas {
Image image = mImageOverlay.setImage(session.getImage(), session.isAlphaChannelImage());
mOutlinePage.setModel(mViewHierarchy.getRoot());
+ mEditorDelegate.getGraphicalEditor().setModel(mViewHierarchy.getRoot());
if (image != null) {
mHScale.setSize(image.getImageData().width, getClientArea().width);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutWindowCoordinator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutWindowCoordinator.java
new file mode 100644
index 0000000..6a6f564
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutWindowCoordinator.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+
+import com.android.annotations.NonNull;
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
+
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchWindow;
+
+/**
+ * The {@link LayoutWindowCoordinator} keeps track of Eclipse window events (opening, closing,
+ * fronting, etc) and uses this information to manage the propertysheet and outline
+ * views such that they are always(*) showing:
+ * <ul>
+ * <li> If the Property Sheet and Outline Eclipse views are showing, it does nothing.
+ * "Showing" means "is open", not necessary "is visible", e.g. in a tabbed view
+ * there could be a different view on top.
+ * <li> If just the outline is showing, then the property sheet is shown in a sashed
+ * pane below or to the right of the outline (depending on the dominant dimension
+ * of the window).
+ * <li> TBD: If just the property sheet is showing, should the outline be showed
+ * inside that window? Not yet done.
+ * <li> If the outline is *not* showing, then the outline is instead shown
+ * <b>inside</b> the editor area, in a right-docked view! This right docked view
+ * also includes the property sheet!
+ * <li> If the property sheet is not showing (which includes not showing in the outline
+ * view as well), then it will be shown inside the editor area, along with the outline
+ * which should also be there (since if the outline was showing outside the editor
+ * area, the property sheet would have docked there).
+ * <li> When the editor is maximized, then all views are temporarily hidden. In this
+ * case, the property sheet and outline will show up inside the editor.
+ * When the editor view is un-maximized, the view state will return to what it
+ * was before.
+ * </ul>
+ * Note that this coordinator is a singleton and is shared between all the open editors.
+ */
+public class LayoutWindowCoordinator implements IPartListener2 {
+ static final String PROPERTY_SHEET_PART_ID = "org.eclipse.ui.views.PropertySheet"; //$NON-NLS-1$
+ static final String OUTLINE_PART_ID = "org.eclipse.ui.views.ContentOutline"; //$NON-NLS-1$
+ /** The workbench window */
+ private final IWorkbenchWindow mWindow;
+ /** Is the Eclipse property sheet ViewPart open? */
+ private boolean mPropertiesOpen;
+ /** Is the Eclipse outline ViewPart open? */
+ private boolean mOutlineOpen;
+ /** Is the editor maximized? */
+ private boolean mEditorMaximized;
+ /**
+ * Has the coordinator been initialized? We may have to delay initialization
+ * and perform it lazily if the workbench window does not have an active
+ * page when the coordinator is first started
+ */
+ private boolean mInitialized;
+
+ /**
+ * Start the coordinator
+ *
+ * @param window the associated window
+ */
+ public static void start(@NonNull IWorkbenchWindow window) {
+ LayoutWindowCoordinator coordinator = new LayoutWindowCoordinator(window);
+
+ IPartService service = window.getPartService();
+ if (service != null) {
+ // What if the window is *already* open? How do I deal with that?
+ service.addPartListener(coordinator);
+ }
+ }
+
+ private LayoutWindowCoordinator(IWorkbenchWindow window) {
+ mWindow = window;
+
+ initialize();
+ }
+
+ private void initialize() {
+ if (mInitialized) {
+ return;
+ }
+
+ IWorkbenchPage activePage = mWindow.getActivePage();
+ if (activePage == null) {
+ return;
+ }
+
+ mInitialized = true;
+
+ // Look up current state of the properties and outline windows (in case
+ // they have already been opened before we added our part listener)
+ IViewReference ref = findPropertySheetView(activePage);
+ if (ref != null) {
+ IWorkbenchPart part = ref.getPart(false /*restore*/);
+ if (activePage.isPartVisible(part)) {
+ mPropertiesOpen = true;
+ }
+ }
+ ref = findOutlineView(activePage);
+ if (ref != null) {
+ IWorkbenchPart part = ref.getPart(false /*restore*/);
+ if (activePage.isPartVisible(part)) {
+ mOutlineOpen = true;
+ }
+ }
+ mEditorMaximized = activePage.isPageZoomed();
+ syncActive();
+ }
+
+ static IViewReference findPropertySheetView(IWorkbenchPage activePage) {
+ return activePage.findViewReference(PROPERTY_SHEET_PART_ID);
+ }
+
+ static IViewReference findOutlineView(IWorkbenchPage activePage) {
+ return activePage.findViewReference(OUTLINE_PART_ID);
+ }
+
+ /**
+ * Syncs the given editor's view state such that the property sheet and or
+ * outline are shown or hidden according to the visibility of the global
+ * outline and property sheet views.
+ * <p>
+ * This is typically done when a layout editor is fronted. For view updates
+ * when the view is already showing, the {@link LayoutWindowCoordinator}
+ * will automatically handle the current fronted window.
+ *
+ * @param editor the editor to sync
+ */
+ private void sync(GraphicalEditorPart editor) {
+ if (mEditorMaximized) {
+ editor.showStructureViews(true /*outline*/, true /*properties*/, true /*layout*/);
+ } else if (mOutlineOpen) {
+ editor.showStructureViews(false /*outline*/, false /*properties*/, true /*layout*/);
+ editor.getCanvasControl().getOutlinePage().setShowPropertySheet(!mPropertiesOpen);
+ } else {
+ editor.showStructureViews(true /*outline*/, !mPropertiesOpen /*properties*/,
+ true /*layout*/);
+ }
+ }
+
+ private void sync(IWorkbenchPart part) {
+ if (part instanceof AndroidXmlEditor) {
+ LayoutEditorDelegate editor = LayoutEditorDelegate.fromEditor((IEditorPart) part);
+ if (editor != null) {
+ sync(editor.getGraphicalEditor());
+ }
+ }
+ }
+
+ private void syncActive() {
+ IWorkbenchPage activePage = mWindow.getActivePage();
+ if (activePage != null) {
+ IEditorPart editor = activePage.getActiveEditor();
+ sync(editor);
+ }
+ }
+
+ private void propertySheetClosed() {
+ mPropertiesOpen = false;
+ syncActive();
+ }
+
+ private void propertySheetOpened() {
+ mPropertiesOpen = true;
+ syncActive();
+ }
+
+ private void outlineClosed() {
+ mOutlineOpen = false;
+ syncActive();
+ }
+
+ private void outlineOpened() {
+ mOutlineOpen = true;
+ syncActive();
+ }
+
+ // ---- Implements IPartListener2 ----
+
+ @Override
+ public void partOpened(IWorkbenchPartReference partRef) {
+ // We ignore partOpened() and partClosed() because these methods are only
+ // called when a view is opened in the first perspective, and closed in the
+ // last perspective. The outline is typically used in multiple perspectives,
+ // so closing it in the Java perspective does *not* fire a partClosed event.
+ // There is no notification for "part closed in perspective" (see issue
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=54559 for details).
+ // However, the workaround we can use is to listen to partVisible() and
+ // partHidden(). These will be called more often than we'd like (e.g.
+ // when the tab order causes a view to be obscured), however, we can use
+ // the workaround of looking up IWorkbenchPage.findViewReference(id) after
+ // partHidden(), which will return null if the view is closed in the current
+ // perspective. For partOpened, we simply look in partVisible() for whether
+ // our flags tracking the view state have been initialized already.
+ }
+
+ @Override
+ public void partClosed(IWorkbenchPartReference partRef) {
+ // partClosed() doesn't get called when a window is closed unless it has
+ // been closed in *all* perspectives. See partOpened() for more.
+ }
+
+ @Override
+ public void partHidden(IWorkbenchPartReference partRef) {
+ IWorkbenchPage activePage = mWindow.getActivePage();
+ if (activePage == null) {
+ return;
+ }
+ initialize();
+
+ // See if this looks like the window was closed in this workspace
+ // See partOpened() for an explanation.
+ String id = partRef.getId();
+ if (PROPERTY_SHEET_PART_ID.equals(id)) {
+ if (activePage.findViewReference(id) == null) {
+ propertySheetClosed();
+ return;
+ }
+ } else if (OUTLINE_PART_ID.equals(id)) {
+ if (activePage.findViewReference(id) == null) {
+ outlineClosed();
+ return;
+ }
+ }
+
+ // Does this look like a window getting maximized? If so, show the editor
+ // outline and propertysheet views!
+ // (Note: We can't use activePage.isPageZoomed() here because the state flag
+ // is updated too late so querying it here gives us the previous state)
+ IViewReference[] viewReferences = activePage.getViewReferences();
+ int visibleCount = 0;
+ for (IViewReference reference : viewReferences) {
+ IWorkbenchPart part = reference.getPart(false /*restore*/);
+ if (part != null && activePage.isPartVisible(part)) {
+ visibleCount++;
+ if (visibleCount > 1) {
+ break;
+ }
+ }
+ }
+
+ mEditorMaximized = visibleCount <= 1;
+ if (mEditorMaximized) {
+ // Only consider -maximizing- the window to be occasion for handling
+ // a "property sheet closed" event as a "show outline.
+ // And in fact we may want to remove it once you re-expose things
+ // in this mode!
+ syncActive();
+ }
+ }
+
+ @Override
+ public void partVisible(IWorkbenchPartReference partRef) {
+ IWorkbenchPage activePage = mWindow.getActivePage();
+ if (activePage == null) {
+ return;
+ }
+ initialize();
+
+ String id = partRef.getId();
+ if (mEditorMaximized) {
+ // Return to their non-maximized state
+ mEditorMaximized = false;
+ syncActive();
+ }
+
+ IWorkbenchPart part = partRef.getPart(false /*restore*/);
+ sync(part);
+
+ // See partOpened() for an explanation
+ if (PROPERTY_SHEET_PART_ID.equals(id)) {
+ if (!mPropertiesOpen) {
+ propertySheetOpened();
+ assert mPropertiesOpen;
+ }
+ } else if (OUTLINE_PART_ID.equals(id)) {
+ if (!mOutlineOpen) {
+ outlineOpened();
+ assert mOutlineOpen;
+ }
+ }
+ }
+
+ @Override
+ public void partInputChanged(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partActivated(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partBroughtToTop(IWorkbenchPartReference partRef) {
+ }
+
+ @Override
+ public void partDeactivated(IWorkbenchPartReference partRef) {
+ }
+} \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
index c5158af..a413ed1 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
@@ -50,6 +50,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
+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.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.editors.ui.ErrorImageComposite;
@@ -65,6 +66,7 @@ import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.JFacePreferences;
@@ -82,6 +84,7 @@ import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
@@ -92,18 +95,18 @@ import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.INullSelectionListener;
-import org.eclipse.ui.IPageLayout;
-import org.eclipse.ui.ISelectionListener;
-import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
-import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
+import org.eclipse.wb.core.controls.SelfOrientingSashForm;
+import org.eclipse.wb.internal.core.editor.structure.IPage;
+import org.eclipse.wb.internal.core.editor.structure.PageSiteComposite;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -125,7 +128,7 @@ import java.util.Set;
* (on which both the layout editor part and the property sheet page listen.)
*/
public class OutlinePage extends ContentOutlinePage
- implements ISelectionListener, INullSelectionListener {
+ implements INullSelectionListener, IPage {
/** Label which separates outline text from additional attributes like text prefix or url */
private static final String LABEL_SEPARATOR = " - ";
@@ -150,6 +153,14 @@ public class OutlinePage extends ContentOutlinePage
*/
private MenuManager mMenuManager;
+ private Composite mControl;
+ private PropertySheetPage mPropertySheet;
+ private PageSiteComposite mPropertySheetComposite;
+ private boolean mShowPropertySheet;
+ private boolean mShowHeader;
+ private boolean mIgnoreSelection;
+ private boolean mActive = true;
+
/** Action to Select All in the tree */
private final Action mTreeSelectAllAction = new Action() {
@Override
@@ -204,13 +215,124 @@ public class OutlinePage extends ContentOutlinePage
}
};
+ /**
+ * Creates a new {@link OutlinePage} associated with the given editor
+ *
+ * @param graphicalEditorPart the editor associated with this outline
+ */
public OutlinePage(GraphicalEditorPart graphicalEditorPart) {
super();
mGraphicalEditorPart = graphicalEditorPart;
}
@Override
+ public Control getControl() {
+ // We've injected some controls between the root of the outline page
+ // and the tree control, so return the actual root (a sash form) rather
+ // than the superclass' implementation which returns the tree. If we don't
+ // do this, various checks in the outline page which checks that getControl().getParent()
+ // is the outline window itself will ignore this page.
+ return mControl;
+ }
+
+ void setActive(boolean active) {
+ if (active != mActive) {
+ mActive = active;
+
+ // Outlines are by default active when they are created; this is intended
+ // for deactivating a hidden outline and later reactivating it
+ assert mControl != null;
+ if (active) {
+ getSite().getPage().addSelectionListener(this);
+ setModel(mGraphicalEditorPart.getCanvasControl().getViewHierarchy().getRoot());
+ } else {
+ getSite().getPage().removeSelectionListener(this);
+ mRootWrapper.setRoot(null);
+ if (mPropertySheet != null) {
+ mPropertySheet.selectionChanged(null, TreeSelection.EMPTY);
+ }
+ }
+ }
+ }
+
+ /**
+ * Set whether the outline should be shown in the header
+ *
+ * @param show whether a header should be shown
+ */
+ public void setShowHeader(boolean show) {
+ mShowHeader = show;
+ }
+
+ /**
+ * Set whether the property sheet should be shown within this outline
+ *
+ * @param show whether the property sheet should show
+ */
+ public void setShowPropertySheet(boolean show) {
+ if (show != mShowPropertySheet) {
+ mShowPropertySheet = show;
+ if (mControl == null) {
+ return;
+ }
+
+ if (show && mPropertySheet == null) {
+ createPropertySheet();
+ } else if (!show) {
+ mPropertySheetComposite.dispose();
+ mPropertySheetComposite = null;
+ mPropertySheet.dispose();
+ mPropertySheet = null;
+ }
+
+ mControl.layout();
+ }
+ }
+
+ @Override
public void createControl(Composite parent) {
+ mControl = new SelfOrientingSashForm(parent, SWT.VERTICAL);
+
+ if (mShowHeader) {
+ PageSiteComposite mOutlineComposite = new PageSiteComposite(mControl, SWT.BORDER);
+ mOutlineComposite.setTitleText("Outline");
+ mOutlineComposite.setTitleImage(IconFactory.getInstance().getIcon("components_view"));
+ mOutlineComposite.setPage(new IPage() {
+ @Override
+ public void createControl(Composite outlineParent) {
+ createOutline(outlineParent);
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public Control getControl() {
+ return getTreeViewer().getTree();
+ }
+
+ @Override
+ public void setToolBar(IToolBarManager toolBarManager) {
+ makeContributions(null, toolBarManager, null);
+ toolBarManager.update(false);
+ }
+
+ @Override
+ public void setFocus() {
+ getControl().setFocus();
+ }
+ });
+ } else {
+ createOutline(mControl);
+ }
+
+ if (mShowPropertySheet) {
+ createPropertySheet();
+ }
+ }
+
+ private void createOutline(Composite parent) {
super.createControl(parent);
TreeViewer tv = getTreeViewer();
@@ -218,6 +340,7 @@ public class OutlinePage extends ContentOutlinePage
tv.setContentProvider(new ContentProvider());
tv.setLabelProvider(new LabelProvider());
tv.setInput(mRootWrapper);
+ tv.expandToLevel(mRootWrapper.getRoot(), 2);
int supportedOperations = DND.DROP_COPY | DND.DROP_MOVE;
Transfer[] transfers = new Transfer[] {
@@ -263,6 +386,9 @@ public class OutlinePage extends ContentOutlinePage
tv.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
+ // This used to open the property view, but now that properties are docked
+ // let's use it for something else -- such as showing the editor source
+ /*
// Front properties panel; its selection is already linked
IWorkbenchPage page = getSite().getPage();
try {
@@ -270,6 +396,16 @@ public class OutlinePage extends ContentOutlinePage
} catch (PartInitException e) {
AdtPlugin.log(e, "Could not activate property sheet");
}
+ */
+
+ TreeItem[] selection = getTreeViewer().getTree().getSelection();
+ if (selection.length > 0) {
+ CanvasViewInfo vi = getViewInfo(selection[0].getData());
+ if (vi != null) {
+ LayoutCanvas canvas = mGraphicalEditorPart.getCanvasControl();
+ canvas.show(vi);
+ }
+ }
}
});
@@ -307,12 +443,24 @@ public class OutlinePage extends ContentOutlinePage
});
}
+ private void createPropertySheet() {
+ mPropertySheetComposite = new PageSiteComposite(mControl, SWT.BORDER);
+ mPropertySheetComposite.setTitleText("Properties");
+ mPropertySheetComposite.setTitleImage(IconFactory.getInstance().getIcon("properties_view"));
+ mPropertySheet = new PropertySheetPage(mGraphicalEditorPart);
+ mPropertySheetComposite.setPage(mPropertySheet);
+ }
+
@Override
public void dispose() {
mRootWrapper.setRoot(null);
getSite().getPage().removeSelectionListener(this);
super.dispose();
+ if (mPropertySheet != null) {
+ mPropertySheet.dispose();
+ mPropertySheet = null;
+ }
}
/**
@@ -321,6 +469,10 @@ public class OutlinePage extends ContentOutlinePage
* @param rootViewInfo The root of the view info hierarchy. Can be null.
*/
public void setModel(CanvasViewInfo rootViewInfo) {
+ if (!mActive) {
+ return;
+ }
+
mRootWrapper.setRoot(rootViewInfo);
TreeViewer tv = getTreeViewer();
@@ -354,6 +506,9 @@ public class OutlinePage extends ContentOutlinePage
if (selection == null) {
selection = TreeSelection.EMPTY;
}
+ if (selection.equals(TreeSelection.EMPTY)) {
+ return;
+ }
super.setSelection(selection);
@@ -369,6 +524,14 @@ public class OutlinePage extends ContentOutlinePage
}
}
+ @Override
+ protected void fireSelectionChanged(ISelection selection) {
+ super.fireSelectionChanged(selection);
+ if (mPropertySheet != null && !mIgnoreSelection) {
+ mPropertySheet.selectionChanged(null, selection);
+ }
+ }
+
/**
* Listens to a workbench selection.
* Only listen on selection coming from {@link LayoutEditorDelegate}, which avoid
@@ -376,10 +539,23 @@ public class OutlinePage extends ContentOutlinePage
*/
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ if (mIgnoreSelection) {
+ return;
+ }
+
if (part instanceof IEditorPart) {
LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor((IEditorPart) part);
if (delegate != null) {
- setSelection(selection);
+ try {
+ mIgnoreSelection = true;
+ setSelection(selection);
+
+ if (mPropertySheet != null) {
+ mPropertySheet.selectionChanged(part, selection);
+ }
+ } finally {
+ mIgnoreSelection = false;
+ }
}
}
}
@@ -760,10 +936,10 @@ public class OutlinePage extends ContentOutlinePage
mGraphicalEditorPart.getCanvasControl(),
mMenuManager);
- getControl().setMenu(mMenuManager.createContextMenu(getControl()));
+ getTreeViewer().getTree().setMenu(mMenuManager.createContextMenu(getControl()));
// Update Move Up/Move Down state only when the menu is opened
- getControl().addMenuDetectListener(new MenuDetectListener() {
+ getTreeViewer().getTree().addMenuDetectListener(new MenuDetectListener() {
@Override
public void menuDetected(MenuDetectEvent e) {
mMenuManager.update(IAction.ENABLED);
@@ -1085,4 +1261,10 @@ public class OutlinePage extends ContentOutlinePage
return text;
}
+
+ @Override
+ public void setToolBar(IToolBarManager toolBarManager) {
+ makeContributions(null, toolBarManager, null);
+ toolBarManager.update(false);
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java
index bdd34b9..a65f97c 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/PaletteControl.java
@@ -46,8 +46,6 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gre.PaletteMetadataDe
import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository.RenderMode;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
-import com.android.ide.eclipse.adt.internal.editors.ui.DecorComposite;
-import com.android.ide.eclipse.adt.internal.editors.ui.IDecorContent;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
@@ -58,6 +56,7 @@ import com.android.util.Pair;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
@@ -94,6 +93,7 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.wb.internal.core.editor.structure.IPage;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -127,38 +127,42 @@ import java.util.Set;
public class PaletteControl extends Composite {
/**
- * Wrapper to create a {@link PaletteControl} into a {@link DecorComposite}.
+ * Wrapper to create a {@link PaletteControl}
*/
- public static class PaletteDecor implements IDecorContent {
+ static class PalettePage implements IPage {
private final GraphicalEditorPart mEditorPart;
private PaletteControl mControl;
- public PaletteDecor(GraphicalEditorPart editor) {
+ PalettePage(GraphicalEditorPart editor) {
mEditorPart = editor;
}
@Override
- public String getTitle() {
- return "Palette";
+ public void createControl(Composite parent) {
+ mControl = new PaletteControl(parent, mEditorPart);
}
@Override
- public Image getImage() {
- return IconFactory.getInstance().getIcon("editor_palette"); //$NON-NLS-1$
+ public Control getControl() {
+ return mControl;
}
@Override
- public void createControl(Composite parent) {
- mControl = new PaletteControl(parent, mEditorPart);
+ public void dispose() {
+ mControl.dispose();
}
@Override
- public Control getControl() {
- return mControl;
+ public void setToolBar(IToolBarManager toolBarManager) {
+ assert false; // Call createToolbarItems instead
}
- @Override
- public void createToolbarItems(final ToolBar toolbar) {
+ /**
+ * Add tool bar items to the given toolbar
+ *
+ * @param toolbar the toolbar to add items into
+ */
+ void createToolbarItems(final ToolBar toolbar) {
final ToolItem popupMenuItem = new ToolItem(toolbar, SWT.PUSH);
popupMenuItem.setToolTipText("View Menu");
popupMenuItem.setImage(IconFactory.getInstance().getIcon("view_menu"));
@@ -173,6 +177,11 @@ public class PaletteControl extends Composite {
}
});
}
+
+ @Override
+ public void setFocus() {
+ mControl.setFocus();
+ }
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertyFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertyFactory.java
index bdd7c29..e160079 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertyFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertyFactory.java
@@ -42,7 +42,6 @@ import org.eclipse.wb.internal.core.model.property.ComplexProperty;
import org.eclipse.wb.internal.core.model.property.Property;
import org.eclipse.wb.internal.core.model.property.category.PropertyCategory;
import org.eclipse.wb.internal.core.model.property.editor.PropertyEditor;
-import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -65,7 +64,7 @@ import java.util.WeakHashMap;
* TODO: For any properties that are *set* in XML, they should NOT be labeled as
* advanced (which would make them disappear)
*/
-class PropertyFactory {
+public class PropertyFactory {
/** Disable cache during development only */
private static final boolean CACHE_ENABLED = true || !LintUtils.assertionsEnabled();
static {
@@ -81,7 +80,6 @@ class PropertyFactory {
private static final int PRIO_LAST = 100000;
private final GraphicalEditorPart mGraphicalEditorPart;
- private final PropertyTable mPropertyTable;
private Map<UiViewElementNode, Property[]> mCache =
new WeakHashMap<UiViewElementNode, Property[]>();
private UiViewElementNode mCurrentViewCookie;
@@ -99,9 +97,8 @@ class PropertyFactory {
private SortingMode mSortMode = DEFAULT_MODE;
private SortingMode mCacheSortMode;
- PropertyFactory(GraphicalEditorPart graphicalEditorPart, PropertyTable propertyTable) {
+ public PropertyFactory(GraphicalEditorPart graphicalEditorPart) {
mGraphicalEditorPart = graphicalEditorPart;
- mPropertyTable = propertyTable;
}
/**
@@ -148,7 +145,7 @@ class PropertyFactory {
properties = null;
}
if (properties == null) {
- Collection<? extends Property> propertyList = getProperties(node, mPropertyTable);
+ Collection<? extends Property> propertyList = getProperties(node);
if (propertyList == null) {
properties = new Property[0];
} else {
@@ -160,9 +157,7 @@ class PropertyFactory {
}
- protected Collection<? extends Property> getProperties(
- UiViewElementNode node,
- PropertyTable propertyTable) {
+ protected Collection<? extends Property> getProperties(UiViewElementNode node) {
ViewMetadataRepository repository = ViewMetadataRepository.get();
ViewElementDescriptor viewDescriptor = (ViewElementDescriptor) node.getDescriptor();
String fqcn = viewDescriptor.getFullClassName();
@@ -670,10 +665,6 @@ class PropertyFactory {
return collapsed;
}
- PropertyTable getPropertyTable() {
- return mPropertyTable;
- }
-
@Nullable
GraphicalEditorPart getGraphicalEditor() {
return mGraphicalEditorPart;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertySheetPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertySheetPage.java
index 4a33223..5893c2c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertySheetPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/PropertySheetPage.java
@@ -47,6 +47,7 @@ import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.Page;
import org.eclipse.ui.views.properties.IPropertySheetPage;
+import org.eclipse.wb.internal.core.editor.structure.IPage;
import org.eclipse.wb.internal.core.model.property.Property;
import org.eclipse.wb.internal.core.model.property.table.IPropertyExceptionHandler;
import org.eclipse.wb.internal.core.model.property.table.PropertyTable;
@@ -60,10 +61,10 @@ import java.util.List;
/**
* Property sheet page used when the graphical layout editor is chosen
*/
-public class PropertySheetPage extends Page implements IPropertySheetPage, IUiUpdateListener {
+public class PropertySheetPage extends Page
+ implements IPropertySheetPage, IUiUpdateListener, IPage {
private PropertyTable mPropertyTable;
private final GraphicalEditorPart mEditor;
- private PropertyFactory mPropertyFactory;
private Property mActiveProperty;
private Action mDefaultValueAction;
private Action mShowAdvancedPropertiesAction;
@@ -89,17 +90,13 @@ public class PropertySheetPage extends Page implements IPropertySheetPage, IUiUp
mEditor = editor;
}
- PropertyFactory getPropertyFactory() {
- if (mPropertyFactory == null) {
- assert mPropertyTable != null;
- mPropertyFactory = new PropertyFactory(mEditor, mPropertyTable);
- }
-
- return mPropertyFactory;
+ private PropertyFactory getPropertyFactory() {
+ return mEditor.getPropertyFactory();
}
@Override
public void createControl(Composite parent) {
+ assert parent != null;
mPropertyTable = new PropertyTable(parent, SWT.NONE);
mPropertyTable.setExceptionHandler(new IPropertyExceptionHandler() {
@Override
@@ -121,6 +118,38 @@ public class PropertySheetPage extends Page implements IPropertySheetPage, IUiUp
&& mPropertyTable != null && !mPropertyTable.isDisposed()) {
TreeSelection treeSelection = (TreeSelection) selection;
+ // We get a lot of repeated selection requests for the same selection
+ // as before, so try to eliminate these
+ if (mSelection != null) {
+ if (mSelection.isEmpty()) {
+ if (treeSelection.isEmpty()) {
+ return;
+ }
+ } else {
+ int selectionCount = treeSelection.size();
+ if (selectionCount == mSelection.size()) {
+ boolean same = true;
+ Iterator<?> iterator = treeSelection.iterator();
+ for (int i = 0, n = selectionCount; i < n && iterator.hasNext(); i++) {
+ Object next = iterator.next();
+ if (next instanceof CanvasViewInfo) {
+ CanvasViewInfo info = (CanvasViewInfo) next;
+ if (info != mSelection.get(i)) {
+ same = false;
+ break;
+ }
+ } else {
+ same = false;
+ break;
+ }
+ }
+ if (same) {
+ return;
+ }
+ }
+ }
+ }
+
stopTrackingSelection();
if (treeSelection.isEmpty()) {
@@ -364,4 +393,10 @@ public class PropertySheetPage extends Page implements IPropertySheetPage, IUiUp
}
}
}
+
+ @Override
+ public void setToolBar(IToolBarManager toolBarManager) {
+ makeContributions(null, toolBarManager, null);
+ toolBarManager.update(false);
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/DecorComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/DecorComposite.java
deleted file mode 100755
index b7cc44e..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/DecorComposite.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 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.ui;
-
-import com.android.sdkuilib.ui.GridDataBuilder;
-import com.android.sdkuilib.ui.GridLayoutBuilder;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.CLabel;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.ToolBar;
-
-/**
- * A composite that wraps a control, with a header composed of an image/label
- * and a set of toolbar icons.
- */
-public class DecorComposite extends Composite {
-
- private CLabel mTitle;
- private ToolBar mToolbar;
- private IDecorContent mContent;
-
- public DecorComposite(Composite parent, int style) {
- super(parent, style);
-
- GridLayoutBuilder.create(this).noMargins().columns(2).vSpacing(1);
-
- mTitle = new CLabel(this, SWT.NONE);
- GridDataBuilder.create(mTitle).hGrab().hFill().vCenter();
-
- mToolbar = new ToolBar(this, SWT.FLAT | SWT.RIGHT);
- GridDataBuilder.create(mToolbar).fill();
-
- Label sep = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL);
- GridDataBuilder.create(sep).hSpan(2).hFill();
- }
-
- public DecorComposite setTitle(String title) {
- mTitle.setText(title);
- return this;
- }
-
- public DecorComposite setImage(Image image) {
- mTitle.setImage(image);
- return this;
- }
-
- public DecorComposite setContent(IDecorContent content) {
- mContent = content;
- content.createControl(this);
- GridDataBuilder.create(content.getControl()).hSpan(2).grab().fill();
-
- String t = content.getTitle();
- if (t != null) {
- setTitle(t);
- }
-
- Image i = content.getImage();
- if (i != null) {
- setImage(i);
- }
-
- content.createToolbarItems(mToolbar);
-
- return this;
- }
-
- public Control getContentControl() {
- return mContent == null ? null : mContent.getControl();
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/IDecorContent.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/IDecorContent.java
deleted file mode 100755
index 6f14165..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/ui/IDecorContent.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 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.ui;
-
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.ToolBar;
-
-/**
- * Describes the content of a {@link IDecorContent}.
- */
-public interface IDecorContent {
- /**
- * Creates the control that will be displayed in the {@link IDecorContent}.
- * The control must be available from {@link #getControl()}.
- * @param parent The {@link IDecorContent} parent. Never null.
- */
- public void createControl(Composite parent);
-
- /**
- * Creates the toolbar items that will be displayed in the {@link IDecorContent}. This
- * method will always be called <b>after</b> {@link #createControl}, so the
- * implementation can assume that it can call {@link #getControl()} to obtain the
- * corresponding control that the toolbar items will operate on.
- *
- * @param toolbar the toolbar to add the toolbar items to
- */
- public void createToolbarItems(ToolBar toolbar);
-
- /**
- * Returns the control previously created by {@link #createControl(Composite)}.
- * @return A control to display in the {@link IDecorContent}. Must not be null.
- */
- public Control getControl();
-
- /**
- * Returns an optional title for the {@link IDecorContent}'s header.
- * @return A string to display in the header or null.
- */
- public String getTitle();
-
- /**
- * Returns an optional image for the {@link IDecorContent}'s header.
- * @return An image to display in the header or null.
- */
- public Image getImage();
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java
index 96add71..f6dc870 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/welcome/AdtStartup.java
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.internal.welcome;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutWindowCoordinator;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.sdkstats.DdmsPreferenceStore;
import com.android.sdkstats.SdkStatsService;
@@ -65,6 +66,8 @@ public class AdtStartup implements IStartup {
} else if (mStore.isPingOptIn()) {
sendUsageStats();
}
+
+ initializeWindowCoordinator();
}
private boolean isFirstTime() {
@@ -110,6 +113,19 @@ public class AdtStartup implements IStartup {
return !mStore.isAdtUsed();
}
+ private void initializeWindowCoordinator() {
+ final IWorkbench workbench = PlatformUI.getWorkbench();
+ workbench.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+ if (window != null) {
+ LayoutWindowCoordinator.start(window);
+ }
+ }
+ });
+ }
+
private void showWelcomeWizard() {
final IWorkbench workbench = PlatformUI.getWorkbench();
workbench.getDisplay().asyncExec(new Runnable() {