Source code: nextapp/echoservlet/ui/TriCellTable.java
1 /*
2 * This file is part of the Echo Web Application Framework (hereinafter "Echo").
3 * Copyright (C) 2002-2004 NextApp, Inc.
4 *
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * Alternatively, the contents of this file may be used under the terms of
18 * either the GNU General Public License Version 2 or later (the "GPL"), or
19 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
20 * in which case the provisions of the GPL or the LGPL are applicable instead
21 * of those above. If you wish to allow use of your version of this file only
22 * under the terms of either the GPL or the LGPL, and not to allow others to
23 * use your version of this file under the terms of the MPL, indicate your
24 * decision by deleting the provisions above and replace them with the notice
25 * and other provisions required by the GPL or the LGPL. If you do not delete
26 * the provisions above, a recipient may use your version of this file under
27 * the terms of any one of the MPL, the GPL or the LGPL.
28 */
29
30 package nextapp.echoservlet.ui;
31
32 import nextapp.echo.EchoConstants;
33
34 import nextapp.echoservlet.Connection;
35 import nextapp.echoservlet.LayoutStrut;
36 import nextapp.echoservlet.html.Element;
37 import nextapp.echoservlet.html.ElementNames;
38
39 /**
40 * Renders an HTML table that has two or three "container" cells and
41 * independently settable margins between them. These tables are useful for
42 * rendering buttons that have two or three elements (images, text labels, and
43 * state indicators). This class supports all possible permutations for
44 * placement of each of the two or three contained components.
45 */
46 class TriCellTable extends Element {
47
48 static final int INVERTED = 1;
49 static final int VERTICAL = 2;
50
51 static final int LEFT_RIGHT = 0;
52 static final int RIGHT_LEFT = INVERTED;
53 static final int TOP_BOTTOM = VERTICAL;
54 static final int BOTTOM_TOP = INVERTED | VERTICAL;
55
56 /**
57 * Translates horizontal and vertical orientation constants from the
58 * <code>nextapp.echo.EchoContstants</code> class into the constants
59 * used by <code>TriCellTable</code>:
60 * <ul>
61 * <li>LEFT_RIGHT</li>
62 * <li>RIGHT_LEFT</li>
63 * <li>TOP_BOTTOM</li>
64 * <li>BOTTOM_TOP</li>
65 * </ul>
66 * @param horizontalOrientation The horizontal orientation desired, one of
67 * the following values:
68 * <ul>
69 * <li>EchoConstants.LEFT</li>
70 * <li>EchoConstants.CENTER</li>
71 * <li>EchoConstants.RIGHT</li>
72 * </ul>
73 * @param verticalOrientation The vertical orientation desired, one of the
74 * following values:
75 * <ul>
76 * <li>EchoConstants.TOP</li>
77 * <li>EchoConstants.CENTER</li>
78 * <li>EchoConstants.BOTTOM</li>
79 * </ul>
80 * @return Am orientation constant from <code>TriCellTable</code> that
81 * equates to the orientation parameters provided.
82 */
83 static int getOrientation(int horizontalOrientation, int verticalOrientation) {
84 int tctOrientation;
85
86 switch (verticalOrientation) {
87 case EchoConstants.TOP:
88 tctOrientation = TriCellTable.TOP_BOTTOM;
89 break;
90 case EchoConstants.BOTTOM:
91 tctOrientation = TriCellTable.BOTTOM_TOP;
92 break;
93 default:
94 if (horizontalOrientation == EchoConstants.LEFT) {
95 tctOrientation = TriCellTable.LEFT_RIGHT;
96 } else {
97 tctOrientation = TriCellTable.RIGHT_LEFT;
98 }
99 break;
100 }
101
102 return tctOrientation;
103 }
104
105 private Element[] tds;
106 private Element[] marginTds = null;
107
108 /**
109 * This constructor is called by the non-private constructors to set up
110 * common properties.
111 */
112 private TriCellTable() {
113 super(ElementNames.TABLE);
114
115 addAttribute("border", 0);
116 addAttribute("cellpadding", 0);
117 addAttribute("cellspacing", 0);
118 }
119
120 /**
121 * Creates a two-celled <code>TriCellTable</code>.
122 *
123 * @param conn The connection which is to render the underlying button
124 * object.
125 * @param orientation0_1 The orientation of Element 0 with respect to
126 * Element 1, one of the following values:
127 * <ul>
128 * <li>LEFT_RIGHT (element 0 is to the left of element 1)</li>
129 * <li>RIGHT_LEFT (element 1 is to the left of element 0)</li>
130 * <li>TOP_BOTTOM (element 0 is above element 1)</li>
131 * <li>BOTTOM_TOP (element 1 is above element 0)</li>
132 * </ul>
133 * @param margin0_1 The margin size (in pixels) between element 0 and
134 * element 1.
135 */
136 TriCellTable(Connection conn, int orientation0_1, int margin0_1) {
137 this();
138
139 marginTds = new Element[1];
140 tds = new Element[2];
141 tds[0] = new Element(ElementNames.TD);
142 tds[0].setWhitespaceRelevant(true);
143 tds[1] = new Element(ElementNames.TD);
144 tds[1].setWhitespaceRelevant(true);
145
146 if (margin0_1 > 0) {
147 marginTds[0] = new Element(ElementNames.TD);
148 marginTds[0].setWhitespaceRelevant(true);
149 if ((orientation0_1 & VERTICAL) == 0) {
150 marginTds[0].add(LayoutStrut.createElement(conn, margin0_1, 1));
151 } else {
152 marginTds[0].add(LayoutStrut.createElement(conn, 1, margin0_1));
153 }
154 }
155
156 if ((orientation0_1 & VERTICAL) == 0) {
157 // horizontally oriented
158 Element tr = new Element(ElementNames.TR);
159 if ((orientation0_1 & INVERTED) == 0) {
160 // normal (left to right)
161 addColumn(tr, tds[0]);
162 addColumn(tr, marginTds[0]);
163 addColumn(tr, tds[1]);
164 } else {
165 // inverted (right to left)
166 addColumn(tr, tds[1]);
167 addColumn(tr, marginTds[0]);
168 addColumn(tr, tds[0]);
169 }
170 add(tr);
171 } else {
172 // vertically oriented
173 if ((orientation0_1 & INVERTED) == 0) {
174 // normal (top to bottom)
175 addRow(tds[0]);
176 addRow(marginTds[0]);
177 addRow(tds[1]);
178 } else {
179 // inverted (bottom to top)
180 addRow(tds[1]);
181 addRow(marginTds[0]);
182 addRow(tds[0]);
183 }
184 }
185 }
186
187 /**
188 * Creates a three-celled <code>TriCellTable</code>.
189 *
190 * @param conn The connection which is to render the underlying button
191 * object.
192 * @param orientation0_1 The orientation of Element 0 with respect to
193 * Element 1, one of the following values:
194 * <ul>
195 * <li>LEFT_RIGHT (element 0 is to the left of element 1)</li>
196 * <li>RIGHT_LEFT (element 1 is to the left of element 0)</li>
197 * <li>TOP_BOTTOM (element 0 is above element 1)</li>
198 * <li>BOTTOM_TOP (element 1 is above element 0)</li>
199 * </ul>
200 * @param margin0_1 The margin size (in pixels) between element 0 and
201 * element 1.
202 * @param orientation01_2 The orientation of Elements 0 and 1 with
203 * respect to Element 2, one of the following values:
204 * <ul>
205 * <li>LEFT_RIGHT (elements 0 and 1 are to the left of
206 * element 1)</li>
207 * <li>RIGHT_LEFT (element 2 is to the left of elements 0 and 1)</li>
208 * <li>TOP_BOTTOM (elements 0 and 1 are above element 2)</li>
209 * <li>BOTTOM_TOP (element 2 is above elements 0 and 1)</li>
210 * </ul>
211 * @param margin01_2 The margin size (in pixels) between the combination
212 * of elements 0 and 1 and element 2.
213 * element 1.
214 */
215 TriCellTable(Connection conn, int orientation0_1, int margin0_1, int orientation01_2, int margin01_2) {
216 this();
217
218 Element tr;
219
220 marginTds = new Element[2];
221 tds = new Element[3];
222 tds[0] = new Element(ElementNames.TD);
223 tds[0].setWhitespaceRelevant(true);
224 tds[1] = new Element(ElementNames.TD);
225 tds[1].setWhitespaceRelevant(true);
226 tds[2] = new Element(ElementNames.TD);
227 tds[2].setWhitespaceRelevant(true);
228
229 // Create margin cells
230 if (margin0_1 > 0 || margin01_2 > 0) {
231 if (margin0_1 > 0) {
232 marginTds[0] = new Element(ElementNames.TD);
233 marginTds[0].setWhitespaceRelevant(true);
234 if ((orientation0_1 & VERTICAL) == 0) {
235 marginTds[0].add(LayoutStrut.createElement(conn, margin0_1, 1));
236 } else {
237 marginTds[0].add(LayoutStrut.createElement(conn, 1, margin0_1));
238 }
239 }
240 if (margin01_2 > 0) {
241 marginTds[1] = new Element(ElementNames.TD);
242 marginTds[1].setWhitespaceRelevant(true);
243 if ((orientation01_2 & VERTICAL) == 0) {
244 marginTds[1].add(LayoutStrut.createElement(conn, margin01_2, 1));
245 } else {
246 marginTds[1].add(LayoutStrut.createElement(conn, 1, margin01_2));
247 }
248 }
249 }
250
251 if ((orientation0_1 & VERTICAL) == 0) {
252 // horizontally oriented 0/1
253 if ((orientation01_2 & VERTICAL) == 0) {
254 // horizontally orientated 01/2
255 tr = new Element(ElementNames.TR);
256 if ((orientation01_2 & INVERTED) != 0) {
257 // 2 before 01: render #2 and margin at beginning of TR.
258 addColumn(tr, tds[2]);
259 addColumn(tr, marginTds[1]);
260 }
261
262 // Render 01
263 if ((orientation0_1 & INVERTED) == 0) {
264 // normal (left to right)
265 addColumn(tr, tds[0]);
266 addColumn(tr, marginTds[0]);
267 addColumn(tr, tds[1]);
268 } else {
269 // inverted (right to left)
270 addColumn(tr, tds[1]);
271 addColumn(tr, marginTds[0]);
272 addColumn(tr, tds[0]);
273 }
274
275 if ((orientation01_2 & INVERTED) == 0) {
276 addColumn(tr, marginTds[1]);
277 addColumn(tr, tds[2]);
278 }
279
280 add(tr);
281 } else {
282 // vertically oriented 01/2
283
284 // determine and apply column span based on presence of margin between 0 and 1
285 int columns = margin0_1 > 0 ? 3 : 2;
286 tds[2].addAttribute("colspan", columns);
287 if (marginTds[1] != null) {
288 marginTds[1].addAttribute("colspan", columns);
289 }
290
291 if ((orientation01_2 & INVERTED) != 0) {
292 // 2 before 01: render #2 and margin at beginning of TR.
293 addRow(tds[2]);
294 addRow(marginTds[1]);
295 }
296
297 // Render 01
298 tr = new Element(ElementNames.TR);
299 if ((orientation0_1 & INVERTED) == 0) {
300 // normal (left to right)
301 addColumn(tr, tds[0]);
302 addColumn(tr, marginTds[0]);
303 addColumn(tr, tds[1]);
304 } else {
305 // inverted (right to left)
306 addColumn(tr, tds[1]);
307 addColumn(tr, marginTds[0]);
308 addColumn(tr, tds[0]);
309 }
310 add(tr);
311
312 if ((orientation01_2 & INVERTED) == 0) {
313 // 01 before 2: render margin and #2 at end of TR.
314 addRow(marginTds[1]);
315 addRow(tds[2]);
316 }
317 }
318 } else {
319 // vertically oriented 0/1
320 if ((orientation01_2 & VERTICAL) == 0) {
321 // horizontally orientated 01/2
322
323 // determine and apply row span based on presence of margin between 0 and 1
324 int rows = margin0_1 > 0 ? 3 : 2;
325 tds[2].addAttribute("rowspan", rows);
326 if (marginTds[1] != null) {
327 marginTds[1].addAttribute("rowspan", rows);
328 }
329
330 tr = new Element(ElementNames.TR);
331 if ((orientation01_2 & INVERTED) != 0) {
332 addColumn(tr, tds[2]);
333 addColumn(tr, marginTds[1]);
334 if ((orientation0_1 & INVERTED) == 0) {
335 addColumn(tr, tds[0]);
336 } else {
337 addColumn(tr, tds[1]);
338 }
339 } else {
340 if ((orientation0_1 & INVERTED) == 0) {
341 addColumn(tr, tds[0]);
342 } else {
343 addColumn(tr, tds[1]);
344 }
345 addColumn(tr, marginTds[1]);
346 addColumn(tr, tds[2]);
347 }
348 add(tr);
349 addRow(marginTds[0]);
350 if ((orientation0_1 & INVERTED) == 0) {
351 addRow(tds[1]);
352 } else {
353 addRow(tds[0]);
354 }
355 } else {
356 // vertically oriented 01/2
357 if ((orientation01_2 & INVERTED) != 0) {
358 // 2 before 01: render #2 and margin at beginning of TABLE.
359 addRow(tds[2]);
360 addRow(marginTds[1]);
361 }
362
363 // Render 01
364 if ((orientation0_1 & INVERTED) == 0) {
365 // normal (top to bottom)
366 addRow(tds[0]);
367 addRow(marginTds[0]);
368 addRow(tds[1]);
369 } else {
370 // inverted (bottom to top)
371 addRow(tds[1]);
372 addRow(marginTds[0]);
373 addRow(tds[0]);
374 }
375
376 if ((orientation01_2 & INVERTED) == 0) {
377 // 01 before 2: render margin and #2 at end of TABLE.
378 addRow(marginTds[1]);
379 addRow(tds[2]);
380 }
381 }
382 }
383 }
384
385 /**
386 * Adds an cell element to a table row. The element will not be added
387 * if null is provided for the value of <code>td</code>.
388 *
389 * @param tr The table row to which the cell element is to be added.
390 * @param td The cell element to be added (if not null).
391 */
392 private void addColumn(Element tr, Element td) {
393 if (td != null) {
394 tr.add(td);
395 }
396 }
397
398 /**
399 * Adds an attribute to every table cell in the rendered table.
400 *
401 * @param name The name of the attribute.
402 * @param value The value of the attribute.
403 */
404 public void addGlobalAttribute(String name, String value) {
405 for (int index = 0; index < tds.length; ++index) {
406 tds[index].addAttribute(name, value);
407 }
408 if (marginTds != null) {
409 for (int index = 0; index < marginTds.length; ++index) {
410 if (marginTds[index] != null) {
411 marginTds[index].addAttribute(name, value);
412 }
413 }
414 }
415 }
416
417 /**
418 * Adds a row containing a single column element to a table.
419 * The row will not be added if <code>td</code> is null.
420 *
421 * @param td The cell element to be added.
422 */
423 private void addRow(Element td) {
424 if (td != null) {
425 Element tr = new Element(ElementNames.TR);
426 tr.add(td);
427 add(tr);
428 }
429 }
430
431 /**
432 * Returns the specified container element.
433 *
434 * @param index The index of the table element to return. For two-celled tables,
435 * legitimate values are 0 and 1. For three-celled tables,
436 * legitimate values are 0, 1, and 2.
437 * @return The specified container element.
438 */
439 Element getTdElement(int index) {
440 return tds[index];
441 }
442
443 /**
444 * Returns the specified margin element.
445 *
446 * @param index The index of the table element to return. Index 0 is the margin
447 * element between container cells 0 and 1. Index 1 is the margin
448 * element between container cells 0/1 and 2.
449 * @return The specified margin element. Returns null if the margin is zero
450 * pixels.
451 */
452 Element getMarginTdElement(int index) {
453 return marginTds[index];
454 }
455 }