Initialize
[sdk/ide/product.git] / org.eclipse.jst.pagedesigner / src / org / eclipse / jst / pagedesigner / css2 / layout / CSSBlockFlowLayout.java
1 /*******************************************************************************\r
2  * Copyright (c) 2006 Sybase, Inc. and others.\r
3  *\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     Sybase, Inc. - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.eclipse.jst.pagedesigner.css2.layout;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.List;\r
16 \r
17 import org.eclipse.draw2d.FigureUtilities;\r
18 import org.eclipse.draw2d.Graphics;\r
19 import org.eclipse.draw2d.geometry.Insets;\r
20 import org.eclipse.draw2d.geometry.Rectangle;\r
21 import org.eclipse.jst.pagedesigner.css2.ICSSStyle;\r
22 import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyID;\r
23 import org.eclipse.jst.pagedesigner.css2.property.ICSSPropertyMeta;\r
24 import org.eclipse.jst.pagedesigner.css2.style.ITagEditInfo;\r
25 import org.eclipse.jst.pagedesigner.css2.value.Length;\r
26 import org.eclipse.jst.pagedesigner.css2.widget.BorderUtil;\r
27 import org.eclipse.swt.graphics.FontMetrics;\r
28 \r
29 /**\r
30  * The block layout for {@link CSSFigure}figures. Basic code structure is from\r
31  * BlockFlowLayout.\r
32  * \r
33  * @author mengbo\r
34  */\r
35 public class CSSBlockFlowLayout extends CSSLayout implements ICSSPainter2 {\r
36         private LineBox _previousLine = null;\r
37 \r
38         /**\r
39          * the block box for the layout object\r
40          */\r
41         protected BlockBox _blockBox = null;\r
42 \r
43         /**\r
44          * The font metrics for this layout object\r
45          */\r
46         protected FontMetrics _fontMetrices;\r
47 \r
48         int _userSpecifiedWidth;\r
49 \r
50         int _userSpecifiedHeight;\r
51 \r
52         /*\r
53          * whether we need HScroll and VScroll when overflow is set to "scroll".\r
54          * will be updated in "endBlock" and used in "paintFigurePostClientArea"\r
55          */\r
56         boolean _needHScroll = false;\r
57 \r
58         boolean _needVScroll = false;\r
59 \r
60         /**\r
61      * Creates a new CSSBlockFlowLayout with the given BlockFlow.\r
62          * @param cssfigure\r
63          */\r
64         public CSSBlockFlowLayout(CSSFigure cssfigure) {\r
65                 super(cssfigure);\r
66         }\r
67 \r
68         /**\r
69          * @return true if this layout box has more than one line\r
70          */\r
71         protected boolean hasMoreThanOneLine() {\r
72                 return _previousLine != null;\r
73         }\r
74 \r
75         /**\r
76          * @return true if this layout block is inline\r
77          */\r
78         public boolean isInlineBlock() {\r
79                 String obj = getCSSStyle().getDisplay();\r
80                 return ICSSPropertyID.VAL_INLINE_BLOCK.equals(obj)\r
81                                 || ICSSPropertyID.VAL_INLINE_TABLE.equals(obj);\r
82         }\r
83 \r
84         /**\r
85          * @return true if should expand the width to all available width. \r
86          */\r
87         public boolean shouldExpand() {\r
88                 ICSSStyle style = getCSSStyle();\r
89                 if (style == null) {\r
90                         return false;\r
91                 }\r
92         return "block".equalsIgnoreCase(style.getDisplay()) //$NON-NLS-1$\r
93                         || "list-item".equalsIgnoreCase(style.getDisplay()); //$NON-NLS-1$\r
94         }\r
95 \r
96         // ---------------------------------------------------------------------------------------------------\r
97         // preLayout stage. Major job is get the top-left corner information of the\r
98         // new block.\r
99 \r
100         /**\r
101          * sets up the single block that contains all of the lines.\r
102          */\r
103         protected void setupBlock() {\r
104                 // int recommended = line.getAvailableWidth();\r
105                 // if (recommended != previousRecommendedWidth)\r
106                 // Remove all current Fragments\r
107                 _blockBox.clear();\r
108                 // Ask for a new line, in case we are in the middle of a line\r
109 \r
110                 if (!isInlineBlock()) {\r
111                         LineBox lineBox = getFlowContext().getCurrentLine();\r
112                         if (lineBox != null && !lineBox.isEmptyStringLine()) {\r
113                                 getFlowContext().endLine();\r
114                         }\r
115                 }\r
116 \r
117                 ICSSStyle style = getCSSStyle();\r
118 \r
119                 // endLine will result in context create a new line, so we are in the\r
120                 // new line now.\r
121                 // passing in the top margin, and context will consider that when create\r
122                 // the new line.\r
123                 int marginTop = style.getMarginInsets().top;\r
124                 LineBox line = getFlowContext().getCurrentLine(marginTop);\r
125 \r
126                 // Setup the one fragment for this Block with the correct X and\r
127                 // available width\r
128 \r
129                 // FIXME: according to spec, when using percentage width/height, should\r
130                 // percentage to\r
131                 // the "containing block". But we don't have very good "containing\r
132                 // block" resolution\r
133                 // implementation yet.\r
134 \r
135                 // calculate the min size\r
136                 // int minWidth = 0;\r
137                 // int minHeight = 0;\r
138                 // if (style != null)\r
139                 // {\r
140                 // // try to see whether there is any designer specified min size\r
141                 // ITagEditInfo info = (ITagEditInfo)\r
142                 // style.getAdapter(ITagEditInfo.class);\r
143                 // if (info != null)\r
144                 // {\r
145                 // minWidth = info.getMinWidth();\r
146                 // minHeight = info.getMinHeight();\r
147                 // }\r
148                 //\r
149                 // // CSS also has the min-width/min-height property. We should also get\r
150                 // that,\r
151                 // // and using the max of the "min-width" css property and the designer\r
152                 // specified min size.\r
153                 // int height = getLengthValue(style,ICSSPropertyID.ATTR_MIN_HEIGHT);\r
154                 // if(height > minHeight)\r
155                 // {\r
156                 // minHeight = height;\r
157                 // }\r
158                 // int width = getLengthValue(style,ICSSPropertyID.ATTR_MIN_WIDTH);\r
159                 // if(width > minWidth)\r
160                 // {\r
161                 // minWidth = width;\r
162                 // }\r
163                 // }\r
164 \r
165                 // keep track of user specified size, this will be used when handling\r
166                 // the "overflow" CSS property.\r
167                 _userSpecifiedWidth = 0;\r
168                 _userSpecifiedHeight = 0;\r
169 \r
170                 {\r
171                         int width = getLengthValue(style, ICSSPropertyID.ATTR_WIDTH);\r
172 \r
173                         int availableWidth = line.getAvailableWidth()\r
174                                         - style.getMarginInsets().getWidth();\r
175                         if (width <= 0) {\r
176                                 // no width setting\r
177                                 if (isCalculatingMaxWidth()) {\r
178                                         _blockBox.setRecommendedWidth(Integer.MAX_VALUE);\r
179                                         // _blockBox.setWidth( (minWidth>0?minWidth:0));\r
180                                 } else {\r
181                                         _blockBox.setRecommendedWidth(availableWidth);\r
182                                         if (shouldExpand()) {\r
183                                                 _blockBox.setWidth(availableWidth);\r
184                                         } else {\r
185                                                 // _blockBox.setWidth( (minWidth>0?minWidth:0));\r
186                                         }\r
187                                 }\r
188                         } else {\r
189                                 int w = width;\r
190                                 if (!style.isSizeIncludeBorderPadding()) {\r
191                                         w += style.getBorderInsets().getWidth()\r
192                                                         + style.getPaddingInsets().getWidth();\r
193                                 }\r
194                                 // XXX: should we use minWidth or follow user's choice?\r
195                                 // if (w < minWidth)\r
196                                 // {\r
197                                 // w = minWidth;\r
198                                 // }\r
199                                 _userSpecifiedWidth = w;\r
200                                 _blockBox.setWidth(w);\r
201                                 _blockBox.setRecommendedWidth(w);\r
202                         }\r
203                 }\r
204 \r
205                 {\r
206                         int height = getLengthValue(style, ICSSPropertyID.ATTR_HEIGHT);\r
207                         // Object height =\r
208                         // style.getStyleProperty(ICSSPropertyID.ATTR_HEIGHT);\r
209                         // Length heightLength = (height instanceof Length) ? (Length)\r
210                         // height : null;\r
211 \r
212                         if (height <= 0) {\r
213                                 // if (minHeight > 0)\r
214                                 // {\r
215                                 // // _blockBox.setHeight(minHeight);\r
216                                 // _blockBox.setRecommendedHeight(minHeight);\r
217                                 // }\r
218                                 // else\r
219                                 {\r
220                                         _blockBox.setHeight(0);\r
221                                         _blockBox.setRecommendedHeight(0);\r
222                                 }\r
223                         } else {\r
224                                 int h = height;\r
225                                 if (handlingBorderForBlock()\r
226                                                 && !style.isSizeIncludeBorderPadding()) {\r
227                                         h += style.getBorderInsets().getHeight()\r
228                                                         + style.getPaddingInsets().getHeight();\r
229                                 }\r
230                                 // XXX: should we follow minHeight or user's choice?\r
231                                 // if (minHeight > h)\r
232                                 // {\r
233                                 // h = minHeight;\r
234                                 // }\r
235                                 _userSpecifiedHeight = h;\r
236                                 _blockBox.setHeight(h);\r
237                                 _blockBox.setRecommendedHeight(h);\r
238                         }\r
239                 }\r
240                 _blockBox.setMarginInsets(new Insets(style.getMarginInsets()));\r
241                 if (handlingBorderForBlock()) {\r
242                         BoxUtil.setupBorderPaddingMargin(_blockBox, getCSSStyle());\r
243                 }\r
244 \r
245                 // as in designer, we don't want to the element to have zero size, so\r
246                 // set a minimun size here.\r
247                 // _blockBox.setWidth(Math.max(20, _blockBox.getWidth()));\r
248                 // int minHeight = getCSSStyle().getCSSFont().getFontSize() +\r
249                 // _blockBox.getBorderPaddingHeight();\r
250                 // _blockBox.setHeight(Math.max(minHeight, _blockBox.getHeight()));\r
251 \r
252                 _blockBox._y = line._y;\r
253                 _blockBox._x = line._x;\r
254 \r
255                 setBlockVerticalAlign(_blockBox);\r
256         }\r
257 \r
258         /**\r
259          * @param style\r
260          * @param property\r
261          * @return the length value\r
262          */\r
263         protected int getLengthValue(ICSSStyle style, String property) {\r
264                 int lengthValue = 0;\r
265                 if (style != null) {\r
266                         Object object = style.getStyleProperty(property);\r
267                         Length lengthObj = (object instanceof Length) ? (Length) object\r
268                                         : null;\r
269 \r
270                         if (lengthObj != null) {\r
271                                 lengthValue = lengthObj.getValue();\r
272                                 if (lengthObj.isPercentage()) {\r
273                                         if (ICSSPropertyID.ATTR_WIDTH.equalsIgnoreCase(property)\r
274                                                         || ICSSPropertyID.ATTR_MIN_WIDTH\r
275                                                                         .equalsIgnoreCase(property)) {\r
276                                                 lengthValue = this.getFlowContext().getCurrentLine().getRecommendedContentWidth()\r
277                                                                 * lengthValue / 100;\r
278                                         } else if (ICSSPropertyID.ATTR_HEIGHT\r
279                                                         .equalsIgnoreCase(property)\r
280                                                         || ICSSPropertyID.ATTR_MIN_HEIGHT\r
281                                                                         .equalsIgnoreCase(property)) {\r
282                                                 // XXX: we should omit it because we don't support\r
283                                                 // percentage height now.\r
284                                                 lengthValue = 0;\r
285                                         }\r
286                                 }\r
287                         }\r
288                 }\r
289                 return lengthValue;\r
290         }\r
291 \r
292         private void setBlockVerticalAlign(BlockBox box) {\r
293                 ICSSStyle style = getCSSStyle();\r
294                 if (style != null) {\r
295                         box.setVerticalAlignData(style\r
296                                         .getStyleProperty(ICSSPropertyID.ATTR_VERTICAL_ALIGN));\r
297                 }\r
298         }\r
299 \r
300         /**\r
301          * @see FlowContainerLayout#preLayout()\r
302          */\r
303         protected void preLayout() {\r
304                 super.preLayout();\r
305                 _blockBox = new BlockBox();\r
306                 setupBlock();\r
307                 // Probably could setup current and previous line here, or just previous\r
308         }\r
309 \r
310         // -------------------------------------------------------------------------------------------------------\r
311         /**\r
312          * layout the lines in this layout\r
313          */\r
314         protected void layoutLines() {\r
315                 List lines = _blockBox.getFragments();\r
316                 if (lines != null) {\r
317                         for (int i = 0; i < lines.size(); i++) {\r
318                                 if (lines.get(i) instanceof LineBox) {\r
319                                         layoutLine((LineBox) lines.get(i));\r
320                                 }\r
321                         }\r
322                 }\r
323         }\r
324 \r
325         /**\r
326          * Called by flush(), adds the BlockBox associated with this BlockFlowLayout\r
327          * to the current line and then ends the line.\r
328          */\r
329         protected void endBlock() {\r
330                 layoutLines();\r
331                 ICSSStyle style = getCSSStyle();\r
332                 if (style != null) {\r
333                         int minWidth = 0;\r
334                         int minHeight = 0;\r
335                         // try to see whether there is any designer specified min size\r
336                         ITagEditInfo info = (ITagEditInfo) style\r
337                                         .getAdapter(ITagEditInfo.class);\r
338                         if (info != null) {\r
339                                 minWidth = info.getMinWidth();\r
340                                 minHeight = info.getMinHeight();\r
341                         }\r
342 \r
343                         // CSS also has the min-width/min-height property. We should also\r
344                         // get that,\r
345                         // and using the max of the "min-width" css property and the\r
346                         // designer specified min size.\r
347                         int height = getLengthValue(style, ICSSPropertyID.ATTR_MIN_HEIGHT);\r
348                         if (height > minHeight) {\r
349                                 minHeight = height;\r
350                         }\r
351                         int width = getLengthValue(style, ICSSPropertyID.ATTR_MIN_WIDTH);\r
352                         if (width > minWidth) {\r
353                                 minWidth = width;\r
354                         }\r
355                         if (minHeight > _blockBox.getHeight()) {\r
356                                 _blockBox.setHeight(minHeight);\r
357                         }\r
358                         if (minWidth > _blockBox.getWidth()) {\r
359                                 _blockBox.setWidth(minWidth);\r
360                         }\r
361                 }\r
362 \r
363                 // reset scroll information.\r
364                 this._needHScroll = this._needVScroll = false;\r
365 \r
366                 // ok, now we need to adjust the _blockBox's size according to the\r
367                 // "overflow" setting.\r
368                 // depends on different "overflow" style of this block, different sizing\r
369                 // policy may apply.\r
370                 // ICSSStyle style = this.getCSSStyle();\r
371                 if (style != null) {\r
372                         Object overflow = style\r
373                                         .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);\r
374                         if (ICSSPropertyID.VAL_HIDDEN.equals(overflow)) {\r
375                                 if (_userSpecifiedWidth > 0) {\r
376                                         _blockBox.setWidth(_userSpecifiedWidth);\r
377                                 }\r
378                                 if (_userSpecifiedHeight > 0) {\r
379                                         _blockBox.setHeight(_userSpecifiedHeight);\r
380                                 }\r
381                         } else if (ICSSPropertyID.VAL_SCROLL.equals(overflow)\r
382                                         || ICSSPropertyID.VAL_AUTO.equals(overflow)) {\r
383                                 // adjust _needHScroll and _needVScroll\r
384                                 if (_userSpecifiedWidth > 0\r
385                                                 && _userSpecifiedWidth < _blockBox.getWidth()) {\r
386                                         _needHScroll = true;\r
387                                 }\r
388                                 if (_userSpecifiedHeight > 0\r
389                                                 && _userSpecifiedHeight < _blockBox.getHeight()) {\r
390                                         _needVScroll = true;\r
391                                 }\r
392                                 if (_needHScroll && !_needVScroll) {\r
393                                         if (_userSpecifiedHeight > 0\r
394                                                         && _blockBox.getInternalContentHeight() >= 0\r
395                                                         && _userSpecifiedHeight < _blockBox\r
396                                                                         .getInternalContentHeight()\r
397                                                                         + _blockBox.getPaddingInsets().getHeight()\r
398                                                                         + BorderUtil.SCROLL_WIDTH) {\r
399                                                 _needVScroll = true;\r
400                                         }\r
401                                 }\r
402                                 if (!_needHScroll && _needVScroll) {\r
403                                         if (_userSpecifiedWidth > 0\r
404                                                         && _blockBox.getInternalContentWidth() >= 0\r
405                                                         && _userSpecifiedWidth < _blockBox\r
406                                                                         .getInternalContentWidth()\r
407                                                                         + _blockBox.getPaddingInsets().getWidth()\r
408                                                                         + BorderUtil.SCROLL_WIDTH) {\r
409                                                 _needHScroll = true;\r
410                                         }\r
411                                 }\r
412 \r
413                                 if (_userSpecifiedWidth > 0) {\r
414                                         _blockBox.setWidth(_userSpecifiedWidth);\r
415                                 }\r
416                                 if (_userSpecifiedHeight > 0) {\r
417                                         _blockBox.setHeight(_userSpecifiedHeight);\r
418                                 }\r
419                         }\r
420                 }\r
421 \r
422                 if (getFlowContext().isCurrentLineOccupied()\r
423                                 && getFlowContext().getCurrentLine().getAvailableWidth() < _blockBox._width\r
424                                                 + _blockBox.getMarginInsets().getWidth()) {\r
425                         getFlowContext().endLine();\r
426                 }\r
427                 if (!isInlineBlock()) {\r
428                         LineBox line = getFlowContext().getCurrentLine();\r
429                         line.setHorizonalData(getCSSStyle().getStyleProperty(\r
430                                         ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));\r
431                         line.setHtmlInitData(getCSSStyle().getHTMLelementInitValue(\r
432                                         ICSSPropertyID.ATTR_HORIZONTAL_ALIGN));\r
433                         line.add(_blockBox);\r
434                         // getFlowContext().addToCurrentLine(_blockBox);\r
435                 } else {\r
436                         getFlowContext().addToCurrentLine(_blockBox);\r
437                 }\r
438                 getFlowContext().getCurrentLine().getMarginInsets().bottom = getCSSStyle()\r
439                                 .getMarginInsets().bottom;\r
440 \r
441                 if (!isInlineBlock()) {\r
442                         getFlowContext().endLine();\r
443                 }\r
444         }\r
445 \r
446         /**\r
447          * @param line\r
448          */\r
449         protected void layoutLine(LineBox line) {\r
450                 // currentLine.x = 0; //XXX: comment out, don't understand why set to 0,\r
451                 // because it has already\r
452                 // been set when setupLine(). And if do need, should\r
453                 // set to getBorderPaddingInsets().left\r
454                 // if (!isInlineBlock() && shouldExpand())\r
455                 // {\r
456                 // FIXME: currently we are using getRecommendedContentWidth,\r
457                 // what happen if after adding the new line, the new width is bigger\r
458                 // than\r
459                 // recommendedContentWidth? should we use getWidth() instead of\r
460                 // recommendedcontentWidth?\r
461                 Object textalign = line.getHorizonalData();\r
462                 if (textalign == null\r
463                                 || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {\r
464                         textalign = (getCSSStyle()\r
465                                         .getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));\r
466                 }\r
467                 if (textalign == null\r
468                                 || ICSSPropertyMeta.NOT_SPECIFIED.equals(textalign)) {\r
469                         textalign = line.getHtmlInitData();\r
470                 }\r
471                 if (ICSSPropertyID.VAL_RIGHT.equals(textalign)) {\r
472                         line._x = _blockBox.getContentWidth() - line.getWidth();\r
473                 } else if (ICSSPropertyID.VAL_CENTER.equals(textalign)) {\r
474                         line._x = (_blockBox.getContentWidth() - line.getWidth()) / 2;\r
475                 }\r
476 \r
477                 if (line._x < 0) {\r
478                         line._x = 0;\r
479                 }\r
480                 line.commit();\r
481         }\r
482 \r
483         /**\r
484          * Adjust all fragments in the current line to have the same baseline. Do\r
485          * any additional adjustments, such as horizontal alignment.\r
486          */\r
487         protected void addCurrentLine() {\r
488                 // The follow code is commented out, and moved into layoutLine(line)\r
489                 // called by endBlock().\r
490                 // since only when endBlock is called we really know how big is this\r
491                 // block box, and then can\r
492                 // do horizontal alignment.\r
493                 // // currentLine.x = 0; //XXX: comment out, don't understand why set to\r
494                 // 0, because it has already\r
495                 // // been set when setupLine(). And if do need, should\r
496                 // // set to getBorderPaddingInsets().left\r
497                 // if (!isInlineBlock() && shouldExpand())\r
498                 // {\r
499                 // // FIXME: currently we are using getRecommendedContentWidth,\r
500                 // // what happen if after adding the new line, the new width is bigger\r
501                 // than\r
502                 // // recommendedContentWidth? should we use getWidth() instead of\r
503                 // // recommendedcontentWidth?\r
504                 //\r
505                 // Object textalign =\r
506                 // (getCSSStyle().getStyleProperty(ICSSPropertyID.ATTR_TEXTALIGN));\r
507                 // if (textalign == ICSSPropertyID.VAL_RIGHT)\r
508                 // {\r
509                 // _currentLine._x = _blockBox.getContentWidth() +\r
510                 // _blockBox.getBorderPaddingInsets().left - _currentLine.getWidth();\r
511                 // }\r
512                 // else if (textalign == ICSSPropertyID.VAL_CENTER)\r
513                 // {\r
514                 //\r
515                 // _currentLine._x = _blockBox.getBorderPaddingInsets().left +\r
516                 // (_blockBox.getContentWidth() - _currentLine.getWidth()) / 2;\r
517                 // }\r
518                 // if (_currentLine._x < 0)\r
519                 // _currentLine._x = 0;\r
520                 // }\r
521                 //\r
522                 // // FIXME: should check vertical alignment here?\r
523                 // _currentLine.commit();\r
524 \r
525                 // layoutLine(_currentLine);\r
526                 _blockBox.add(_currentLine);\r
527         }\r
528 \r
529         /**\r
530          * @see FlowContainerLayout#flush()\r
531          */\r
532         protected void flush() {\r
533                 if (_currentLine != null && _currentLine.isOccupied()) {\r
534                         addCurrentLine();\r
535                 }\r
536                 endBlock();\r
537         }\r
538 \r
539         /**\r
540          * @see FlowContainerLayout#cleanup()\r
541          */\r
542         protected void cleanup() {\r
543                 _currentLine = _previousLine = null;\r
544                 _fontMetrices = null;\r
545         }\r
546 \r
547         // ----------------------------------------------------------------------------------\r
548 \r
549         /**\r
550          * Override to setup the line's x, remaining, and available width.\r
551          * \r
552          * @param line\r
553          *            the LineBox to set up\r
554          * @param topMargin \r
555          */\r
556         protected void setupLine(LineBox line, int topMargin) {\r
557                 line.clear();\r
558 \r
559                 // the caller of getCurrentLine() may add leftMargin and leftPadding and\r
560                 // leftBorder to line.x\r
561                 line._x = 0;\r
562 \r
563                 // FIXME: here should check the floating boxes, and minus the width of\r
564                 // them from\r
565                 // current line.\r
566                 line.setRecommendedWidth(_blockBox.getRecommendedContentWidth());\r
567                 if (_previousLine == null) {\r
568                         line._y = 0;\r
569                         if (topMargin != Integer.MIN_VALUE) {\r
570                                 line._y += topMargin;\r
571                         }\r
572                 } else {\r
573                         if (topMargin == Integer.MIN_VALUE) {\r
574                                 line._y = _previousLine._y + _previousLine.getHeight()\r
575                                                 + getLinePadding() + _previousLine.getMarginInsets().bottom; // XXX:\r
576                                 // should\r
577                                 // add\r
578                                 // previous\r
579                                 // margin\r
580                                 // bottom?\r
581                         } else {\r
582                                 line._y = _previousLine._y\r
583                                                 + _previousLine.getHeight()\r
584                                                 + Math.max(topMargin,\r
585                                                                 _previousLine.getMarginInsets().bottom);\r
586                         }\r
587                 }\r
588                 setFontinfoForLine(line);\r
589                 // line.validate();\r
590         }\r
591 \r
592         private void setFontinfoForLine(LineBox line) {\r
593 \r
594                 ICSSStyle style = getCSSStyle();\r
595                 if (style != null) {\r
596                         if (_fontMetrices == null) {\r
597                                 // as getSwtFont is resource consuming, so we cache the\r
598                                 // _fontMetrics.\r
599                                 _fontMetrices = FigureUtilities.getFontMetrics(style\r
600                                                 .getCSSFont().getSwtFont());\r
601                         }\r
602                         line.setFontMetrics(_fontMetrices);\r
603                 }\r
604         }\r
605 \r
606         /**\r
607          * @see FlowContainerLayout#createNewLine()\r
608          */\r
609         protected void createNewLine() {\r
610                 _currentLine = new LineBox();\r
611                 setupLine(_currentLine, Integer.MIN_VALUE);\r
612         }\r
613 \r
614         protected void createNewLine(int topmargin) {\r
615                 _currentLine = new LineBox();\r
616                 setupLine(_currentLine, topmargin);\r
617         }\r
618 \r
619         /**\r
620          * @see FlowContext#endLine()\r
621          */\r
622         public void endLine() {\r
623                 // this is called from child layouts.\r
624                 // If there is no current line, state is equivalent to new line\r
625                 if (_currentLine == null) {\r
626                         return;\r
627                 }\r
628                 if (_currentLine.isOccupied()) {\r
629                         addCurrentLine(); // finalize the current line layout\r
630                 } else {\r
631                         _currentLine = null;\r
632                         return;\r
633                 }\r
634 \r
635                 LineBox box = _currentLine;\r
636                 // _currentLine = _previousLine; //XXX: ???? why (yang)\r
637                 _previousLine = box;\r
638 \r
639                 _currentLine = null;\r
640                 // setupLine(getCurrentLine());\r
641         }\r
642 \r
643         /**\r
644          * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getCurrentY()\r
645          */\r
646         public int getCurrentY() {\r
647                 return getCurrentLine()._y; // FIXME: margin of previous block?\r
648         }\r
649 \r
650         int getLinePadding() {\r
651                 return 0;\r
652         }\r
653 \r
654         /*\r
655          * (non-Javadoc)\r
656          * \r
657          * @see org.eclipse.jst.pagedesigner.css2.layout.CSSLayout#useLocalCoordinates()\r
658          */\r
659         public boolean useLocalCoordinates() {\r
660                 return true;\r
661         }\r
662 \r
663         /*\r
664          * (non-Javadoc)\r
665          * \r
666          * @see org.eclipse.jst.pagedesigner.css2.layout.FlowFigureLayout#dispose()\r
667          */\r
668         public void dispose() {\r
669                 // \r
670         }\r
671 \r
672         /*\r
673          * (non-Javadoc)\r
674          * \r
675          * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#getFragmentsForRead()\r
676          */\r
677         public List getFragmentsForRead() {\r
678                 List r = new ArrayList(1);\r
679                 r.add(_blockBox);\r
680                 return r;\r
681         }\r
682 \r
683         /*\r
684          * (non-Javadoc)\r
685          * \r
686          * @see org.eclipse.jst.pagedesigner.css2.layout.ICSSLayout#postValidate()\r
687          */\r
688         public void postValidate() {\r
689 \r
690                 Rectangle r = new Rectangle(_blockBox._x, _blockBox._y, _blockBox\r
691                                 .getWidth(), _blockBox.getHeight());\r
692                 getCSSFigure().setBounds(r);\r
693                 List list = getCSSFigure().getChildren();\r
694                 for (int i = 0; i < list.size(); i++) {\r
695                         ((FlowFigure) list.get(i)).postValidate();\r
696                 }\r
697         }\r
698 \r
699         /*\r
700          * (non-Javadoc)\r
701          * \r
702          * @see org.eclipse.jst.pagedesigner.css2.layout.FlowContext#getContainerWidth()\r
703          */\r
704         public int getContainerWidth() {\r
705                 int width = Math.max(0, Math.max(_blockBox.getWidth(), _blockBox\r
706                                 .getRecommendedWidth()));\r
707                 return width;\r
708         }\r
709 \r
710         /**\r
711          * when the "overflow" is "scroll", we need to paint the scrollbar\r
712          */\r
713         public void paintFigurePostClientArea(Graphics g) {\r
714                 ICSSStyle style = this.getCSSStyle();\r
715                 if (style != null) {\r
716                         Object overflow = style\r
717                                         .getStyleProperty(ICSSPropertyID.ATTR_OVERFLOW);\r
718                         if (ICSSPropertyID.VAL_SCROLL.equals(overflow)\r
719                                         || ICSSPropertyID.VAL_AUTO.equals(overflow)) {\r
720                                 if (this._needHScroll || this._needVScroll) {\r
721                                         // as this is using localCoordinate, so translate to\r
722                                         // relative to left/up corder of whole\r
723                                         // blockbox.\r
724                                         g.translate(-_blockBox.getBorderPaddingInsets().left,\r
725                                                         -_blockBox.getBorderPaddingInsets().top);\r
726 \r
727                                         Rectangle rect = new Rectangle(0, 0, _blockBox.getWidth(),\r
728                                                         _blockBox.getHeight());\r
729                                         rect.crop(_blockBox.getBorderInsets());\r
730 \r
731                                         if (this._needHScroll && this._needVScroll) {\r
732                                                 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,\r
733                                                                 rect, BorderUtil.BOTH);\r
734                                         } else if (this._needHScroll) {\r
735                                                 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,\r
736                                                                 rect, BorderUtil.HORIZONTAL_BAR);\r
737                                         } else if (this._needVScroll) {\r
738                                                 BorderUtil.drawScrollBar(g, BorderUtil.SCROLL_WIDTH,\r
739                                                                 rect, BorderUtil.VERTICAL_BAR);\r
740                                         }\r
741                                 }\r
742                         }\r
743                 }\r
744         }\r
745 }\r