1package com.xtremelabs.robolectric.shadows;
2
3import android.view.View;
4import android.view.ViewGroup;
5import android.view.animation.Animation.AnimationListener;
6import com.xtremelabs.robolectric.internal.Implementation;
7import com.xtremelabs.robolectric.internal.Implements;
8
9import java.io.PrintStream;
10import java.util.ArrayList;
11import java.util.List;
12
13import static com.xtremelabs.robolectric.Robolectric.shadowOf;
14
15/**
16 * Shadow for {@code ViewGroup} that simulates its implementation
17 */
18@SuppressWarnings({"UnusedDeclaration"})
19@Implements(ViewGroup.class)
20public class ShadowViewGroup extends ShadowView {
21    private List<View> children = new ArrayList<View>();
22    private AnimationListener animListener;
23    private boolean disallowInterceptTouchEvent = false;
24
25    @Implementation
26    @Override
27    public View findViewById(int id) {
28        if (id == getId()) {
29            return realView;
30        }
31
32        for (View child : children) {
33            View found = child.findViewById(id);
34            if (found != null) {
35                return found;
36            }
37        }
38        return null;
39    }
40
41    @Implementation
42    @Override
43    public View findViewWithTag(Object obj) {
44        if (obj.equals(realView.getTag())) {
45            return realView;
46        }
47
48        for (View child : children) {
49            View found = child.findViewWithTag(obj);
50            if (found != null) {
51                return found;
52            }
53        }
54
55        return null;
56    }
57
58    @Implementation
59    public void addView(View child) {
60        ((ViewGroup) realView).addView(child, -1);
61    }
62
63    @Implementation
64    public void addView(View child, int index) {
65        if (index == -1) {
66            children.add(child);
67        } else {
68            children.add(index, child);
69        }
70        shadowOf(child).parent = this;
71    }
72
73    @Implementation
74    public void addView(View child, int width, int height) {
75        ((ViewGroup) realView).addView(child, -1);
76    }
77
78    @Implementation
79    public void addView(View child, ViewGroup.LayoutParams params) {
80        ((ViewGroup) realView).addView(child, -1);
81    }
82
83    @Implementation
84    public void addView(View child, int index, ViewGroup.LayoutParams params) {
85        ((ViewGroup) realView).addView(child, index);
86    }
87
88    @Implementation
89    public int indexOfChild(View child) {
90        int count = getChildCount();
91        for (int i = 0; i < count; i++) {
92            if (children.get(i) == child) {
93                return i;
94            }
95        }
96        return -1;
97    }
98
99    @Implementation
100    public int getChildCount() {
101        return children.size();
102    }
103
104    @Implementation
105    public View getChildAt(int index) {
106    	if( index >= children.size() ){ return null; }
107        return children.get(index);
108    }
109
110    @Implementation
111    public void removeAllViews() {
112        for (View child : children) {
113            shadowOf(child).parent = null;
114        }
115        children.clear();
116    }
117
118    @Implementation
119    public void removeViewAt(int position) {
120        shadowOf(children.remove(position)).parent = null;
121    }
122
123    @Implementation
124    public void removeView(View view) {
125        removeViewInLayout(view);
126    }
127
128    @Implementation
129    public void removeViewInLayout(View view) {
130        int index = indexOfChild(view);
131        if (index >= 0) {
132            removeViewAt(index);
133        }
134    }
135
136    @Implementation
137    public void removeViews(int start, int count) {
138        removeViewsInLayout(start, count);
139    }
140
141    @Implementation
142    public void removeViewsInLayout(int start, int count) {
143        int lastIndex = start + count - 1;
144        for (int i = lastIndex; i >= start; i--) {
145            removeViewAt(i);
146        }
147    }
148
149    @Override
150    @Implementation
151    public boolean hasFocus() {
152        if (super.hasFocus()) return true;
153
154        for (View child : children) {
155            if (child.hasFocus()) return true;
156        }
157
158        return false;
159    }
160
161    @Implementation
162    @Override
163    public void clearFocus() {
164        if (hasFocus()) {
165            super.clearFocus();
166
167            for (View child : children) {
168                child.clearFocus();
169            }
170        }
171    }
172
173    @Implementation
174    @Override
175    public View findFocus() {
176        if (super.hasFocus()) {
177            return this.realView;
178        }
179
180        for (View child : children) {
181            View focusedView = child.findFocus();
182            if (focusedView != null) {
183                return focusedView;
184            }
185        }
186
187        return null;
188    }
189
190    /**
191     * Returns a string representation of this {@code ViewGroup} by concatenating all of the strings contained in all
192     * of the descendants of this {@code ViewGroup}.
193     * <p/>
194     * Robolectric extension.
195     */
196    @Override
197    public String innerText() {
198        String innerText = "";
199        String delimiter = "";
200
201        for (int i = 0; i < getChildCount(); i++) {
202            View child = getChildAt(i);
203            String childText = shadowOf(child).innerText();
204            if (childText.length() > 0) {
205                innerText += delimiter;
206                delimiter = " ";
207            }
208            innerText += childText;
209        }
210        return innerText;
211    }
212
213    /**
214     * Non-Android method that dumps the state of this {@code ViewGroup} to {@code System.out}
215     */
216    @Override
217    public void dump(PrintStream out, int indent) {
218        dumpFirstPart(out, indent);
219        if (children.size() > 0) {
220            out.println(">");
221
222            for (View child : children) {
223                shadowOf(child).dump(out, indent + 2);
224            }
225
226            dumpIndent(out, indent);
227            out.println("</" + realView.getClass().getSimpleName() + ">");
228        } else {
229            out.println("/>");
230        }
231    }
232
233    @Implementation
234    public void setLayoutAnimationListener(AnimationListener listener) {
235        animListener = listener;
236    }
237
238    @Implementation
239    public AnimationListener getLayoutAnimationListener() {
240        return animListener;
241    }
242
243    @Implementation
244    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
245        disallowInterceptTouchEvent = disallowIntercept;
246    }
247
248    public boolean getDisallowInterceptTouchEvent() {
249        return disallowInterceptTouchEvent;
250    }
251}
252