blob: 75c7b6d1113775a52e5c29651e7fd12cda88689c [file] [log] [blame]
/*
* Copyright (C) 2008 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.parts;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.uimodel.IUiUpdateListener;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
import com.android.sdklib.SdkConstants;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RequestConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.LayoutEditPolicy;
import org.eclipse.gef.editpolicies.SelectionEditPolicy;
import org.eclipse.gef.requests.CreateRequest;
import org.eclipse.gef.requests.DropRequest;
import org.eclipse.gef.tools.SelectEditPartTracker;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import java.util.List;
/**
* An {@link EditPart} for a {@link UiElementNode}.
*
* @since GLE1
*/
public abstract class UiElementEditPart extends AbstractGraphicalEditPart
implements IUiUpdateListener {
public UiElementEditPart(UiElementNode uiElementNode) {
setModel(uiElementNode);
}
//-------------------------
// Derived classes must define these
abstract protected void hideSelection();
abstract protected void showSelection();
//-------------------------
// Base class overrides
@Override
public DragTracker getDragTracker(Request request) {
return new SelectEditPartTracker(this);
}
@Override
protected void createEditPolicies() {
/*
* This is no longer needed, as a selection edit policy is set by the parent layout.
* Leave this code commented out right now, I'll want to play with this later.
*
installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE,
new NonResizableSelectionEditPolicy(this));
*/
}
/* (non-javadoc)
* Returns a List containing the children model objects.
* Must not return null, instead use the super which returns an empty list.
*/
@SuppressWarnings("unchecked")
@Override
protected List getModelChildren() {
return getUiNode().getUiChildren();
}
@Override
public void activate() {
super.activate();
getUiNode().addUpdateListener(this);
}
@Override
public void deactivate() {
super.deactivate();
getUiNode().removeUpdateListener(this);
}
@Override
protected void refreshVisuals() {
if (getFigure().getParent() != null) {
((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), getBounds());
}
// update the visuals of the children as well
refreshChildrenVisuals();
}
protected void refreshChildrenVisuals() {
if (children != null) {
for (Object child : children) {
if (child instanceof UiElementEditPart) {
UiElementEditPart childPart = (UiElementEditPart)child;
childPart.refreshVisuals();
}
}
}
}
//-------------------------
// IUiUpdateListener implementation
public void uiElementNodeUpdated(UiElementNode ui_node, UiUpdateState state) {
// TODO: optimize by refreshing only when needed
switch(state) {
case ATTR_UPDATED:
refreshVisuals();
break;
case CHILDREN_CHANGED:
refreshChildren();
// new children list, need to update the layout
refreshVisuals();
break;
case CREATED:
refreshVisuals();
break;
case DELETED:
// pass
break;
}
}
//-------------------------
// Local methods
/** @return The object model casted to an {@link UiElementNode} */
public final UiElementNode getUiNode() {
return (UiElementNode) getModel();
}
protected final ElementDescriptor getDescriptor() {
return getUiNode().getDescriptor();
}
protected final UiElementEditPart getEditPartParent() {
EditPart parent = getParent();
if (parent instanceof UiElementEditPart) {
return (UiElementEditPart)parent;
}
return null;
}
/**
* Returns a given XML attribute.
* @param attrName The local name of the attribute.
* @return the attribute as a {@link String}, if it exists, or <code>null</code>
*/
protected final String getStringAttr(String attrName) {
UiElementNode uiNode = getUiNode();
if (uiNode.getXmlNode() != null) {
Node xmlNode = uiNode.getXmlNode();
if (xmlNode != null) {
NamedNodeMap nodeAttributes = xmlNode.getAttributes();
if (nodeAttributes != null) {
Node attr = nodeAttributes.getNamedItemNS(
SdkConstants.NS_RESOURCES, attrName);
if (attr != null) {
return attr.getNodeValue();
}
}
}
}
return null;
}
protected final Rectangle getBounds() {
UiElementNode model = (UiElementNode)getModel();
Object editData = model.getEditData();
if (editData != null) {
// assert with fully qualified class name to prevent import changes to another
// Rectangle class.
assert (editData instanceof org.eclipse.draw2d.geometry.Rectangle);
return (Rectangle)editData;
}
// return a dummy rect
return new Rectangle(0, 0, 0, 0);
}
/**
* Returns the EditPart that should be used as the target for the specified Request.
* <p/>
* For instance this is called during drag'n'drop with a CreateRequest.
* <p/>
* Reject being a target for elements which descriptor does not allow children.
*
* {@inheritDoc}
*/
@Override
public EditPart getTargetEditPart(Request request) {
if (request != null && request.getType() == RequestConstants.REQ_CREATE) {
// Reject being a target for elements which descriptor does not allow children.
if (!getUiNode().getDescriptor().hasChildren()) {
return null;
}
}
return super.getTargetEditPart(request);
}
/**
* Used by derived classes {@link UiDocumentEditPart} and {@link UiLayoutEditPart}
* to accept drag'n'drop of new items from the palette.
*
* @param layoutEditPart The layout edit part where this policy is installed. It can
* be either a {@link UiDocumentEditPart} or a {@link UiLayoutEditPart}.
*/
protected void installLayoutEditPolicy(final UiElementEditPart layoutEditPart) {
// This policy indicates how elements can be constrained by the layout.
// TODO Right now we use the XY layout policy since our constraints are
// handled by the android rendering engine rather than GEF. Tweak as
// appropriate.
installEditPolicy(EditPolicy.LAYOUT_ROLE, new LayoutEditPolicy() {
/**
* We don't allow layout children to be resized yet.
* <p/>
* Typical choices would be:
* <ul>
* <li> ResizableEditPolicy, to allow for selection, move and resize.
* <li> NonResizableEditPolicy, to allow for selection, move but not resize.
* <li> SelectionEditPolicy to allow for only selection.
* </ul>
* <p/>
* TODO: make this depend on the part layout. For an AbsoluteLayout we should
* probably use a NonResizableEditPolicy and SelectionEditPolicy for the rest.
* Whether to use ResizableEditPolicy or NonResizableEditPolicy should depend
* on the child in an AbsoluteLayout.
*/
@Override
protected EditPolicy createChildEditPolicy(EditPart child) {
if (child instanceof UiElementEditPart) {
return new NonResizableSelectionEditPolicy((UiElementEditPart) child);
}
return null;
}
@Override
protected Command getCreateCommand(CreateRequest request) {
// We store the ElementDescriptor in the request.factory.type
Object newType = request.getNewObjectType();
if (newType instanceof ElementDescriptor) {
Point where = request.getLocation().getCopy();
Point origin = getLayoutContainer().getClientArea().getLocation();
where.translate(origin.getNegated());
// The host is the EditPart where this policy is installed,
// e.g. this UiElementEditPart.
EditPart host = getHost();
if (host instanceof UiElementEditPart) {
return new ElementCreateCommand((ElementDescriptor) newType,
(UiElementEditPart) host,
where);
}
}
return null;
}
@Override
protected Command getMoveChildrenCommand(Request request) {
// TODO Auto-generated method stub
return null;
}
@Override
public void showLayoutTargetFeedback(Request request) {
super.showLayoutTargetFeedback(request);
// for debugging
// System.out.println("target: " + request.toString() + " -- " + layoutEditPart.getUiNode().getBreadcrumbTrailDescription(false));
if (layoutEditPart instanceof UiLayoutEditPart &&
request instanceof DropRequest) {
Point where = ((DropRequest) request).getLocation().getCopy();
Point origin = getLayoutContainer().getClientArea().getLocation();
where.translate(origin.getNegated());
((UiLayoutEditPart) layoutEditPart).showDropTarget(where);
}
}
@Override
protected void eraseLayoutTargetFeedback(Request request) {
super.eraseLayoutTargetFeedback(request);
if (layoutEditPart instanceof UiLayoutEditPart) {
((UiLayoutEditPart) layoutEditPart).hideDropTarget();
}
}
@Override
protected IFigure createSizeOnDropFeedback(CreateRequest createRequest) {
// TODO understand if this is useful for us or remove
return super.createSizeOnDropFeedback(createRequest);
}
});
}
protected static class NonResizableSelectionEditPolicy extends SelectionEditPolicy {
private final UiElementEditPart mEditPart;
public NonResizableSelectionEditPolicy(UiElementEditPart editPart) {
mEditPart = editPart;
}
@Override
protected void hideSelection() {
mEditPart.hideSelection();
}
@Override
protected void showSelection() {
mEditPart.showSelection();
}
}
}