001    package org.apache.myfaces.tobago.util;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more
005     * contributor license agreements.  See the NOTICE file distributed with
006     * this work for additional information regarding copyright ownership.
007     * The ASF licenses this file to You under the Apache License, Version 2.0
008     * (the "License"); you may not use this file except in compliance with
009     * the License.  You may obtain a copy of the License at
010     *
011     *      http://www.apache.org/licenses/LICENSE-2.0
012     *
013     * Unless required by applicable law or agreed to in writing, software
014     * distributed under the License is distributed on an "AS IS" BASIS,
015     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    import org.apache.commons.lang.builder.ToStringBuilder;
021    import org.slf4j.Logger;
022    import org.slf4j.LoggerFactory;
023    import org.apache.myfaces.tobago.layout.HideLayoutToken;
024    import org.apache.myfaces.tobago.layout.LayoutToken;
025    import org.apache.myfaces.tobago.layout.LayoutTokens;
026    import org.apache.myfaces.tobago.layout.PercentLayoutToken;
027    import org.apache.myfaces.tobago.layout.PixelLayoutToken;
028    import org.apache.myfaces.tobago.layout.RelativeLayoutToken;
029    
030    import java.util.ArrayList;
031    import java.util.List;
032    
033    /**
034     * @deprecated
035     */
036    @Deprecated
037    public class LayoutInfo {
038    
039      private static final Logger LOG = LoggerFactory.getLogger(LayoutInfo.class);
040    
041      private static final int FREE = -1;
042      public static final int HIDE = -2;
043    
044      private int cellsLeft;
045      private int spaceLeft;
046      private int[] spaces;
047      private LayoutTokens layoutTokens;
048      private String clientIdForLogging;
049    
050      public LayoutInfo(int cellCount, int space, LayoutTokens layoutTokens, String clientIdForLogging) {
051        this(cellCount, space, layoutTokens, clientIdForLogging, false);
052      }
053    
054      public LayoutInfo(int cellCount, int space, LayoutTokens layoutTokens,
055          String clientIdForLogging, boolean ignoreMismatch) {
056    
057        this.cellsLeft = cellCount;
058        this.spaceLeft = space;
059        this.layoutTokens = layoutTokens;
060        this.clientIdForLogging = clientIdForLogging;
061        /*if (layoutTokens.length == cellCount) {
062          this.layoutTokens = layoutTokens;
063        } else */
064        if (layoutTokens.getSize() > cellCount) {
065          if (!ignoreMismatch) {
066            LOG.warn("More tokens (" + layoutTokens.getSize()
067                + ") for layout than cells (" + cellCount + ") found! Ignoring"
068                + " redundant tokens. Token string was: "
069                + layoutTokens
070                + " clientId='" + clientIdForLogging + "'");
071          }
072    
073          layoutTokens.shrinkSizeTo(cellCount);
074        } else {
075          if (!ignoreMismatch && LOG.isWarnEnabled() && (cellCount - layoutTokens.getSize()) != 0) {
076            LOG.warn("More cells (" + cellCount + ") than tokens (" + layoutTokens.getSize()
077                + ") for layout found! Setting missing tokens to '1*'."
078                + " Token string was: " + layoutTokens
079                + " clientId='" + clientIdForLogging + "'");
080          }
081          layoutTokens.ensureSize(cellCount, new RelativeLayoutToken(1));
082          //this.layoutTokens = new String[cellCount];
083          //for (int i = 0; i < cellCount; i++) {
084          //  if (i < layoutTokens.length) {
085          //    this.layoutTokens[i] = layoutTokens[i];
086          //  } else {
087          //    this.layoutTokens[i] = "1*";
088          //  }
089          //}
090        }
091        createAndInitSpaces(cellCount, FREE);
092      }
093    
094      private void createAndInitSpaces(int columns, int initValue) {
095        spaces = new int[columns];
096        for (int j = 0; j < spaces.length; j++) {
097          spaces[j] = initValue;
098        }
099      }
100    
101      public void update(int space, int index) {
102        update(space, index, false);
103      }
104    
105      public void update(int space, int index, boolean force) {
106        if (space > spaceLeft) {
107          if (LOG.isDebugEnabled()) {
108            LOG.debug("More space (" + space + ") needed than available (" + spaceLeft + ")!"
109                + " clientId='" + clientIdForLogging + "'");
110          }
111          if (!force) {
112            if (LOG.isDebugEnabled()) {
113              LOG.debug("Cutting to fit. " + " clientId='" + clientIdForLogging + "'");
114            }
115            if (spaceLeft < 0) {
116              space = 0;
117            } else {
118              space = spaceLeft;
119            }
120          }
121        }
122    
123        spaceLeft -= space;
124        cellsLeft--;
125        if (index < spaces.length) {
126          spaces[index] = space;
127          if (spaceLeft < 1 && columnsLeft()) {
128            if (LOG.isWarnEnabled()) {
129              LOG.warn("There are columns left but no more space! cellsLeft="
130                  + cellsLeft + ", tokens=" + layoutTokens
131                  + " clientId='" + clientIdForLogging + "'");
132              LOG.warn("calculated spaces = " + tokensToString(spaces)
133                  + " clientId='" + clientIdForLogging + "'");
134            }
135          }
136        } else {
137          LOG.warn("More space to assign (" + space + "px) but no more columns!"
138              + " More layout tokens than column tags?" + " clientId='" + clientIdForLogging + "'");
139        }
140      }
141    
142      public boolean columnsLeft() {
143        return cellsLeft > 0;
144      }
145    
146    
147      public void handleIllegalTokens() {
148        for (int i = 0; i < spaces.length; i++) {
149          if (isFree(i)) {
150            if (LOG.isWarnEnabled()) {
151              LOG.warn("Illegal layout token pattern \"" + layoutTokens.get(i)
152                  + "\" ignored, set to 0px !" + " clientId='" + clientIdForLogging + "'");
153            }
154            spaces[i] = 0;
155          }
156        }
157      }
158    
159    
160      public static String listToTokenString(List list) {
161        String[] tokens = new String[list.size()];
162        for (int i = 0; i < list.size(); i++) {
163          tokens[i] = list.get(i).toString();
164        }
165        return tokensToString(tokens);
166      }
167    
168      public static String tokensToString(int[] tokens) {
169        String[] strings = new String[tokens.length];
170        for (int i = 0; i < tokens.length; i++) {
171          strings[i] = Integer.toString(tokens[i]);
172        }
173        return tokensToString(strings);
174      }
175    
176      public static String tokensToString(String[] tokens) {
177        StringBuilder sb = new StringBuilder();
178        for (String token : tokens) {
179          if (sb.length() != 0) {
180            sb.append(";");
181          }
182          sb.append(token);
183        }
184        sb.insert(0, "\"");
185        sb.append("\"");
186        return sb.toString();
187      }
188    
189      public boolean isFree(int column) {
190        return spaces[column] == FREE;
191      }
192    
193      public int getSpaceLeft() {
194        return spaceLeft;
195      }
196    
197      public LayoutTokens getLayoutTokens() {
198        return layoutTokens;
199      }
200    
201      public boolean hasLayoutTokens() {
202        return !layoutTokens.isEmpty();
203      }
204    
205      public List<Integer> getSpaceList() {
206        List<Integer> list = new ArrayList<Integer>(spaces.length);
207        for (int space : spaces) {
208          list.add(space);
209        }
210        return list;
211      }
212    
213      public void handleSpaceLeft() {
214        if (spaceLeft > 0) {
215          if (LOG.isDebugEnabled()) {
216            LOG.debug("spread spaceLeft (" + spaceLeft + "px) to columns" + " clientId='" + clientIdForLogging + "'");
217            LOG.debug("spaces before spread :" + arrayAsString(spaces) + " clientId='" + clientIdForLogging + "'");
218          }
219    
220          for (int i = 0; i < layoutTokens.getSize(); i++) {
221            if (layoutTokens.get(i) instanceof RelativeLayoutToken) {
222              addSpace(spaceLeft, i);
223              break;
224            }
225          }
226          boolean found = false;
227          while (spaceLeft > 0) {
228    //        for (int i = 0; i < layoutTokens.length; i++) {
229            for (int i = layoutTokens.getSize() - 1; i > -1; i--) {
230              //String layoutToken = layoutTokens[i];
231              if (spaceLeft > 0 && layoutTokens.get(i) instanceof RelativeLayoutToken) {
232                found = true;
233                addSpace(1, i);
234              }
235            }
236            if (!found) {
237              break;
238            }
239          }
240        }
241        if (spaceLeft > 0 && LOG.isWarnEnabled()) {
242          LOG.warn("Space left after spreading : " + spaceLeft + "px!" + " clientId='" + clientIdForLogging + "'");
243        }
244        if (LOG.isDebugEnabled()) {
245          LOG.debug("spaces after spread  :" + arrayAsString(spaces) + " clientId='" + clientIdForLogging + "'");
246        }
247      }
248    
249      //TODO replace with Arrays.asList ..
250      private String arrayAsString(int[] currentSpaces) {
251        StringBuilder sb = new StringBuilder("[");
252        for (int currentSpace : currentSpaces) {
253          sb.append(currentSpace);
254          sb.append(", ");
255        }
256        sb.replace(sb.lastIndexOf(", "), sb.length(), "]");
257        return sb.toString();
258      }
259    
260      private void addSpace(int space, int i) {
261        if (spaces[i] > HIDE) {
262          if (spaces[i] == FREE) {
263            spaces[i] = space;
264          } else {
265            spaces[i] += space;
266          }
267          spaceLeft -= space;
268        }
269      }
270    
271    
272      private void parsePortions(int portions) {
273        if (columnsLeft()) {
274    
275          //  2. calc and set portion
276          if (portions > 0) {
277            int widthForPortions = getSpaceLeft();
278            for (int i = 0; i < layoutTokens.getSize(); i++) {
279              LayoutToken token = layoutTokens.get(i);
280              if (isFree(i) && token instanceof RelativeLayoutToken) {
281                int portion = ((RelativeLayoutToken) token).getFactor();
282                float w = (float) widthForPortions / portions * portion;
283                if (w < 0) {
284                  update(0, i);
285                  if (LOG.isDebugEnabled()) {
286                    LOG.debug("set column " + i + " from " + token
287                        + " to with " + w + " == 0px" + " clientId='" + clientIdForLogging + "'");
288                  }
289                } else {
290                  update(Math.round(w), i);
291                  if (LOG.isDebugEnabled()) {
292                    LOG.debug("set column " + i + " from " + token
293                        + " to with " + w + " == " + Math.round(w) + "px" + " clientId='" + clientIdForLogging + "'");
294                  }
295                }
296              }
297            }
298          }
299        }
300      }
301    
302    /*
303      public void parseAsterisks() {
304        String[] tokens = getLayoutTokens();
305        if (columnsLeft()) {
306          //  1. count unset columns
307          int portions = 0;
308          for (int i = 0; i < tokens.length; i++) {
309            if (isFree(i) && tokens[i].equals("*")) {
310              portions++;
311            }
312          }
313          //  2. calc and set portion
314          int widthPerPortion;
315          if (portions > 0) {
316            widthPerPortion = getSpaceLeft() / portions;
317            for (int i = 0; i < tokens.length; i++) {
318              if (isFree(i) && tokens[i].equals("*")) {
319                int w = widthPerPortion;
320                update(w, i);
321                if (LOG.isDebugEnabled()) {
322                  LOG.debug("set column " + i + " from " + tokens[i]
323                      + " to with " + w);
324                }
325              }
326            }
327          }
328        }
329      }
330    */
331    
332      public void parseColumnLayout(double space) {
333        parseColumnLayout(space, 0);
334      }
335    
336      public void parseColumnLayout(double space, int padding) {
337    
338        if (hasLayoutTokens()) {
339          int portions = 0;
340          for (int i = 0; i < layoutTokens.getSize(); i++) {
341            LayoutToken token = layoutTokens.get(i);
342            if (token instanceof HideLayoutToken) {
343              update(0, i);
344              spaces[i] = HIDE;
345              if (LOG.isDebugEnabled()) {
346                LOG.debug("set column " + i + " from " + layoutTokens.get(i)
347                    + " to hide " + " clientId='" + clientIdForLogging + "'");
348              }
349            } else if (token instanceof PixelLayoutToken) {
350              int w = ((PixelLayoutToken) token).getPixel();
351              update(w, i, true);
352              if (LOG.isDebugEnabled()) {
353                LOG.debug("set column " + i + " from " + token
354                    + " to with " + w + " clientId='" + clientIdForLogging + "'");
355              }
356            } else if (token instanceof RelativeLayoutToken) {
357              portions += ((RelativeLayoutToken) token).getFactor();
358            } else if (token instanceof PercentLayoutToken) {
359              int percent = ((PercentLayoutToken) token).getPercent();
360              int w = (int) (space / 100 * percent);
361              update(w, i);
362              if (LOG.isDebugEnabled()) {
363                LOG.debug("set column " + i + " from " + token
364                    + " to with " + w + " clientId='" + clientIdForLogging + "'");
365              }
366            }
367          }
368          parsePortions(portions);
369    //      parseAsterisks();
370          handleSpaceLeft();
371        }
372    
373        if (columnsLeft() && LOG.isWarnEnabled()) {
374          handleIllegalTokens();
375        }
376      }
377    
378      public String toString() {
379        return new ToStringBuilder(this).
380            append("cellLeft", cellsLeft).
381            append("spaceLeft", spaceLeft).
382            append("spaces", spaces).
383            append("layoutTokens", layoutTokens).
384            toString();
385      }
386    }
387