--- /dev/null
+/*
+ * 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.common.layout;
+
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.REQUEST_FOCUS;
+
+import com.android.ide.common.api.IMenuCallback;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.INodeHandler;
+import com.android.ide.common.api.IViewRule;
+import com.android.ide.common.api.InsertType;
+import com.android.ide.common.api.MenuAction;
+
+import java.util.List;
+
+/**
+ * An {@link IViewRule} for android.widget.EditText.
+ */
+public class EditTextRule extends BaseViewRule {
+
+ @Override
+ public void onCreate(INode node, INode parent, InsertType insertType) {
+ super.onCreate(node, parent, insertType);
+
+ if (parent != null) {
+ INode focus = findFocus(findRoot(parent));
+ if (focus == null) {
+ // Add <requestFocus>
+ node.appendChild(REQUEST_FOCUS);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Adds a "Request Focus" menu item.
+ */
+ @Override
+ public List<MenuAction> getContextMenu(final INode selectedNode) {
+ final boolean hasFocus = hasFocus(selectedNode);
+ final String label = hasFocus ? "Clear Focus" : "Request Focus";
+
+ IMenuCallback onChange = new IMenuCallback() {
+ public void action(MenuAction menuAction, String valueId, Boolean newValue) {
+ selectedNode.editXml(label, new INodeHandler() {
+ public void handle(INode node) {
+ INode focus = findFocus(findRoot(node));
+ if (focus != null && focus.getParent() != null) {
+ focus.getParent().removeChild(focus);
+ }
+ if (!hasFocus) {
+ node.appendChild(REQUEST_FOCUS);
+ }
+ }
+ });
+ }
+ };
+
+ return concatenate(super.getContextMenu(selectedNode),
+ new MenuAction.Action("_setfocus", label, null, onChange)); //$NON-NLS-1$
+ }
+
+ /** Returns true if the given node currently has focus */
+ private static boolean hasFocus(INode node) {
+ INode focus = findFocus(node);
+ if (focus != null) {
+ return focus.getParent() == node;
+ }
+
+ return false;
+ }
+
+ /** Returns the root/top level node in the view hierarchy that contains the given node */
+ private static INode findRoot(INode node) {
+ // First find the parent
+ INode root = node;
+ while (root != null) {
+ INode parent = root.getParent();
+ if (parent == null) {
+ break;
+ } else {
+ root = parent;
+ }
+ }
+
+ return root;
+ }
+
+ /** Finds the focus node (not the node containing focus, but the actual request focus node
+ * under a given node */
+ private static INode findFocus(INode node) {
+ if (node.getFqcn().equals(REQUEST_FOCUS)) {
+ return node;
+ }
+
+ for (INode child : node.getChildren()) {
+ INode focus = findFocus(child);
+ if (focus != null) {
+ return focus;
+ }
+ }
+ return null;
+ }
+
+}
import static com.android.ide.common.layout.LayoutConstants.RELATIVE_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.REQUEST_FOCUS;
import com.android.ide.common.api.IAttributeInfo.Format;
import com.android.ide.common.resources.platform.AttributeInfo;
// if this ui_node is a layout and we're adding it to a document, use match_parent for
// both W/H. Otherwise default to wrap_layout.
ElementDescriptor descriptor = node.getDescriptor();
+
+ if (descriptor.getXmlLocalName().equals(REQUEST_FOCUS)) {
+ // Don't add ids etc to <requestFocus>
+ return;
+ }
+
boolean fill = descriptor.hasChildren() &&
node.getUiParent() instanceof UiDocumentNode;
node.setAttributeValue(
public final class LayoutDescriptors implements IDescriptorProvider {
/**
- * The XML name of the special <include> layout tag.
+ * The XML name of the special {@code <include>} layout tag.
* A synthetic element with that name is created as part of the view descriptors list
* returned by {@link #getViewDescriptors()}.
*/
public static final String VIEW_INCLUDE = "include"; //$NON-NLS-1$
/**
- * The XML name of the special <merge> layout tag.
+ * The XML name of the special {@code <merge>} layout tag.
* A synthetic element with that name is created as part of the view descriptors list
* returned by {@link #getViewDescriptors()}.
*/
public static final String VIEW_MERGE = "merge"; //$NON-NLS-1$
/**
+ * The XML name of the special {@code <requestFocus>} layout tag.
+ * A synthetic element with that name is created as part of the view descriptors list
+ * returned by {@link #getViewDescriptors()}.
+ */
+ public static final String REQUEST_FOCUS = "requestFocus";//$NON-NLS-1$
+
+ /**
* The attribute name of the include tag's url naming the resource to be inserted
* <p>
* <b>NOTE</b>: The layout attribute is NOT in the Android namespace!
fixSuperClasses(infoDescMap);
+ ViewElementDescriptor requestFocus = createRequestFocus();
+ newViews.add(requestFocus);
+ newDescriptors.add(requestFocus);
+
// The <merge> tag can only be a root tag, so it is added at the end.
// It gets everything else as children but it is not made a child itself.
ViewElementDescriptor mergeTag = createMerge(newLayouts);
}
/**
- * Creates and return a new <merge> descriptor.
+ * Creates and return a new {@code <merge>} descriptor.
* @param knownLayouts A list of all known layout view descriptors, used to find the
* FrameLayout descriptor and extract its layout attributes.
*/
}
/**
+ * Creates and return a new {@code <requestFocus>} descriptor.
+ * @param knownLayouts A list of all known layout view descriptors, used to find the
+ * FrameLayout descriptor and extract its layout attributes.
+ */
+ private ViewElementDescriptor createRequestFocus() {
+ String xml_name = REQUEST_FOCUS;
+
+ // Create the include descriptor
+ return new ViewElementDescriptor(
+ xml_name, // xml_name
+ xml_name, // ui_name
+ xml_name, // "class name"; the GLE only treats this as an element tag
+ "Requests focus for the parent element or one of its descendants", // tooltip
+ null, // sdk_url
+ null, // attributes
+ null, // layout attributes
+ null, // children
+ false /* mandatory */);
+ }
+
+ /**
* Finds the descriptor and retrieves all its layout attributes.
*/
private AttributeDescriptor[] findViewLayoutAttributes(