From f200375d590efd084142d60058ce6c9543a1b9cd Mon Sep 17 00:00:00 2001 From: Raphael Date: Mon, 30 Nov 2009 11:07:45 -0800 Subject: [PATCH] ADT GLE2: palette view with drag'n'drop source. Work in progress. --- .../internal/editors/layout/PaletteComposite.java | 323 +++++++++++++++++++-- 1 file changed, 301 insertions(+), 22 deletions(-) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/PaletteComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/PaletteComposite.java index 229494c1e..fd06bdafe 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/PaletteComposite.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/PaletteComposite.java @@ -20,12 +20,27 @@ import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescripto import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.List; /** @@ -79,40 +94,304 @@ public class PaletteComposite extends Composite { c.dispose(); } - if (targetData != null) { - GridLayout gl = new GridLayout(1, false); - gl.horizontalSpacing = 0; - gl.verticalSpacing = 0; - gl.marginHeight = 2; - gl.marginBottom = 2; - gl.marginLeft = 2; - gl.marginRight = 2; - gl.marginTop = 2; - gl.marginBottom = 2; - setLayout(gl); + setGridLayout(this, 2); + + final Composite parent = new Composite(this, SWT.NONE); + setGridLayout(parent, 0); + if (targetData != null) { /* TODO: All this is TEMPORARY. */ Label l = new Label(this, SWT.NONE); l.setText("*** PLACEHOLDER ***"); //$NON-NLS-1$ l.setToolTipText("Temporary mock for the palette. Needs to scroll, needs no buttons, needs to drag'n'drop."); //$NON-NLS-1$ - addGroup("Layouts", targetData.getLayoutDescriptors().getLayoutDescriptors()); - addGroup("Views", targetData.getLayoutDescriptors().getViewDescriptors()); + addGroup(parent, "Layouts", targetData.getLayoutDescriptors().getLayoutDescriptors()); + addGroup(parent, "Views", targetData.getLayoutDescriptors().getViewDescriptors()); } layout(true); + + final ScrollBar vbar = getVerticalBar(); + vbar.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + Point p = parent.getLocation(); + p.y = - vbar.getSelection(); + parent.setLocation(p); + } + }); + } + + private void setGridLayout(Composite parent, int spacing) { + GridLayout gl = new GridLayout(1, false); + gl.horizontalSpacing = 0; + gl.verticalSpacing = 0; + gl.marginHeight = spacing; + gl.marginBottom = spacing; + gl.marginLeft = spacing; + gl.marginRight = spacing; + gl.marginTop = spacing; + gl.marginBottom = spacing; + parent.setLayout(gl); } - private void addGroup(String uiName, List descriptors) { - Label label = new Label(this, SWT.NONE); - label.setText(uiName); + private void addGroup(Composite parent, + String uiName, + List descriptors) { + + Composite group = new Composite(parent, SWT.NONE); + setGridLayout(group, 0); + + Toggle toggle = new Toggle(group, uiName); + //label.setText(String.format("-= %s =-", uiName)); + //label.setToolTipText(); for (ElementDescriptor desc : descriptors) { - Button b = new Button(this, SWT.PUSH); - b.setText(desc.getUiName()); - b.setImage(desc.getIcon()); - b.setToolTipText(desc.getTooltip()); - b.setData(desc); + toggle.addItem(new Item(group, desc)); + } + } + + private static class Toggle extends CLabel implements MouseTrackListener, Listener { + private boolean mMouseIn; + private DragSource mSource; + private ArrayList mItems = new ArrayList(); + + public Toggle(Composite parent, String groupName) { + super(parent, SWT.NONE); + mMouseIn = false; + + String s = String.format("-= %s =-", groupName); + setText(s); + setToolTipText(s); + //TODO use triangle icon and swap it -- setImage(desc.getIcon()); + addMouseTrackListener(this); + addListener(SWT.Selection, this); + } + + public void addItem(Item item) { + mItems.add(item); + } + + @Override + public void dispose() { + if (mSource != null) { + mSource.dispose(); + mSource = null; + } + super.dispose(); + } + + @Override + public int getStyle() { + int style = super.getStyle(); + if (mMouseIn) { + style |= SWT.SHADOW_IN; + } + return style; + } + + public void mouseEnter(MouseEvent e) { + if (!mMouseIn) { + mMouseIn = true; + redraw(); + } + } + + public void mouseExit(MouseEvent e) { + if (mMouseIn) { + mMouseIn = false; + redraw(); + } + } + + public void mouseHover(MouseEvent e) { + // pass + } + + /** Selection event */ + public void handleEvent(Event event) { + for (Item i : mItems) { + i.setVisible(!i.isVisible()); + i.setEnabled(!i.isEnabled()); + } + } + } + + private static class Item extends CLabel implements MouseTrackListener { + + private boolean mMouseIn; + private DragSource mSource; + + public Item(Composite parent, ElementDescriptor desc) { + super(parent, SWT.NONE); + mMouseIn = false; + + setText(desc.getUiName()); + setImage(desc.getIcon()); + setToolTipText(desc.getTooltip()); + addMouseTrackListener(this); + + // DND Reference: http://www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html + mSource = new DragSource(this, DND.DROP_COPY); + mSource.setTransfer(new Transfer[] { ElementDescTransfer.getInstance() }); + mSource.addDragListener(new DescDragSourceListener(desc)); + } + + @Override + public void dispose() { + if (mSource != null) { + mSource.dispose(); + mSource = null; + } + super.dispose(); + } + + @Override + public int getStyle() { + int style = super.getStyle(); + if (mMouseIn) { + style |= SWT.SHADOW_IN; + } + return style; + } + + public void mouseEnter(MouseEvent e) { + if (!mMouseIn) { + mMouseIn = true; + redraw(); + } + } + + public void mouseExit(MouseEvent e) { + if (mMouseIn) { + mMouseIn = false; + redraw(); + } + } + + public void mouseHover(MouseEvent e) { + // pass + } + } + + /** + * A {@link DragSourceListener} that deals with drag'n'drop of + * {@link ElementDescriptor}s. + */ + private static class DescDragSourceListener implements DragSourceListener { + + private final ElementDescriptor mDesc; + + public DescDragSourceListener(ElementDescriptor desc) { + mDesc = desc; + } + + public void dragStart(DragSourceEvent e) { + if (mDesc == null) { + e.doit = false; + } + } + + + public void dragSetData(DragSourceEvent e) { + // Provide the data for the drop when requested by the other side. + if (ElementDescTransfer.getInstance().isSupportedType(e.dataType)) { + e.data = mDesc; + } + } + + public void dragFinished(DragSourceEvent e) { + // Nothing to do here. + } + } + + // TODO move out of this scope once we need it on the other side. + /** + * A d'n'd {@link Transfer} class that can transfer {@link ElementDescriptor}s. + *

+ * The implementation is based on the {@link ByteArrayTransfer} and what we transfer + * is actually only the inner XML name of the element, which is unique enough. + *

+ * Drag source provides an {@link ElementDescriptor} object. + * Drog receivers get back a {@link String} object representing the + * {@link ElementDescriptor#getXmlName()}. + *

+ * Drop receivers can find the corresponding element by using + * {@link ElementDescriptor#findChildrenDescriptor(String, boolean)} with the + * XML name returned by this transfer operation and their root descriptor. + *

+ * Drop receivers must deal with the fact that this XML name may not exist in their + * own {@link ElementDescriptor} hierarchy -- e.g. if the drag came from a different + * GLE based on a different SDK platform or using custom widgets. In this case they + * must refuse the drop. + */ + public static class ElementDescTransfer extends ByteArrayTransfer { + + // Reference: http://www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html + + + private static final String TYPE_NAME = "android.ADT.element.desc.transfer.1"; + private static final int TYPE_ID = registerType(TYPE_NAME); + private static ElementDescTransfer sInstance = new ElementDescTransfer(); + + private ElementDescTransfer() { + // pass + } + + public static ElementDescTransfer getInstance() { + return sInstance; + } + + @Override + protected int[] getTypeIds() { + return new int[] { TYPE_ID }; + } + + @Override + protected String[] getTypeNames() { + return new String[] { TYPE_NAME }; + } + + @Override + protected void javaToNative(Object object, TransferData transferData) { + if (object == null || !(object instanceof ElementDescriptor[])) { + return; + } + + if (isSupportedType(transferData)) { + StringBuilder sb = new StringBuilder(); + boolean needSeparator = false; + for (ElementDescriptor desc : (ElementDescriptor[]) object) { + if (needSeparator) { + sb.append(';'); + } + sb.append(desc.getXmlName()); + needSeparator = true; + } + try { + byte[] buf = sb.toString().getBytes("UTF-8"); //$NON-NLS-1$ + super.javaToNative(buf, transferData); + } catch (UnsupportedEncodingException e) { + // unlikely; ignore + } + } + } + + @Override + protected Object nativeToJava(TransferData transferData) { + if (isSupportedType(transferData)) { + byte[] buf = (byte[]) super.nativeToJava(transferData); + if (buf != null && buf.length > 0) { + try { + String s = new String(buf, "UTF-8"); //$NON-NLS-1$ + String[] names = s.split(";"); //$NON-NLS-1$ + return names; + } catch (UnsupportedEncodingException e) { + // unlikely to happen, but still possible + } + } + } + + return null; } } } -- 2.11.0