Home | History | Annotate | Download | only in layout
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.common.layout;
     18 
     19 import static com.android.SdkConstants.ANDROID_URI;
     20 import static com.android.SdkConstants.ATTR_EMS;
     21 import static com.android.SdkConstants.REQUEST_FOCUS;
     22 
     23 import com.android.annotations.NonNull;
     24 import com.android.annotations.Nullable;
     25 import com.android.ide.common.api.IMenuCallback;
     26 import com.android.ide.common.api.INode;
     27 import com.android.ide.common.api.INodeHandler;
     28 import com.android.ide.common.api.IViewRule;
     29 import com.android.ide.common.api.InsertType;
     30 import com.android.ide.common.api.RuleAction;
     31 
     32 import java.util.List;
     33 
     34 /**
     35  * An {@link IViewRule} for android.widget.EditText.
     36  */
     37 public class EditTextRule extends BaseViewRule {
     38 
     39     @Override
     40     public void onCreate(@NonNull INode node, @NonNull INode parent,
     41             @NonNull InsertType insertType) {
     42         super.onCreate(node, parent, insertType);
     43 
     44         if (parent != null) {
     45             INode focus = findFocus(findRoot(parent));
     46             if (focus == null) {
     47                 // Add <requestFocus>
     48                 node.appendChild(REQUEST_FOCUS);
     49             }
     50 
     51             if (parent.getBounds().w >= 320) {
     52                 node.setAttribute(ANDROID_URI, ATTR_EMS, "10"); //$NON-NLS-1$
     53             }
     54         }
     55     }
     56 
     57     /**
     58      * {@inheritDoc}
     59      * <p>
     60      * Adds a "Request Focus" menu item.
     61      */
     62     @Override
     63     public void addContextMenuActions(@NonNull List<RuleAction> actions,
     64             final @NonNull INode selectedNode) {
     65         super.addContextMenuActions(actions, selectedNode);
     66 
     67         final boolean hasFocus = hasFocus(selectedNode);
     68         final String label = hasFocus ? "Clear Focus" : "Request Focus";
     69 
     70         IMenuCallback onChange = new IMenuCallback() {
     71             @Override
     72             public void action(
     73                     @NonNull RuleAction menuAction,
     74                     @NonNull List<? extends INode> selectedNodes,
     75                     @Nullable String valueId,
     76                     @Nullable Boolean newValue) {
     77                 selectedNode.editXml(label, new INodeHandler() {
     78                     @Override
     79                     public void handle(@NonNull INode node) {
     80                         INode focus = findFocus(findRoot(node));
     81                         if (focus != null && focus.getParent() != null) {
     82                             focus.getParent().removeChild(focus);
     83                         }
     84                         if (!hasFocus) {
     85                             node.appendChild(REQUEST_FOCUS);
     86                         }
     87                     }
     88                 });
     89             }
     90         };
     91 
     92         actions.add(RuleAction.createAction("_setfocus", label, onChange, //$NON-NLS-1$
     93                 null, 5, false /*supportsMultipleNodes*/));
     94         actions.add(RuleAction.createSeparator(7));
     95     }
     96 
     97     /** Returns true if the given node currently has focus */
     98     private static boolean hasFocus(INode node) {
     99         INode focus = findFocus(node);
    100         if (focus != null) {
    101             return focus.getParent() == node;
    102         }
    103 
    104         return false;
    105     }
    106 
    107     /** Returns the root/top level node in the view hierarchy that contains the given node */
    108     private static INode findRoot(INode node) {
    109         // First find the parent
    110         INode root = node;
    111         while (root != null) {
    112             INode parent = root.getParent();
    113             if (parent == null) {
    114                 break;
    115             } else {
    116                 root = parent;
    117             }
    118         }
    119 
    120         return root;
    121     }
    122 
    123     /** Finds the focus node (not the node containing focus, but the actual request focus node
    124      * under a given node */
    125     private static INode findFocus(INode node) {
    126         if (node.getFqcn().equals(REQUEST_FOCUS)) {
    127             return node;
    128         }
    129 
    130         for (INode child : node.getChildren()) {
    131             INode focus = findFocus(child);
    132             if (focus != null) {
    133                 return focus;
    134             }
    135         }
    136         return null;
    137     }
    138 
    139 }
    140