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  
20  package org.apache.myfaces.tobago.internal.layout;
21  
22  import org.apache.myfaces.tobago.layout.Measure;
23  import org.apache.myfaces.tobago.layout.MeasureList;
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import java.lang.invoke.MethodHandles;
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  /**
32   * @deprecated since 4.0.0
33   */
34  @Deprecated
35  public class Grid {
36  
37    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
38  
39    // TODO: check if it is faster with arrays.
40    /**
41     * The rectangular data as a 1-dim list
42     */
43    private List<Cell> cells;
44  
45    private MeasureList columns;
46    private MeasureList rows;
47  
48    private int columnCount;
49    private int rowCount;
50  
51    private int columnCursor;
52    private int rowCursor;
53  
54    private List<Integer> errorIndexes;
55  
56    public Grid(final MeasureList columns, final MeasureList rows) {
57      assert columns.getSize() > 0;
58      assert rows.getSize() > 0;
59  
60      this.columnCount = columns.getSize();
61      this.rowCount = rows.getSize();
62  
63      this.columns = columns;
64      this.rows = rows;
65  
66      final int size = columnCount * rowCount;
67      this.cells = new ArrayList<>(size);
68      for (int i = 0; i < size; i++) {
69        this.cells.add(null);
70      }
71    }
72  
73    public void add(final OriginCell cell, final int columnSpan, final int rowSpan) {
74  
75      assert columnSpan > 0;
76      assert rowSpan > 0;
77  
78      int iterator = columnSpan;
79      boolean error = false;
80  
81      if (iterator + columnCursor > columnCount) {
82        LOG.warn("The columnSpan is to large for the actual position in the grid. Will be fixed. "
83            + "columnSpan='" + iterator + "' columnCursor='" + columnCursor + "' columnCount='" + columnCount + "'");
84        iterator = columnCount - columnCursor;
85        error = true;
86      }
87  
88      cell.setColumnSpan(iterator);
89      cell.setRowSpan(rowSpan);
90  
91      for (int i = 1; i < iterator; i++) {
92        if (getCell(i + columnCursor, rowCursor) != null) {
93          LOG.warn("The columnSpan is to large for the actual position in the grid. Will be fixed. "
94              + "columnSpan='" + iterator + "' columnCursor='" + columnCursor + "' columnCount='" + columnCount + "'");
95          iterator = i - 1;
96          error = true;
97        }
98      }
99  
100     for (int j = 0; j < rowSpan; j++) {
101       for (int i = 0; i < iterator; i++) {
102         final Cell actualCell;
103         if (i == 0 && j == 0) {
104           actualCell = cell;
105         } else {
106           actualCell = new SpanCell(cell, i == 0, j == 0);
107         }
108         assert getCell(i + columnCursor, j + rowCursor) == null : "Position in the cell must be free.";
109         setCell(i + columnCursor, j + rowCursor, actualCell);
110         if (error) {
111           addError(i + columnCursor, j + rowCursor);
112         }
113       }
114     }
115 
116     findNextFreeCell();
117   }
118 
119   public Cell getCell(final int column, final int row) {
120     assert column >= 0 && column < columnCount : "column=" + column + " columnCount=" + columnCount;
121     assert row >= 0 : "row=" + row;
122 
123     if (row >= rowCount) {
124       return null;
125     } else {
126       return cells.get(column + row * columnCount);
127     }
128   }
129 
130   public void setCell(final int column, final int row, final Cell cell) {
131     if (row >= rowCount) {
132       enlarge(row - rowCount + 1);
133     }
134     cells.set(column + row * columnCount, cell);
135   }
136 
137   private void findNextFreeCell() {
138     for (; rowCursor < rowCount; rowCursor++) {
139       for (; columnCursor < columnCount; columnCursor++) {
140         if (getCell(columnCursor, rowCursor) == null) {
141           return;
142         }
143       }
144       columnCursor = 0;
145     }
146   }
147 
148   protected MeasureList getColumns() {
149     return columns;
150   }
151 
152   protected MeasureList getRows() {
153     return rows;
154   }
155 
156   private void enlarge(final int newRows) {
157 
158     // process cells
159     for (int i = 0; i < newRows; i++) {
160       for (int j = 0; j < columnCount; j++) {
161         cells.add(null);
162       }
163     }
164 
165     // process heads
166     for (int i = rowCount; i < rowCount + newRows; i++) {
167       rows.add(Measure.FRACTION1);
168     }
169 
170     rowCount += newRows;
171   }
172 
173   public void addError(final int i, final int j) {
174     if (errorIndexes == null) {
175       errorIndexes = new ArrayList<>();
176     }
177     errorIndexes.add(j * columnCount + i);
178   }
179 
180   public boolean hasError(final int i, final int j) {
181     if (errorIndexes == null) {
182       return false;
183     }
184     return errorIndexes.contains(j * columnCount + i);
185   }
186 
187   public int getColumnCount() {
188     return columnCount;
189   }
190 
191   public int getRowCount() {
192     return rowCount;
193   }
194 
195   /**
196    * Prints the state of the grid as an Unicode shape like this:
197    * ┏━┳━┳━┳━┯━┓
198    * ┃█┃█┃█┃█│➞┃
199    * ┠─╂─╊━╇━┿━┫
200    * ┃⬇┃⬇┃█│➞│➞┃
201    * ┣━╉─╊━╈━╈━┫
202    * ┃█┃⬇┃█┃█┃█┃
203    * ┣━╇━╇━╉─╊━┩
204    * ┃█│➞│➞┃⬇┃◌│
205    * ┡━┿━┿━╉─╂─┤
206    * │◌│◌│◌┃⬇┃◌│
207    * └─┴─┴─┺━┹─┘
208    */
209   public String gridAsString() {
210 
211     final StringBuilder builder = new StringBuilder();
212 
213     // top of grid
214     for (int i = 0; i < columnCount; i++) {
215       if (i == 0) {
216         if (getCell(i, 0) != null) {
217           builder.append("┏");
218         } else {
219           builder.append("┌");
220         }
221       } else {
222         final Cell c = getCell(i - 1, 0);
223         final Cell d = getCell(i, 0);
224         if (c == null && d == null) {
225           builder.append("┬");
226         } else {
227           if (connected(c, d)) {
228             builder.append("┯");
229           } else {
230             if (c == null) {
231               builder.append("┲");
232             } else if (d == null) {
233               builder.append("┱");
234             } else {
235               builder.append("┳");
236             }
237           }
238         }
239       }
240       if (getCell(i, 0) != null) {
241         builder.append("━");
242       } else {
243         builder.append("─");
244       }
245 
246     }
247     if (getCell(columnCount - 1, 0) != null) {
248       builder.append("┓");
249     } else {
250       builder.append("┐");
251     }
252     builder.append("\n");
253 
254     for (int j = 0; j < rowCount; j++) {
255 
256       // between the cells
257       if (j != 0) {
258         for (int i = 0; i < columnCount; i++) {
259           if (i == 0) {
260             final Cell b = getCell(0, j - 1);
261             final Cell d = getCell(0, j);
262             if (b == null && d == null) {
263               builder.append("├");
264             } else {
265               if (connected(b, d)) {
266                 builder.append("┠");
267               } else {
268                 if (b == null) {
269                   builder.append("┢");
270                 } else if (d == null) {
271                   builder.append("┡");
272                 } else {
273                   builder.append("┣");
274                 }
275               }
276             }
277           } else {
278             final Cell a = getCell(i - 1, j - 1);
279             final Cell b = getCell(i, j - 1);
280             final Cell c = getCell(i - 1, j);
281             final Cell d = getCell(i, j);
282 //            a│b
283 //            ─┼─
284 //            c│d
285             if (connected(a, b)) {
286               if (connected(c, d)) {
287                 if (connected(a, c)) {
288                   builder.append("┼");
289                 } else {
290                   builder.append("┿");
291                 }
292               } else {
293                 builder.append("╈");
294               }
295             } else {
296               if (connected(c, d)) {
297                 if (connected(a, c)) {
298                   builder.append("╄");
299                 } else if (connected(b, d)) {
300                   builder.append("╃");
301                 } else {
302                   builder.append("╇");
303                 }
304               } else {
305                 if (connected(a, c)) {
306                   if (connected(b, d)) {
307                     builder.append("╂");
308                   } else {
309                     builder.append("╊");
310                   }
311                 } else {
312                   if (connected(b, d)) {
313                     builder.append("╉");
314                   } else {
315                     builder.append("╋");
316                   }
317                 }
318               }
319             }
320           }
321           final Cell a = getCell(i, j - 1);
322           final Cell c = getCell(i, j);
323           if (connected(a, c)) {
324             builder.append("─");
325           } else {
326             builder.append("━");
327           }
328         }
329         final Cell a = getCell(columnCount - 1, j - 1);
330         final Cell c = getCell(columnCount - 1, j);
331         if (a == null && c == null) {
332           builder.append("┤");
333         } else {
334           if (connected(a, c)) {
335             builder.append("┨");
336           } else {
337             if (a == null) {
338               builder.append("┪");
339             } else if (c == null) {
340               builder.append("┩");
341             } else {
342               builder.append("┫");
343             }
344           }
345         }
346         builder.append("\n");
347       }
348 
349       // cell
350       for (int i = 0; i < columnCount; i++) {
351         if (i == 0) {
352           if (getCell(i, j) != null) {
353             builder.append("┃");
354           } else {
355             builder.append("│");
356           }
357         } else {
358           final Cell c = getCell(i - 1, j);
359           final Cell d = getCell(i, j);
360           if (connected(c, d)) {
361             builder.append("│");
362           } else {
363             builder.append("┃");
364           }
365         }
366         if (hasError(i, j)) {
367           builder.append("✖"); //↯
368         } else {
369           if (getCell(i, j) instanceof OriginCell) {
370             builder.append("█");
371           } else if (getCell(i, j) instanceof SpanCell) {
372             if (j == 0) {
373               builder.append("➞");
374             } else {
375               final Cell a = getCell(i, j - 1);
376               final Cell c = getCell(i, j);
377               if (connected(a, c)) {
378                 builder.append("⬇");
379               } else {
380                 builder.append("➞");
381               }
382             }
383           } else {
384             builder.append("◌");
385           }
386         }
387       }
388       if (getCell(columnCount - 1, j) != null) {
389         builder.append("┃");
390       } else {
391         builder.append("│");
392       }
393       builder.append("\n");
394     }
395 
396     //last bottom
397     for (int i = 0; i < columnCount; i++) {
398       if (i == 0) {
399         if (getCell(0, rowCount - 1) != null) {
400           builder.append("┗");
401         } else {
402           builder.append("└");
403         }
404       } else {
405         final Cell a = getCell(i - 1, rowCount - 1);
406         final Cell b = getCell(i, rowCount - 1);
407         if (a == null && b == null) {
408           builder.append("┴");
409         } else {
410           if (connected(a, b)) {
411             builder.append("┷");
412           } else {
413             if (a == null) {
414               builder.append("┺");
415             } else if (b == null) {
416               builder.append("┹");
417             } else {
418               builder.append("┻");
419             }
420           }
421         }
422       }
423       if (getCell(i, rowCount - 1) != null) {
424         builder.append("━");
425       } else {
426         builder.append("─");
427       }
428     }
429     if (getCell(columnCount - 1, rowCount - 1) != null) {
430       builder.append("┛");
431     } else {
432       builder.append("┘");
433     }
434     builder.append("\n");
435 
436     return builder.toString();
437   }
438 
439   @Override
440   public String toString() {
441     return gridAsString() + "columns=" + columns + '\n' + "rows=" + rows + "\n";
442   }
443 
444   private boolean connected(final Cell a, final Cell b) {
445     if (a == null && b == null) {
446       return true;
447     }
448     if (a == null || b == null) {
449       return false;
450     }
451     return a.getOrigin().equals(b.getOrigin());
452   }
453 }