blob: f4a826fa296049ceb325a26643655abc1ff5e88a [file] [log] [blame]
/*
* 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.layout.gle2;
import com.android.ide.common.api.INode;
import com.android.ide.common.api.InsertType;
import com.android.ide.common.layout.BaseLayoutRule;
import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** Drop listener for the outline page */
/*package*/ class OutlineDropListener extends ViewerDropAdapter {
private final OutlinePage mOutlinePage;
public OutlineDropListener(OutlinePage outlinePage, TreeViewer treeViewer) {
super(treeViewer);
mOutlinePage = outlinePage;
}
@Override
public void dragEnter(DropTargetEvent event) {
if (event.detail == DND.DROP_NONE && GlobalCanvasDragInfo.getInstance().isDragging()) {
// For some inexplicable reason, we get DND.DROP_NONE from the palette
// even though in its drag start we set DND.DROP_COPY, so correct that here...
int operation = DND.DROP_COPY;
event.detail = operation;
}
super.dragEnter(event);
}
@Override
public boolean performDrop(Object data) {
final DropTargetEvent event = getCurrentEvent();
if (event == null) {
return false;
}
int location = determineLocation(event);
if (location == LOCATION_NONE) {
return false;
}
final SimpleElement[] elements;
SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
if (sxt.isSupportedType(event.currentDataType)) {
if (data instanceof SimpleElement[]) {
elements = (SimpleElement[]) data;
} else {
return false;
}
} else {
return false;
}
if (elements.length == 0) {
return false;
}
// Determine target:
CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
if (parent == null) {
return false;
}
int index = -1;
UiViewElementNode parentNode = parent.getUiViewNode();
if (location == LOCATION_BEFORE || location == LOCATION_AFTER) {
UiViewElementNode node = parentNode;
parent = parent.getParent();
if (parent == null) {
return false;
}
parentNode = parent.getUiViewNode();
// Determine index
index = 0;
for (UiElementNode child : parentNode.getUiChildren()) {
if (child == node) {
break;
}
index++;
}
if (location == LOCATION_AFTER) {
index++;
}
}
// Copy into new position.
final LayoutCanvas canvas = mOutlinePage.getEditor().getCanvasControl();
final NodeProxy targetNode = canvas.getNodeFactory().create(parentNode);
// Record children of the target right before the drop (such that we can
// find out after the drop which exact children were inserted)
Set<INode> children = new HashSet<INode>();
for (INode node : targetNode.getChildren()) {
children.add(node);
}
String label = MoveGesture.computeUndoLabel(targetNode, elements, event.detail);
final int indexFinal = index;
canvas.getEditorDelegate().getEditor().wrapUndoEditXmlModel(label, new Runnable() {
@Override
public void run() {
InsertType insertType = MoveGesture.getInsertType(event, targetNode);
canvas.getRulesEngine().setInsertType(insertType);
Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas();
boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas;
BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal);
targetNode.applyPendingChanges();
// Clean up drag if applicable
if (event.detail == DND.DROP_MOVE) {
GlobalCanvasDragInfo.getInstance().removeSource();
}
}
});
// Now find out which nodes were added, and look up their corresponding
// CanvasViewInfos
final List<INode> added = new ArrayList<INode>();
for (INode node : targetNode.getChildren()) {
if (!children.contains(node)) {
added.add(node);
}
}
// Select the newly dropped nodes
final SelectionManager selectionManager = canvas.getSelectionManager();
selectionManager.setOutlineSelection(added);
canvas.redraw();
return true;
}
@Override
public boolean validateDrop(Object target, int operation,
TransferData transferType) {
DropTargetEvent event = getCurrentEvent();
if (event == null) {
return false;
}
int location = determineLocation(event);
if (location == LOCATION_NONE) {
return false;
}
SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
if (!sxt.isSupportedType(transferType)) {
return false;
}
CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
if (parent == null) {
return false;
}
UiViewElementNode parentNode = parent.getUiViewNode();
if (location == LOCATION_ON) {
// Targeting the middle of an item means to add it as a new child
// of the given element. This is only allowed on some types of nodes.
if (!DescriptorsUtils.canInsertChildren(parentNode.getDescriptor(),
parent.getViewObject())) {
return false;
}
}
// Check that the drop target position is not a child or identical to
// one of the dragged items
SelectionItem[] sel = GlobalCanvasDragInfo.getInstance().getCurrentSelection();
if (sel != null) {
for (SelectionItem item : sel) {
if (isAncestor(item.getViewInfo().getUiViewNode(), parentNode)) {
return false;
}
}
}
return true;
}
/** Returns true if the given parent node is an ancestor of the given child node */
private boolean isAncestor(UiElementNode parent, UiElementNode child) {
while (child != null) {
if (child == parent) {
return true;
}
child = child.getUiParent();
}
return false;
}
}