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 Mike Bowler
30 * @author David K. Taylor
31 * @author Christian Sell
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 }