View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.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    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import java.util.ArrayList;
18  import java.util.Collections;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.NoSuchElementException;
23  
24  import org.htmlunit.SgmlPage;
25  
26  /**
27   * Wrapper for the HTML element "tr".
28   *
29   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
30   * @author David K. Taylor
31   * @author <a href="mailto:cse@dynabean.de">Christian Sell</a>
32   * @author Ahmed Ashour
33   * @author Ronald Brill
34   * @author Frank Danek
35   */
36  public class HtmlTableRow extends HtmlElement {
37  
38      /** The HTML tag represented by this element. */
39      public static final String TAG_NAME = "tr";
40  
41      /**
42       * Creates an instance.
43       *
44       * @param qualifiedName the qualified name of the element type to instantiate
45       * @param page the page that this element is contained within
46       * @param attributes the initial attributes
47       */
48      HtmlTableRow(final String qualifiedName, final SgmlPage page,
49              final Map<String, DomAttr> attributes) {
50          super(qualifiedName, page, attributes);
51      }
52  
53      /**
54       * @return an Iterator over the all HtmlTableCell objects in this row
55       */
56      public CellIterator getCellIterator() {
57          return new CellIterator();
58      }
59  
60      /**
61       * @return an immutable list containing all the HtmlTableCells held by this object
62       * @see #getCellIterator
63       */
64      public List<HtmlTableCell> getCells() {
65          final List<HtmlTableCell> result = new ArrayList<>();
66          for (final HtmlTableCell cell : getCellIterator()) {
67              result.add(cell);
68          }
69          return Collections.unmodifiableList(result);
70      }
71  
72      /**
73       * @param index the 0-based index
74       * @return the cell at the given index
75       * @throws IndexOutOfBoundsException if there is no cell at the given index
76       */
77      public HtmlTableCell getCell(final int index) throws IndexOutOfBoundsException {
78          int count = 0;
79          for (final HtmlTableCell cell : getCellIterator()) {
80              if (count == index) {
81                  return cell;
82              }
83              count++;
84          }
85          throw new IndexOutOfBoundsException("No cell found for index " + index + ".");
86      }
87  
88      /**
89       * Returns the value of the attribute {@code align}. Refer to the
90       * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
91       * documentation for details on the use of this attribute.
92       *
93       * @return the value of the attribute {@code align}
94       *         or an empty string if that attribute isn't defined.
95       */
96      public final String getAlignAttribute() {
97          return getAttributeDirect("align");
98      }
99  
100     /**
101      * Returns the value of the attribute {@code char}. Refer to the
102      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
103      * documentation for details on the use of this attribute.
104      *
105      * @return the value of the attribute {@code char}
106      *         or an empty string if that attribute isn't defined.
107      */
108     public final String getCharAttribute() {
109         return getAttributeDirect("char");
110     }
111 
112     /**
113      * Returns the value of the attribute {@code charoff}. Refer to the
114      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
115      * documentation for details on the use of this attribute.
116      *
117      * @return the value of the attribute {@code charoff}
118      *         or an empty string if that attribute isn't defined.
119      */
120     public final String getCharoffAttribute() {
121         return getAttributeDirect("charoff");
122     }
123 
124     /**
125      * Returns the value of the attribute {@code valign}. Refer to the
126      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
127      * documentation for details on the use of this attribute.
128      *
129      * @return the value of the attribute {@code valign}
130      *         or an empty string if that attribute isn't defined.
131      */
132     public final String getValignAttribute() {
133         return getAttributeDirect("valign");
134     }
135 
136     /**
137      * Gets the table containing this row.
138      * @return the table
139      */
140     public HtmlTable getEnclosingTable() {
141         return (HtmlTable) getEnclosingElement("table");
142     }
143 
144     /**
145      * Returns the value of the attribute {@code bgcolor}. Refer to the
146      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
147      * documentation for details on the use of this attribute.
148      *
149      * @return the value of the attribute {@code bgcolor}
150      *         or an empty string if that attribute isn't defined.
151      */
152     public final String getBgcolorAttribute() {
153         return getAttributeDirect("bgcolor");
154     }
155 
156     /**
157      * An Iterator over the HtmlTableCells contained in this row. It will also dive
158      * into nested forms, even though that is illegal HTML.
159      */
160     public class CellIterator implements Iterator<HtmlTableCell>, Iterable<HtmlTableCell> {
161         private HtmlTableCell nextCell_;
162         private HtmlForm currentForm_;
163 
164         /** Creates an instance. */
165         public CellIterator() {
166             setNextCell(getFirstChild());
167         }
168 
169         /**
170          * @return whether there is another cell available
171          */
172         @Override
173         public boolean hasNext() {
174             return nextCell_ != null;
175         }
176 
177         /**
178          * @return the next cell
179          * @throws NoSuchElementException if no cell is available
180          */
181         @Override
182         public HtmlTableCell next() throws NoSuchElementException {
183             return nextCell();
184         }
185 
186         /**
187          * Removes the cell under the cursor from the current row.
188          */
189         @Override
190         public void remove() {
191             if (nextCell_ == null) {
192                 throw new IllegalStateException();
193             }
194             final DomNode sibling = nextCell_.getPreviousSibling();
195             if (sibling != null) {
196                 sibling.remove();
197             }
198         }
199 
200         /**
201          * @return the next cell
202          * @throws NoSuchElementException if no cell is available
203          */
204         public HtmlTableCell nextCell() throws NoSuchElementException {
205             if (nextCell_ != null) {
206                 final HtmlTableCell result = nextCell_;
207                 setNextCell(nextCell_.getNextSibling());
208                 return result;
209             }
210             throw new NoSuchElementException();
211         }
212 
213         /**
214          * Sets the internal position to the next cell, starting at the given node
215          * @param node the node to mark as the next cell; if this is not a cell, the
216          *        next reachable cell will be marked.
217          */
218         private void setNextCell(final DomNode node) {
219             nextCell_ = null;
220             for (DomNode next = node; next != null; next = next.getNextSibling()) {
221                 if (next instanceof HtmlTableCell) {
222                     nextCell_ = (HtmlTableCell) next;
223                     return;
224                 }
225                 else if (currentForm_ == null && next instanceof HtmlForm) {
226                     // Completely illegal HTML but some of the big sites (ie amazon) do this
227                     currentForm_ = (HtmlForm) next;
228                     setNextCell(next.getFirstChild());
229                     return;
230                 }
231             }
232             if (currentForm_ != null) {
233                 final DomNode form = currentForm_;
234                 currentForm_ = null;
235                 setNextCell(form.getNextSibling());
236             }
237         }
238 
239         /**
240          * Returns an HtmlTableCell iterator.
241          *
242          * @return an HtmlTableCell Iterator.
243          */
244         @Override
245         public Iterator<HtmlTableCell> iterator() {
246             return this;
247         }
248     }
249 
250     /**
251      * {@inheritDoc}
252      */
253     @Override
254     public DisplayStyle getDefaultStyleDisplay() {
255         return DisplayStyle.TABLE_ROW;
256     }
257 }