View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.component;
20  
21  import javax.faces.component.UIComponent;
22  
23  import java.util.Collection;
24  import java.util.ArrayList;
25  import java.util.List;
26  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
27  
28  
29  /**
30   * List for storing children.
31   *
32   */
33  class ChildArrayList extends ArrayList<UIComponent>
34  {
35    public ChildArrayList(UIComponent parent)
36    {
37      _parent = parent;
38    }
39  
40    @Override
41    public void add(int index, UIComponent element)
42    {
43      if (element == null)
44        throw new NullPointerException();
45  
46      if ((index < 0) || (index > size()))
47        throw new IndexOutOfBoundsException(_LOG.getMessage(
48          "INDEX_SIZE", new Object[]{index, size()}));
49  
50      UIComponent oldParent = element.getParent();
51      if (oldParent != null)
52      {
53        int adjustedIndex = __removeFromParent(element, index);
54        // Only adjust the index when the child is re-added to the same parent
55        if (oldParent == _parent)
56        {
57          index = adjustedIndex; 
58        }
59      }
60      
61      // do not change the order of these calls, see TRINIDAD-1674 for more info
62      super.add(index, element);
63      element.setParent(_parent);
64    }
65  
66    
67    @Override
68    public boolean add(UIComponent element)
69    {
70      add(size(), element);
71      return true;
72    }
73    
74    @Override
75    public boolean addAll(Collection<? extends UIComponent> collection)
76    {
77      return addAll(size(), collection);
78    }
79  
80    @Override
81    public boolean addAll(
82        int index, 
83        Collection<? extends UIComponent> collection)
84    {
85      boolean changed = false;
86      for(UIComponent element : collection)
87      {
88        if (element == null)
89          throw new NullPointerException();
90  
91        add(index++, element);
92        changed = true;
93      }
94      
95      return changed;
96    }
97  
98    @Override
99    public UIComponent remove(int index)
100   {
101     UIComponent child = super.remove(index);
102     child.setParent(null);
103 
104     return child;
105   }
106 
107   @Override
108   public boolean remove(Object element)
109   {
110     if (element == null)
111       throw new NullPointerException();
112     
113     if (!(element instanceof UIComponent))
114       return false;
115   
116     if (super.remove(element))
117     {
118       UIComponent child = (UIComponent) element;
119       child.setParent(null);
120       return true;
121     }
122 
123     return false;
124   }
125 
126   @Override
127   public void clear()
128   {
129     int size = this.size();
130     
131     while ( size > 0)
132     {
133       size--;
134       remove(size);
135     }
136     
137     super.clear();
138   }
139   
140   @Override
141   public boolean removeAll(Collection<?> collection)
142   {
143     boolean result = false;
144     for(Object element : collection)
145     {
146       if (remove(element))
147         result = true;
148     }
149     
150     return result;
151   }
152 
153   @Override
154   public UIComponent set(int index, UIComponent element)
155   {
156     if (element == null)
157       throw new NullPointerException();
158     
159     if ((index < 0) || (index >= size()))
160       throw new IndexOutOfBoundsException();
161 
162     UIComponent child = element;
163     UIComponent previous = get(index);
164 
165     previous.setParent(null);
166     
167     child.setParent(_parent);
168     super.set(index, element);
169     
170     return previous;
171   }
172 
173   @SuppressWarnings("unchecked")
174   static int __removeFromParent(
175     UIComponent component,
176     int index)
177   {
178     UIComponent parent = component.getParent();
179     assert(parent != null);
180 
181     if (parent.getChildCount() > 0)
182     {
183       List<UIComponent> children = parent.getChildren();
184       int size = children.size();
185       for  (int i = 0; i < size; i++)
186       {
187         if  (children.get(i) == component)
188         {
189           children.remove(i);
190           if (index > i)
191             index--;
192           return index;
193         }
194       }
195     }
196     
197     Collection<UIComponent> facets = parent.getFacets().values();
198     if (facets.contains(component))
199     {
200       facets.remove(component);
201       return index;
202     }
203 
204     // Not good - the child thought it was in a parent,
205     // but it wasn't.
206     assert(false);
207     return index;
208   }
209 
210 
211   private final UIComponent _parent;
212   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
213     ChildArrayList.class);
214   private static final long serialVersionUID = 1L;
215 
216 }