KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lobobrowser > html > renderer > RBlock


1 /*
2     GNU LESSER GENERAL PUBLIC LICENSE
3     Copyright (C) 2006 The Lobo Project
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19     Contact info: xamjadmin@users.sourceforge.net
20 */

21 /*
22  * Created on Apr 16, 2005
23  */

24 package org.lobobrowser.html.renderer;
25
26 import java.util.*;
27 import java.util.logging.*;
28
29 import java.awt.*;
30 import java.awt.event.*;
31
32 import javax.swing.*;
33 import java.awt.image.ImageObserver JavaDoc;
34
35 import org.lobobrowser.html.*;
36 import org.lobobrowser.html.domimpl.*;
37 import org.lobobrowser.html.style.*;
38 import org.lobobrowser.util.*;
39 import org.w3c.dom.Node JavaDoc;
40
41 /**
42  * @author J. H. S.
43  */

44 public class RBlock extends BaseElementRenderable implements RenderableContainer, ImageObserver JavaDoc {
45     static final Logger logger = Logger.getLogger(RBlock.class.getName());
46     private static final boolean loggableInfo = logger.isLoggable(Level.INFO);
47     private static final FloatingBounds INVALID_FLOAT_BOUNDS = new FloatingViewportBounds(null, 0, 0, 0, 0);
48     
49     protected final FrameContext frameContext;
50     protected final int listNesting;
51     protected final HtmlRendererContext rendererContext;
52     protected final int defaultOverflow;
53     protected final RBlockViewport bodyLayout;
54
55     protected RenderableSpot startSelection;
56     protected RenderableSpot endSelection;
57     
58     protected JScrollBar vScrollBar;
59     protected JScrollBar hScrollBar;
60     protected boolean hasHScrollBar = false;
61     protected boolean hasVScrollBar = false;
62
63
64     // Validation-dependent variables...
65
//private Dimension layoutSize = null;
66
private Boolean JavaDoc lastExpandWidth = null;
67     private Boolean JavaDoc lastExpandHeight = null;
68     private int lastAvailHeight = -1;
69     private int lastAvailWidth = -1;
70     private int lastWhiteSpace = -1;
71     private FloatingBounds lastFloatBounds = INVALID_FLOAT_BOUNDS;
72     private Font lastFont = null;
73
74     public RBlock(NodeImpl modelNode, int listNesting, UserAgentContext pcontext, HtmlRendererContext rcontext, FrameContext frameContext, RenderableContainer parentContainer) {
75         this(modelNode, listNesting, pcontext, rcontext, frameContext, parentContainer, RBlock.OVERFLOW_NONE);
76     }
77     
78     public RBlock(NodeImpl modelNode, int listNesting, UserAgentContext pcontext, HtmlRendererContext rcontext, FrameContext frameContext, RenderableContainer parentContainer, int defaultOverflow) {
79         super(parentContainer, modelNode, pcontext);
80         this.listNesting = listNesting;
81         this.frameContext = frameContext;
82         this.rendererContext = rcontext;
83         this.defaultOverflow = defaultOverflow;
84         RBlockViewport bl = new RBlockViewport(modelNode, this, this.getViewportListNesting(listNesting), pcontext, rcontext, frameContext, this);
85         this.bodyLayout = bl;
86         bl.setOriginalParent(this);
87         // Initialize origin of RBlockViewport to be as far top-left as possible.
88
// This will be corrected on first layout.
89
bl.setX(Short.MAX_VALUE);
90         bl.setY(Short.MAX_VALUE);
91     }
92             
93     /**
94      * Gets the width the vertical scrollbar has when shown.
95      */

96     public int getVScrollBarWidth() {
97         return SCROLL_BAR_THICKNESS;
98     }
99     
100     public void finalize() throws Throwable JavaDoc {
101         super.finalize();
102     }
103     
104     public int getVAlign() {
105         // Not used
106
return VALIGN_BASELINE;
107     }
108
109     public void ensureVisible(Point point) {
110         RBlockViewport bodyLayout = this.bodyLayout;
111         if(bodyLayout != null) {
112             boolean hscroll = this.hasHScrollBar;
113             boolean vscroll = this.hasVScrollBar;
114             int origX = bodyLayout.x;
115             int origY = bodyLayout.y;
116             Insets insets = this.getInsets(hscroll, vscroll);
117             if(hscroll) {
118                 if(point.x < insets.left) {
119                     bodyLayout.x += (insets.left - point.x);
120                 }
121                 else if(point.x > this.width - insets.right) {
122                     bodyLayout.x -= (point.x - this.width + insets.right);
123                 }
124             }
125             if(vscroll) {
126                 if(point.y < insets.top) {
127                     bodyLayout.y += (insets.top - point.y);
128                 }
129                 else if(point.y > this.height - insets.bottom) {
130                     bodyLayout.y -= (point.y - this.height + insets.bottom);
131                 }
132             }
133             if(hscroll || vscroll) {
134                 this.correctViewportOrigin(insets, this.width, this.height);
135                 if(origX != bodyLayout.x || origY != bodyLayout.y) {
136                     this.resetScrollBars(null);
137                     //TODO: This could be paintImmediately.
138
this.repaint();
139                 }
140             }
141         }
142     }
143     
144     private JScrollBar getHScrollBar() {
145         JScrollBar sb = this.hScrollBar;
146         if(sb == null) {
147             // Should never go back to null
148
sb = new JScrollBar(JScrollBar.HORIZONTAL);
149             sb.addAdjustmentListener(new LocalAdjustmentListener(JScrollBar.HORIZONTAL));
150             this.hScrollBar = sb;
151         }
152         return sb;
153     }
154         
155     private JScrollBar getVScrollBar() {
156         JScrollBar sb = this.vScrollBar;
157         if(sb == null) {
158             // Should never go back to null
159
sb = new JScrollBar(JScrollBar.VERTICAL);
160             sb.addAdjustmentListener(new LocalAdjustmentListener(JScrollBar.VERTICAL));
161             this.vScrollBar = sb;
162         }
163         return sb;
164     }
165
166     public final boolean couldBeScrollable() {
167         int overflow = this.getOverflow();
168         return overflow != OVERFLOW_NONE && (overflow == OVERFLOW_SCROLL || overflow == OVERFLOW_VERTICAL || overflow == OVERFLOW_AUTO);
169     }
170     
171     private Insets defaultPaddingInsets = null;
172     
173     public void setDefaultPaddingInsets(Insets insets) {
174         this.defaultPaddingInsets = insets;
175     }
176     
177     public void setDefaultMarginInsets(Insets insets) {
178         this.defaultMarginInsets = insets;
179     }
180
181     public int getFirstLineHeight() {
182         return this.bodyLayout.getFirstLineHeight();
183     }
184
185     public void setSelectionEnd(RenderableSpot rpoint) {
186         this.endSelection = rpoint;
187     }
188     
189     public void setSelectionStart(RenderableSpot rpoint) {
190         this.startSelection = rpoint;
191     }
192     
193     protected final Insets getPaddingInsets(RenderState rs) {
194         Insets mi = rs.getPaddingInsets();
195         if(mi == null) {
196             return this.defaultPaddingInsets;
197         }
198         return mi;
199     }
200
201     public int getViewportListNesting(int blockNesting) {
202         return blockNesting;
203     }
204
205     public void paint(Graphics g) {
206         boolean linfo = loggableInfo;
207         long time1 = linfo ? System.currentTimeMillis() : 0;
208         this.prePaint(g);
209         long time2 = linfo ? System.currentTimeMillis() : 0;
210         long time3 = 0;
211         try {
212             Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
213             RBlockViewport bodyLayout = this.bodyLayout;
214             if(bodyLayout != null) {
215                 int overflow = this.getOverflow();
216                 if(overflow == OVERFLOW_NONE || overflow == OVERFLOW_VISIBLE) {
217                     // Simply translate.
218
int bx = bodyLayout.x;
219                     int by = bodyLayout.y;
220                     g.translate(bx, by);
221                     try {
222                         bodyLayout.paint(g);
223                     } finally {
224                         g.translate(-bx, -by);
225                     }
226                 }
227                 else {
228                     // Clip when there potential scrolling or hidden overflow was requested.
229
Graphics newG = g.create(insets.left, insets.top, this.width - insets.left - insets.right, this.height - insets.top - insets.bottom);
230                     try {
231                         // Second, translate
232
newG.translate(bodyLayout.x - insets.left, bodyLayout.y - insets.top);
233                         // Third, paint in clipped + translated region.
234
bodyLayout.paint(newG);
235                     } finally {
236                         newG.dispose();
237                     }
238                 }
239
240                 if(linfo) {
241                     time3 = System.currentTimeMillis();
242                 }
243             } else {
244                 // nop
245
}
246
247             // Paint FrameContext selection.
248
// This is only done by root RBlock.
249

250             RenderableSpot start = this.startSelection;
251             RenderableSpot end = this.endSelection;
252             boolean inSelection = false;
253             if(start != null && end != null && !start.equals(end)) {
254                 this.paintSelection(g, inSelection, start, end);
255             }
256             // Must paint scrollbars too.
257
JScrollBar hsb = this.hScrollBar;
258             if(hsb != null) {
259                 Graphics sbg = g.create(insets.left, this.height - insets.bottom, this.width - insets.left - insets.right, SCROLL_BAR_THICKNESS);
260                 try {
261                     hsb.paint(sbg);
262                 } finally {
263                     sbg.dispose();
264                 }
265             }
266             JScrollBar vsb = this.vScrollBar;
267             if(vsb != null) {
268                 Graphics sbg = g.create(this.width - insets.right, insets.top, SCROLL_BAR_THICKNESS, this.height - insets.top - insets.bottom);
269                 try {
270                     vsb.paint(sbg);
271                 } finally {
272                     sbg.dispose();
273                 }
274             }
275
276         } finally {
277             // Must always call super implementation
278
super.paint(g);
279         }
280         if(linfo) {
281             long time4 = System.currentTimeMillis();
282             if(time4 - time1 > 100) {
283                 logger.info("paint(): Elapsed: " + (time4 - time1) + " ms. Prepaint: " + (time2 - time1) + " ms. Viewport: " + (time3 - time2) + " ms. RBlock: " + this + ".");
284             }
285         }
286     }
287             
288     /**
289      * @param width The width available, including insets.
290      * @param height The height available, including insets.
291      */

292     protected Dimension doCellLayout(int width, int height, boolean expandWidth, boolean expandHeight) {
293         try {
294             this.doLayout(width, height, expandWidth, expandHeight);
295             return new Dimension(this.width, this.height);
296         } finally {
297             this.layoutUpTreeCanBeInvalidated = true;
298         }
299     }
300         
301     public final void layout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, int defaultOverflow) {
302         this.layout(availWidth, availHeight, expandWidth, expandHeight, null, 0, defaultOverflow);
303     }
304
305     public final void layout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, FloatingBounds floatBounds, int tentativeY) {
306         this.layout(availWidth, availHeight, expandWidth, expandHeight, floatBounds, tentativeY, this.defaultOverflow);
307     }
308
309     public final void layout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, FloatingBounds floatBounds, int tentativeY, int defaultOverflow) {
310         try {
311             this.doLayout(availWidth, availHeight, expandWidth, expandHeight, floatBounds, tentativeY, defaultOverflow);
312         } finally {
313             this.layoutUpTreeCanBeInvalidated = true;
314             this.layoutDeepCanBeInvalidated = true;
315 // this.renderStyleCanBeInvalidated = true;
316
}
317     }
318
319     public final void doLayout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight) {
320         this.doLayout(availWidth, availHeight, expandWidth, expandHeight, null, 0, this.defaultOverflow);
321     }
322
323     public final void doLayout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, int tentativeY) {
324         this.doLayout(availWidth, availHeight, expandWidth, expandHeight, null, tentativeY, this.defaultOverflow);
325     }
326
327     /**
328      * Lays out and sets dimensions only if RBlock is invalid (or never before
329      * layed out), if the parameters passed differ from the last layout, or
330      * if the current font differs from the font for the last layout.
331      * @param availWidth
332      * @param availHeight
333      */

334     public void doLayout(int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, FloatingBounds floatBounds, int tentativeY, int defaultOverflow) {
335         // Expected to be invoked in the GUI thread.
336
int prevAvailWidth = this.lastAvailWidth;
337         int prevAvailHeight = this.lastAvailHeight;
338         RenderState renderState = this.modelNode.getRenderState();
339         boolean forced = availHeight != prevAvailHeight || availWidth != prevAvailWidth || !Boolean.valueOf(expandWidth).equals(this.lastExpandWidth) || !Boolean.valueOf(expandHeight).equals(this.lastExpandHeight);
340         if(!forced) {
341             if(renderState != null) {
342                 Font font = renderState.getFont();
343                 if(!font.equals(this.lastFont)) {
344                     forced = true;
345                 }
346                 else {
347                     int newWhiteSpace = renderState.getWhiteSpace();
348                     if(newWhiteSpace != this.lastWhiteSpace) {
349                         forced = true;
350                     }
351                 }
352             }
353             if(!forced) {
354                 if(this.lastFloatBounds == INVALID_FLOAT_BOUNDS) {
355                     forced = true;
356                 }
357                 else {
358                     forced = !Objects.equals(this.lastFloatBounds, floatBounds);
359                 }
360             }
361         }
362         if(forced) {
363             this.forceLayout(renderState, availWidth, availHeight, expandWidth, expandHeight, floatBounds, tentativeY, defaultOverflow);
364         }
365         else {
366             // nothing to do
367
}
368         
369 // // Even if we didn't do layout, it is essential
370
// // to add exported renderables in ancestors.
371
// //TODO: Repace float mechanism with delayed pairs.
372
// RBlockViewport localTarget = this.bodyLayout;
373
// Iterator eri = localTarget.getExportedRenderables();
374
// if(eri != null) {
375
// while(eri.hasNext()) {
376
// ExportedRenderable er = (ExportedRenderable) eri.next();
377
// RBlockViewport parentViewport = localTarget.getParentViewport(er);
378
// if(parentViewport == null) {
379
// localTarget.importRenderable(er);
380
// }
381
// else if(parentViewport.isImportable(er)) {
382
// parentViewport.importRenderable(er);
383
// }
384
// else {
385
// // Must be scheduled at each level of the hierarchy,
386
// // otherwise it could be lost when layout is valid.
387
// parentViewport.addToExportedRenderables(er);
388
// }
389
// }
390
// }
391

392         // Even if we didn't do layout, the parent is
393
// expected to have removed its GUI components.
394
this.sendGUIComponentsToParent();
395         
396         // Even if we didn't do layout, the parent is
397
// expected to have removed its delayed pairs.
398
this.sendDelayedPairsToParent();
399     }
400     
401     private final boolean correctViewportOrigin(Insets insets, int blockWidth, int blockHeight) {
402         RBlockViewport bodyLayout = this.bodyLayout;
403         int viewPortX = bodyLayout.x;
404         int viewPortY = bodyLayout.y;
405         boolean corrected = false;
406         if(viewPortX > insets.left) {
407             bodyLayout.x = insets.left;
408             corrected = true;
409         }
410         else if(viewPortX < blockWidth - insets.right - bodyLayout.width) {
411             bodyLayout.x = Math.min(insets.left, blockWidth - insets.right - bodyLayout.width);
412             corrected = true;
413         }
414         if(viewPortY > insets.top) {
415             bodyLayout.y = insets.top;
416             corrected = true;
417         }
418         else if(viewPortY < blockHeight - insets.bottom - bodyLayout.height) {
419             bodyLayout.y = Math.min(insets.top, blockHeight - insets.bottom - bodyLayout.height);
420             corrected = true;
421         }
422         return corrected;
423     }
424     
425     /**
426      * Lays out the block without checking for prior dimensions.
427      * @param availWidth
428      * @param availHeight
429      * @return
430      */

431     private final void forceLayout(RenderState renderState, int availWidth, int availHeight, boolean expandWidth, boolean expandHeight, FloatingBounds floatBounds, int tentativeY, int defaultOverflow) {
432         // Expected to be invoked in the GUI thread.
433
//TODO: Not necessary to do full layout if only expandWidth or expandHeight change (specifically in tables).
434
RenderState rs = renderState;
435         if(rs == null) {
436             rs = new BlockRenderState(null, null);
437         }
438         if(this.lastAvailWidth == -1) {
439             // invalid or first time
440
rs.invalidate();
441             this.applyStyle();
442         }
443
444         int dw = this.getDeclaredWidth(rs, availWidth);
445         int dh = this.getDeclaredHeight(rs, availHeight);
446         this.lastExpandHeight = Boolean.valueOf(expandHeight);
447         this.lastExpandWidth = Boolean.valueOf(expandWidth);
448         Font newFont = rs.getFont();
449         this.lastFont = newFont;
450         this.lastAvailHeight = availHeight;
451         this.lastAvailWidth = availWidth;
452         this.lastFloatBounds = floatBounds;
453         this.lastWhiteSpace = rs.getWhiteSpace();
454         
455         RBlockViewport bodyLayout = this.bodyLayout;
456         NodeImpl node = (NodeImpl) this.modelNode;
457         if(node == null || bodyLayout == null) {
458             Insets insets = this.getInsets(false, false);
459             this.width = insets.left + insets.right;
460             this.height = insets.bottom + insets.top;
461             this.hasHScrollBar = false;
462             this.hasVScrollBar = false;
463             return;
464         }
465
466         // Remove all GUI components previously added by descendents
467
// The RBlockViewport.layout() method is expected to add all of them back.
468
this.clearGUIComponents();
469         
470         int tentativeWidth;
471         int tentativeHeight;
472         // Adjust dw and dh for margin
473
if(dw != -1 || dh != -1) {
474             Insets marginInsets = this.getMarginInsets(rs);
475             if(marginInsets != null) {
476                 //TODO: Is this right?
477
dw = dw == -1 ? -1 : dw + marginInsets.left + marginInsets.right;
478                 dh = dh == -1 ? -1 : dh + marginInsets.top + marginInsets.bottom;
479             }
480         }
481         tentativeWidth = dw == -1 ? availWidth : dw;
482         tentativeHeight = dh == -1 ? availHeight : dh;
483         int overflow = this.getOverflow();
484         if(overflow == OVERFLOW_NONE) {
485             overflow = defaultOverflow;
486         }
487         boolean vertical = overflow == OVERFLOW_VERTICAL;
488         boolean auto = vertical || overflow == OVERFLOW_AUTO;
489         boolean bothScrollBars = overflow == OVERFLOW_SCROLL;
490         boolean hscroll = bothScrollBars;
491         boolean vscroll = bothScrollBars || vertical;
492         boolean mayScroll = auto || bothScrollBars || vertical;
493         Insets paddingInsets = this.getPaddingInsets(rs);
494         if(paddingInsets == null) {
495             paddingInsets = RBlockViewport.ZERO_INSETS;
496         }
497         Insets insets = null;
498         for(int tries = ((auto && !vscroll) ? 0 : 1); tries < 2; tries++) {
499             try {
500                 insets = this.getInsets(hscroll, vscroll);
501                 int maxY = tries == 0 ? (dh == -1 ? -1 : dh - insets.bottom - insets.top - paddingInsets.bottom) : -1;
502                 int desiredViewportWidth = tentativeWidth - insets.left - insets.right;
503                 int desiredViewportHeight = tentativeHeight - insets.top - insets.bottom;
504                 bodyLayout.layout(desiredViewportWidth, desiredViewportHeight, paddingInsets, node, maxY, floatBounds);
505                 break;
506             } catch(SizeExceededException hee) {
507                 if(tries != 0) {
508                     throw new IllegalStateException JavaDoc("tries=" + tries + ",auto=" + auto);
509                 }
510                 vscroll = true;
511             }
512         }
513         this.hasVScrollBar = vscroll;
514         Dimension size = bodyLayout.getSize();
515         Dimension rblockSize = new Dimension(size.width + insets.left + insets.right, size.height + insets.top + insets.bottom);
516         if(auto && !hscroll && ((dw != -1 && rblockSize.width > dw) || (rblockSize.width > availWidth))) {
517             hscroll = true;
518             insets = this.getInsets(hscroll, vscroll);
519             rblockSize = new Dimension(size.width + insets.left + insets.right, size.height + insets.top + insets.bottom);
520         }
521         this.hasHScrollBar = hscroll;
522         boolean visible = !auto && !bothScrollBars && (overflow != OVERFLOW_HIDDEN);
523         int resultingWidth;
524         int resultingHeight;
525         if(dw == -1) {
526             resultingWidth = rblockSize.width;
527             if(expandWidth && resultingWidth < availWidth) {
528                 resultingWidth = availWidth;
529             }
530             else if(hscroll && resultingWidth > availWidth) {
531                 resultingWidth = Math.max(availWidth, SCROLL_BAR_THICKNESS);
532             }
533         }
534         else {
535             resultingWidth = visible ? Math.max(rblockSize.width, dw) : dw;
536         }
537         if(dh == -1) {
538             resultingHeight = rblockSize.height;
539             if(expandHeight && resultingHeight < availHeight) {
540                 resultingHeight = availHeight;
541             }
542             else if(vscroll && resultingHeight > availHeight) {
543                 resultingHeight = Math.max(availHeight, SCROLL_BAR_THICKNESS);
544             }
545         }
546         else {
547             resultingHeight = visible ? Math.max(rblockSize.height, dh) : dh;
548         }
549         if(vscroll) {
550             JScrollBar sb = this.getVScrollBar();
551             this.add(sb);
552             // Bounds set by updateWidgetBounds
553
}
554         if(hscroll) {
555             JScrollBar sb = this.getHScrollBar();
556             this.add(sb);
557             // Bounds set by updateWidgetBounds
558
}
559                 
560         this.width = resultingWidth;
561         this.height = resultingHeight;
562         
563         // Align viewport
564
int alignmentXPercent = rs.getAlignXPercent();
565         int alignmentYPercent = rs.getAlignYPercent();
566         if(alignmentXPercent > 0 || alignmentYPercent > 0) {
567             //TODO: alignment should not be done in table cell sizing determination.
568
int canvasWidth = Math.max(bodyLayout.width, resultingWidth - insets.left - insets.right);
569             int canvasHeight = Math.max(bodyLayout.height, resultingHeight - insets.top - insets.bottom);
570             bodyLayout.align(alignmentXPercent, alignmentYPercent, canvasWidth, canvasHeight, paddingInsets);
571         }
572         if(hscroll || vscroll) {
573             // In this case, viewport origin should not be changed.
574
// We don't want to cause the document to scroll back
575
// up while rendering.
576
this.correctViewportOrigin(insets, resultingWidth, resultingHeight);
577             // Depends on width, height and origin
578
this.resetScrollBars(rs);
579         }
580         else {
581             bodyLayout.x = insets.left;
582             bodyLayout.y = insets.top;
583         }
584     }
585
586     private int getVUnitIncrement(RenderState renderState) {
587         if(renderState != null) {
588             return renderState.getFontMetrics().getHeight();
589         }
590         else {
591             return new BlockRenderState(null, null).getFontMetrics().getHeight();
592         }
593     }
594     
595     private boolean resettingScrollBars = false;
596     
597     /**
598      * Changes scroll bar state to match viewport origin.
599      */

600     private void resetScrollBars(RenderState renderState) {
601         // Expected to be called only in the GUI thread.
602
this.resettingScrollBars = true;
603         try {
604             RBlockViewport bodyLayout = this.bodyLayout;
605             if(bodyLayout != null) {
606                 Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
607                 JScrollBar vsb = this.vScrollBar;
608                 if(vsb != null) {
609                     int newValue = insets.top - bodyLayout.y;
610                     int newExtent = this.height - insets.top - insets.bottom;
611                     int newMin = 0;
612                     int newMax = bodyLayout.height;
613                     vsb.setValues(newValue, newExtent, newMin, newMax);
614                     vsb.setUnitIncrement(this.getVUnitIncrement(renderState));
615                     vsb.setBlockIncrement(newExtent);
616                 }
617                 JScrollBar hsb = this.hScrollBar;
618                 if(hsb != null) {
619                     int newValue = insets.left - bodyLayout.x;
620                     int newExtent = this.width - insets.left - insets.right;
621                     int newMin = 0;
622                     int newMax = bodyLayout.width;
623                     hsb.setValues(newValue, newExtent, newMin, newMax);
624                 }
625             }
626         } finally {
627             this.resettingScrollBars = false;
628         }
629     }
630     
631     /* (non-Javadoc)
632      * @see org.xamjwg.html.renderer.UIControl#paintSelection(java.awt.Graphics, boolean, org.xamjwg.html.renderer.RenderablePoint, org.xamjwg.html.renderer.RenderablePoint)
633      */

634     public boolean paintSelection(Graphics g, boolean inSelection, RenderableSpot startPoint, RenderableSpot endPoint) {
635         Graphics newG = g.create();
636         try {
637             Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
638             // Just clip, don't translate.
639
newG.clipRect(insets.left, insets.top, this.width - insets.left - insets.right, this.height - insets.top - insets.bottom);
640             return super.paintSelection(newG, inSelection, startPoint, endPoint);
641         } finally {
642             newG.dispose();
643         }
644 // boolean endSelectionLater = false;
645
// if(inSelection) {
646
// if(startPoint.renderable == this || endPoint.renderable == this) {
647
// return false;
648
// }
649
// }
650
// else {
651
// if(startPoint.renderable == this || endPoint.renderable == this) {
652
// // This can only occur if the selection point
653
// // is on the margin or border or the block.
654
// inSelection = true;
655
// if(startPoint.renderable == this && endPoint.renderable == this) {
656
// // Start and end selection points on margin or border.
657
// endSelectionLater = true;
658
// }
659
// }
660
// }
661
// RBlockViewport bodyLayout = this.bodyLayout;
662
// if(bodyLayout != null) {
663
// Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
664
// Graphics newG = g.create(insets.left, insets.top, this.width - insets.left - insets.right, this.height - insets.top - insets.bottom);
665
// try {
666
// newG.translate(bodyLayout.x - insets.left, bodyLayout.y - insets.top);
667
// boolean newInSelection = bodyLayout.paintSelection(newG, inSelection, startPoint, endPoint);
668
// if(endSelectionLater) {
669
// return false;
670
// }
671
// return newInSelection;
672
// } finally {
673
// newG.dispose();
674
// }
675
// }
676
// else {
677
// return inSelection;
678
// }
679
}
680         
681     /* (non-Javadoc)
682      * @see org.xamjwg.html.renderer.BoundableRenderable#getRenderablePoint(int, int)
683      */

684     public RenderableSpot getLowestRenderableSpot(int x, int y) {
685         RBlockViewport bodyLayout = this.bodyLayout;
686         if(bodyLayout != null) {
687             Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
688             if(x > insets.left && x < this.width - insets.right && y > insets.top && y < this.height - insets.bottom) {
689                 return bodyLayout.getLowestRenderableSpot(x - bodyLayout.x, y - bodyLayout.y);
690             }
691             else {
692                 return new RenderableSpot(this, x, y);
693             }
694         }
695         else {
696             return new RenderableSpot(this, x, y);
697         }
698     }
699     
700     /**
701      * RBlocks should only be invalidated if one of their
702      * properties change, or if a descendent changes, or
703      * if a style property of an ancestor is such that
704      * it could produce layout changes in this RBlock.
705      */

706     public void invalidateLayoutLocal() {
707         super.invalidateLayoutLocal();
708         this.lastAvailHeight = -1;
709         this.lastAvailWidth = -1;
710         this.lastWhiteSpace = -1;
711         this.lastExpandHeight = null;
712         this.lastExpandWidth = null;
713         this.lastFloatBounds = INVALID_FLOAT_BOUNDS;
714     }
715
716     /* (non-Javadoc)
717      * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseClick(java.awt.event.MouseEvent, int, int)
718      */

719     public boolean onMouseClick(MouseEvent event, int x, int y) {
720         RBlockViewport bodyLayout = this.bodyLayout;
721         if(bodyLayout != null) {
722             if(!bodyLayout.onMouseClick(event, x - bodyLayout.x, y - bodyLayout.y)) {
723                 return false;
724             }
725         }
726         if(!HtmlController.getInstance().onMouseClick(this.modelNode, event, x, y)) {
727             return false;
728         }
729         if(this.backgroundColor != null) {
730             return false;
731         }
732         return true;
733     }
734
735     public boolean onDoubleClick(MouseEvent event, int x, int y) {
736         RBlockViewport bodyLayout = this.bodyLayout;
737         if(bodyLayout != null) {
738             if(!bodyLayout.onDoubleClick(event, x - bodyLayout.x, y - bodyLayout.y)) {
739                 return false;
740             }
741         }
742         if(this.backgroundColor != null) {
743             return false;
744         }
745         return true;
746     }
747
748     /* (non-Javadoc)
749      * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseDisarmed(java.awt.event.MouseEvent)
750      */

751     public boolean onMouseDisarmed(MouseEvent event) {
752         BoundableRenderable br = this.armedRenderable;
753         if(br != null) {
754             try {
755                 return br.onMouseDisarmed(event);
756             } finally {
757                 this.armedRenderable = null;
758             }
759         }
760         else {
761             return true;
762         }
763     }
764
765     private BoundableRenderable armedRenderable;
766     
767     /* (non-Javadoc)
768      * @see org.xamjwg.html.renderer.BoundableRenderable#onMousePressed(java.awt.event.MouseEvent, int, int)
769      */

770     public boolean onMousePressed(MouseEvent event, int x, int y) {
771         RBlockViewport bodyLayout = this.bodyLayout;
772         if(bodyLayout != null) {
773             int newX = x - bodyLayout.x;
774             int newY = y - bodyLayout.y;
775             if(bodyLayout.contains(newX, newY)) {
776                 this.armedRenderable = bodyLayout;
777                 if(!bodyLayout.onMousePressed(event, newX, newY)) {
778                     return false;
779                 }
780             }
781             else {
782                 this.armedRenderable = null;
783             }
784         }
785         else {
786             this.armedRenderable = null;
787         }
788         if(!HtmlController.getInstance().onMouseDown(this.modelNode, event, x, y)) {
789             return false;
790         }
791         if(this.backgroundColor != null) {
792             return false;
793         }
794         return true;
795     }
796
797     /* (non-Javadoc)
798      * @see org.xamjwg.html.renderer.BoundableRenderable#onMouseReleased(java.awt.event.MouseEvent, int, int)
799      */

800     public boolean onMouseReleased(MouseEvent event, int x, int y) {
801         RBlockViewport bodyLayout = this.bodyLayout;
802         if(bodyLayout != null) {
803             int newX = x - bodyLayout.x;
804             int newY = y - bodyLayout.y;
805             if(bodyLayout.contains(newX, newY)) {
806                 this.armedRenderable = null;
807                 if(!bodyLayout.onMouseReleased(event, newX, newY)) {
808                     return false;
809                 }
810             }
811             else {
812                 BoundableRenderable br = this.armedRenderable;
813                 if(br != null) {
814                     br.onMouseDisarmed(event);
815                 }
816             }
817         }
818         if(!HtmlController.getInstance().onMouseUp(this.modelNode, event, x, y)) {
819             return false;
820         }
821         if(this.backgroundColor != null) {
822             return false;
823         }
824         return true;
825     }
826
827     public Color getPaintedBackgroundColor() {
828         return this.backgroundColor;
829     }
830
831     /* (non-Javadoc)
832      * @see org.xamjwg.html.renderer.RCollection#getRenderables()
833      */

834     public Iterator getRenderables() {
835         final RBlockViewport bodyLayout = this.bodyLayout;
836         return new Iterator() {
837             private RBlockViewport bl = bodyLayout;
838             
839             public boolean hasNext() {
840                 return bl != null;
841             }
842
843             public Object JavaDoc next() {
844                 if(bl == null) {
845                     throw new NoSuchElementException();
846                 }
847                 try {
848                     return bl;
849                 } finally {
850                     bl = null;
851                 }
852             }
853
854             public void remove() {
855                 throw new UnsupportedOperationException JavaDoc();
856             }
857         };
858     }
859
860     /* (non-Javadoc)
861      * @see org.xamjwg.html.domimpl.ContainingBlockContext#repaint(org.xamjwg.html.domimpl.RenderableContext)
862      */

863     public void repaint(ModelNode modelNode) {
864         //this.invalidateRenderStyle();
865
this.repaint();
866     }
867
868 // public boolean extractSelectionText(StringBuffer buffer, boolean inSelection, RenderableSpot startPoint, RenderableSpot endPoint) {
869
// RBlockViewport bodyLayout = this.bodyLayout;
870
// if(bodyLayout != null) {
871
// inSelection = inSelection ? endPoint.renderable != this : startPoint.renderable == this;
872
// return bodyLayout.extractSelectionText(buffer, inSelection, startPoint, endPoint);
873
// }
874
// else {
875
// return inSelection;
876
// }
877
// }
878

879     public void updateWidgetBounds(int guiX, int guiY) {
880         super.updateWidgetBounds(guiX, guiY);
881         boolean hscroll = this.hasHScrollBar;
882         boolean vscroll = this.hasVScrollBar;
883         if(hscroll || vscroll) {
884             Insets insets = this.getInsets(hscroll, vscroll);
885             if(hscroll) {
886                 JScrollBar hsb = this.hScrollBar;
887                 if(hsb != null) {
888                     hsb.setBounds(guiX + insets.left, guiY + this.height - insets.bottom, this.width - insets.left - insets.right, SCROLL_BAR_THICKNESS);
889                 }
890             }
891             if(vscroll) {
892                 JScrollBar vsb = this.vScrollBar;
893                 if(vsb != null) {
894                     vsb.setBounds(guiX + this.width - insets.right, guiY + insets.top, SCROLL_BAR_THICKNESS, this.height - insets.top - insets.bottom);
895                 }
896             }
897         }
898     }
899     
900     public void scrollHorizontalTo(int newX) {
901         RBlockViewport bodyLayout = this.bodyLayout;
902         if(bodyLayout != null) {
903             Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
904             int viewPortX = newX;
905             if(viewPortX > insets.left) {
906                 bodyLayout.x = insets.left;
907             }
908             else if(viewPortX < this.width - insets.right - bodyLayout.width) {
909                 bodyLayout.x = Math.min(insets.left, this.width - insets.right - bodyLayout.width);
910             }
911             else {
912                 bodyLayout.x = viewPortX;
913             }
914             this.resetScrollBars(null);
915             this.updateWidgetBounds();
916             this.repaint();
917         }
918     }
919     
920     public void scrollVerticalTo(int newY) {
921         RBlockViewport bodyLayout = this.bodyLayout;
922         if(bodyLayout != null) {
923             Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
924             int viewPortY = newY;
925             if(viewPortY > insets.top) {
926                 bodyLayout.y = insets.top;
927             }
928             else if(viewPortY < this.height - insets.bottom - bodyLayout.height) {
929                 bodyLayout.y = Math.min(insets.top, this.height - insets.bottom - bodyLayout.height);
930             }
931             else {
932                 bodyLayout.y = viewPortY;
933             }
934             this.resetScrollBars(null);
935             this.updateWidgetBounds();
936             this.repaint();
937         }
938     }
939
940     public void scrollByUnits(int orientation, int units) {
941         int offset = orientation == JScrollBar.VERTICAL ? this.getVUnitIncrement(null) * units : units;
942         this.scrollBy(orientation, offset);
943     }
944
945     public void scrollBy(int orientation, int offset) {
946         RBlockViewport bodyLayout = this.bodyLayout;
947         if(bodyLayout != null) {
948             switch(orientation) {
949             case JScrollBar.HORIZONTAL:
950                 this.scrollHorizontalTo(bodyLayout.x - offset);
951                 break;
952             case JScrollBar.VERTICAL:
953                 this.scrollVerticalTo(bodyLayout.y - offset);
954                 break;
955             }
956         }
957     }
958     
959     private void scrollToSBValue(int orientation, int value) {
960         Insets insets = this.getInsets(this.hasHScrollBar, this.hasVScrollBar);
961         switch(orientation) {
962         case JScrollBar.HORIZONTAL:
963             int xOrigin = insets.left - value;
964             this.scrollHorizontalTo(xOrigin);
965             break;
966         case JScrollBar.VERTICAL:
967             int yOrigin = insets.top - value;
968             this.scrollVerticalTo(yOrigin);
969             break;
970         }
971     }
972     
973 // public Iterator getExportedRenderables() {
974
// RBlockViewport bodyLayout = this.bodyLayout;
975
// return bodyLayout == null ? null : bodyLayout.getExportedRenderables();
976
// }
977
//
978
public RBlockViewport getRBlockViewport() {
979         return this.bodyLayout;
980     }
981     
982     public String JavaDoc toString() {
983         return "RBlock[node=" + this.modelNode + "]";
984     }
985     
986     private class LocalAdjustmentListener implements AdjustmentListener {
987         private final int orientation;
988         
989         public LocalAdjustmentListener(int orientation) {
990             this.orientation = orientation;
991         }
992         
993         public void adjustmentValueChanged(AdjustmentEvent e) {
994             if(RBlock.this.resettingScrollBars) {
995                 return;
996             }
997             switch(e.getAdjustmentType()) {
998             case AdjustmentEvent.UNIT_INCREMENT:
999                 // fall through
1000
case AdjustmentEvent.UNIT_DECREMENT:
1001                // fall through
1002
case AdjustmentEvent.BLOCK_INCREMENT:
1003                // fall through
1004
case AdjustmentEvent.BLOCK_DECREMENT:
1005                // fall through
1006
case AdjustmentEvent.TRACK: {
1007                int value = e.getValue();
1008                RBlock.this.scrollToSBValue(this.orientation, value);
1009                break;
1010            }
1011            }
1012        }
1013    }
1014    
1015    private static class BodyFilter implements NodeFilter {
1016        public boolean accept(Node JavaDoc node) {
1017            return node instanceof org.w3c.dom.html2.HTMLBodyElement;
1018        }
1019    }
1020}
Popular Tags