From: Raphael Moll Date: Tue, 29 Jun 2010 04:50:14 +0000 (-0700) Subject: ADT GLE2: Synchronize selection outline->canvas X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=32adc869c620dc06b20bb73cc1b311f13fa277cb;p=android-x86%2Fsdk.git ADT GLE2: Synchronize selection outline->canvas Change-Id: I21458fe649b2d62390edba5ea107afe888185d3f --- 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 40c3ec699..723b9749a 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 @@ -32,6 +32,11 @@ import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; import com.android.layoutlib.api.ILayoutResult; import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ITreeSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreePath; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.dnd.Clipboard; @@ -75,10 +80,12 @@ import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.awt.image.Raster; import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.Set; /** * Displays the image rendered by the {@link GraphicalEditorPart} and handles @@ -89,13 +96,12 @@ import java.util.ListIterator; * * TODO list: * - gray on error, keep select but disable d'n'd. - * - handle drag'n'drop (internal, for moving/duplicating). * - handle context menu (depending on selection). * - delete, copy/paste linked with menus and in context menu * - context menu handling of layout + local props (via IViewRules) - * - selection synchronization with the outline (both ways). * - outline should include same context menu + delete/copy/paste ops. * - outline should include drop support (from canvas or from palette) + * - synchronize with property view */ /* package */ class LayoutCanvas extends Canvas { @@ -193,7 +199,17 @@ import java.util.ListIterator; /** The current Outline Page, to synchronize the selection both ways. */ private OutlinePage2 mOutlinePage; - public LayoutCanvas(LayoutEditor layoutEditor, RulesEngine rulesEngine, Composite parent, int style) { + /** Listens to selections on the Outline Page and updates the canvas selection. */ + private OutlineSelectionListener mOutlineSelectionListener; + + /** Barrier set when updating the outline page to match the canvas selection, + * to prevent it from triggering the outline selection listener. */ + private boolean mInsideUpdateOutlineSelection; + + public LayoutCanvas(LayoutEditor layoutEditor, + RulesEngine rulesEngine, + Composite parent, + int style) { super(parent, style | SWT.DOUBLE_BUFFERED | SWT.V_SCROLL | SWT.H_SCROLL); mLayoutEditor = layoutEditor; mRulesEngine = rulesEngine; @@ -265,13 +281,23 @@ import java.util.ListIterator; Object outline = layoutEditor.getAdapter(IContentOutlinePage.class); if (outline instanceof OutlinePage2) { mOutlinePage = (OutlinePage2) outline; + // Note: we can't set the OutlinePage's SelectionChangeListener now + // because the TreeViewer backing the Outline Page hasn't been created + // yet. Instead we will create it "lazily" in updateOulineSelection(). } } + + @Override public void dispose() { super.dispose(); + if (mOutlineSelectionListener != null && mOutlinePage != null) { + mOutlinePage.removeSelectionChangedListener(mOutlineSelectionListener); + mOutlineSelectionListener = null; + } + if (mHoverFgColor != null) { mHoverFgColor.dispose(); mHoverFgColor = null; @@ -1107,29 +1133,117 @@ import java.util.ListIterator; * Update the selection in the outline page to match the current one from {@link #mSelections} */ private void updateOulineSelection() { - if (mOutlinePage == null) { - return; - } + boolean old = mInsideUpdateOutlineSelection; + try { + mInsideUpdateOutlineSelection = true; - if (mSelections.size() == 0) { - mOutlinePage.selectAndReveal(null); - return; - } + if (mOutlinePage == null) { + return; + } - ArrayList selectedVis = new ArrayList(); - for (CanvasSelection cs : mSelections) { - CanvasViewInfo vi = cs.getViewInfo(); - if (vi != null) { - selectedVis.add(vi); + // Add the OutlineSelectionListener as soon as the outline page tree view exists. + if (mOutlineSelectionListener == null && mOutlinePage.getControl() != null) { + mOutlineSelectionListener = new OutlineSelectionListener(); + mOutlinePage.addSelectionChangedListener(mOutlineSelectionListener); } - } - mOutlinePage.selectAndReveal(selectedVis.toArray(new CanvasViewInfo[selectedVis.size()])); + + if (mSelections.size() == 0) { + mOutlinePage.selectAndReveal(null); + return; + } + + ArrayList selectedVis = new ArrayList(); + for (CanvasSelection cs : mSelections) { + CanvasViewInfo vi = cs.getViewInfo(); + if (vi != null) { + selectedVis.add(vi); + } + } + + mOutlinePage.selectAndReveal( + selectedVis.toArray(new CanvasViewInfo[selectedVis.size()])); + } finally { + mInsideUpdateOutlineSelection = old; + } } //--------------- + private class OutlineSelectionListener implements ISelectionChangedListener { + public void selectionChanged(SelectionChangedEvent event) { + if (mInsideUpdateOutlineSelection) { + return; + } + + try { + mInsideUpdateOutlineSelection = true; + + ISelection sel = event.getSelection(); + + // The selection coming from the OutlinePage2 must be a list of + // CanvasViewInfo. See the implementation of OutlinePage2#selectAndReveal() + // for how it is constructed. + if (sel instanceof ITreeSelection) { + ITreeSelection treeSel = (ITreeSelection) sel; + + if (treeSel.isEmpty() && mSelections.size() > 0) { + // Clear existing selection + mSelections.clear(); + mAltSelection = null; + redraw(); + return; + } + + boolean changed = false; + + // Create a list of all currently selected view infos + Set oldSelected = new HashSet(); + for (CanvasSelection cs : mSelections) { + oldSelected.add(cs.getViewInfo()); + } + + // Go thru new selection and take care of selecting new items + // or marking those which are the same as in the current selection + for (TreePath path : treeSel.getPaths()) { + Object seg = path.getLastSegment(); + if (seg instanceof CanvasViewInfo) { + CanvasViewInfo newVi = (CanvasViewInfo) seg; + if (oldSelected.contains(newVi)) { + // This view info is already selected. Remove it from the + // oldSelected list so that we don't de-select it later. + oldSelected.remove(newVi); + } else { + // This view info is not already selected. Select it now. + + // reset alternate selection if any + mAltSelection = null; + // otherwise add it. + mSelections.add( + new CanvasSelection(newVi, mRulesEngine, mNodeFactory)); + changed = true; + } + } + } + + // De-select old selected items that are not in the new one + for (CanvasViewInfo vi : oldSelected) { + deselect(vi); + changed = true; + } + + if (changed) { + redraw(); + } + } + + } finally { + mInsideUpdateOutlineSelection = false; + } + } + } + private class CanvasDragSourceListener implements DragSourceListener { /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage2.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage2.java index 033732d76..96f0e3fea 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage2.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage2.java @@ -45,7 +45,6 @@ import java.util.ArrayList; /* * TODO -- missing features: - * - synchronize selection tree=>canvas * - right-click context menu *shared* with the one from canvas (simply delegate action) * - drag'n'drop initiated from Palette to Outline * - drag'n'drop from Outline to Outline