1 29 30 package nextapp.echo2.webcontainer.syncpeer; 31 32 import org.w3c.dom.Document ; 33 import org.w3c.dom.DocumentFragment ; 34 import org.w3c.dom.Element ; 35 import org.w3c.dom.Node ; 36 37 import nextapp.echo2.app.Alignment; 38 import nextapp.echo2.app.Border; 39 import nextapp.echo2.app.Color; 40 import nextapp.echo2.app.Component; 41 import nextapp.echo2.app.Extent; 42 import nextapp.echo2.app.Font; 43 import nextapp.echo2.app.ImageReference; 44 import nextapp.echo2.app.Insets; 45 import nextapp.echo2.app.Row; 46 import nextapp.echo2.app.LayoutData; 47 import nextapp.echo2.app.layout.RowLayoutData; 48 import nextapp.echo2.app.update.ServerComponentUpdate; 49 import nextapp.echo2.webcontainer.ContainerInstance; 50 import nextapp.echo2.webcontainer.DomUpdateSupport; 51 import nextapp.echo2.webcontainer.PartialUpdateManager; 52 import nextapp.echo2.webcontainer.RenderContext; 53 import nextapp.echo2.webcontainer.RenderState; 54 import nextapp.echo2.webcontainer.ComponentSynchronizePeer; 55 import nextapp.echo2.webcontainer.SynchronizePeerFactory; 56 import nextapp.echo2.webcontainer.image.ImageRenderSupport; 57 import nextapp.echo2.webcontainer.partialupdate.BorderUpdate; 58 import nextapp.echo2.webcontainer.partialupdate.ColorUpdate; 59 import nextapp.echo2.webcontainer.partialupdate.InsetsUpdate; 60 import nextapp.echo2.webcontainer.propertyrender.AlignmentRender; 61 import nextapp.echo2.webcontainer.propertyrender.BorderRender; 62 import nextapp.echo2.webcontainer.propertyrender.CellLayoutDataRender; 63 import nextapp.echo2.webcontainer.propertyrender.ColorRender; 64 import nextapp.echo2.webcontainer.propertyrender.ExtentRender; 65 import nextapp.echo2.webcontainer.propertyrender.FontRender; 66 import nextapp.echo2.webcontainer.propertyrender.InsetsRender; 67 import nextapp.echo2.webrender.output.CssStyle; 68 import nextapp.echo2.webrender.servermessage.DomUpdate; 69 70 76 public class RowPeer 77 implements ComponentSynchronizePeer, DomUpdateSupport, ImageRenderSupport { 78 79 82 private static class RowPeerRenderState 83 implements RenderState { 84 85 92 public Component lastChild; 93 } 94 95 private PartialUpdateManager partialUpdateManager; 96 97 100 public RowPeer() { 101 partialUpdateManager = new PartialUpdateManager(); 102 partialUpdateManager.add(Row.PROPERTY_BORDER, new BorderUpdate(Row.PROPERTY_BORDER, null, 103 BorderUpdate.CSS_BORDER)); 104 partialUpdateManager.add(Row.PROPERTY_FOREGROUND, new ColorUpdate(Row.PROPERTY_FOREGROUND, null, 105 ColorUpdate.CSS_COLOR)); 106 partialUpdateManager.add(Row.PROPERTY_BACKGROUND, new ColorUpdate(Row.PROPERTY_BACKGROUND, null, 107 ColorUpdate.CSS_BACKGROUND_COLOR)); 108 partialUpdateManager.add(Row.PROPERTY_INSETS, new InsetsUpdate(Row.PROPERTY_INSETS, null, 109 InsetsUpdate.CSS_PADDING)); 110 } 111 112 115 public String getContainerId(Component child) { 116 return ContainerInstance.getElementId(child.getParent()) + "_cell_" + ContainerInstance.getElementId(child); 117 } 118 119 122 public ImageReference getImage(Component component, String imageId) { 123 return CellLayoutDataRender.getCellLayoutDataBackgroundImage(component, imageId); 126 } 127 128 137 private RowLayoutData getLayoutData(Component child) { 138 LayoutData layoutData = (LayoutData) child.getRenderProperty(Component.PROPERTY_LAYOUT_DATA); 139 if (layoutData == null) { 140 return null; 141 } else if (layoutData instanceof RowLayoutData) { 142 return (RowLayoutData) layoutData; 143 } else { 144 throw new RuntimeException ("Invalid LayoutData for Row Child: " + layoutData.getClass().getName()); 145 } 146 } 147 148 152 public void renderAdd(RenderContext rc, ServerComponentUpdate update, String targetId, Component component) { 153 Element domAddElement = DomUpdate.renderElementAdd(rc.getServerMessage()); 154 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 155 renderHtml(rc, update, htmlFragment, component); 156 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, targetId, htmlFragment); 157 } 158 159 167 private void renderAddChild(RenderContext rc, ServerComponentUpdate update, Element parentElement, Component child) { 168 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(child.getClass()); 169 if (syncPeer instanceof DomUpdateSupport) { 170 ((DomUpdateSupport) syncPeer).renderHtml(rc, update, parentElement, child); 171 } else { 172 syncPeer.renderAdd(rc, update, getContainerId(child), child); 173 } 174 } 175 176 183 private void renderAddChildren(RenderContext rc, ServerComponentUpdate update) { 184 Element domAddElement = DomUpdate.renderElementAdd(rc.getServerMessage()); 185 Row row = (Row) update.getParent(); 186 String elementId = ContainerInstance.getElementId(row); 187 String trElementId = elementId + "_tr"; 188 189 Component[] components = update.getParent().getVisibleComponents(); 190 Component[] addedChildren = update.getAddedChildren(); 191 192 for (int componentIndex = components.length - 1; componentIndex >= 0; --componentIndex) { 193 boolean childFound = false; 194 for (int addedChildrenIndex = 0; !childFound && addedChildrenIndex < addedChildren.length; ++addedChildrenIndex) { 195 if (addedChildren[addedChildrenIndex] == components[componentIndex]) { 196 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 197 renderChild(rc, update, htmlFragment, row, components[componentIndex]); 198 if (componentIndex == components.length - 1) { 199 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, trElementId, htmlFragment); 200 } else { 201 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, trElementId, 202 elementId + "_cell_" + ContainerInstance.getElementId(components[componentIndex + 1]), 203 htmlFragment); 204 } 205 childFound = true; 206 } 207 } 208 } 209 210 RowPeerRenderState renderState = (RowPeerRenderState) rc.getContainerInstance().getRenderState(row); 214 if (renderState != null && renderState.lastChild != null) { 215 int previousLastChildIndex = row.visibleIndexOf(renderState.lastChild); 216 if (previousLastChildIndex != -1 && previousLastChildIndex != row.getVisibleComponentCount() - 1) { 217 219 boolean lastChildMoved = false; 221 for (int i = 0; i < addedChildren.length; ++i) { 222 if (renderState.lastChild == addedChildren[i]) { 223 lastChildMoved = true; 224 } 225 } 226 if (!lastChildMoved) { 227 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 228 renderSpacingCell(htmlFragment, row, renderState.lastChild); 229 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, trElementId, 230 elementId + "_cell_" + ContainerInstance.getElementId(components[previousLastChildIndex + 1]), 231 htmlFragment); 232 } 233 } 234 } 235 } 236 237 246 private void renderChild(RenderContext rc, ServerComponentUpdate update, Node parentNode, 247 Component component, Component child) { 248 Document document = parentNode.getOwnerDocument(); 249 String childId = ContainerInstance.getElementId(child); 250 Element tdElement = document.createElement("td"); 251 String cellId = ContainerInstance.getElementId(component) + "_cell_" + childId; 252 tdElement.setAttribute("id", cellId); 253 254 CssStyle cssStyle = new CssStyle(); 256 RowLayoutData layoutData = getLayoutData(child); 257 CellLayoutDataRender.renderToElementAndStyle(tdElement, cssStyle, child, layoutData, "0px"); 258 CellLayoutDataRender.renderBackgroundImageToStyle(cssStyle, rc, this, component, child); 259 if (layoutData != null) { 260 ExtentRender.renderToStyle(cssStyle, "width", layoutData.getWidth()); 261 } 262 tdElement.setAttribute("style", cssStyle.renderInline()); 263 264 parentNode.appendChild(tdElement); 265 266 renderSpacingCell(parentNode, (Row) component, child); 267 268 renderAddChild(rc, update, tdElement, child); 269 } 270 271 275 public void renderDispose(RenderContext rc, ServerComponentUpdate update, Component component) { } 276 277 281 public void renderHtml(RenderContext rc, ServerComponentUpdate update, Node parentNode, Component component) { 282 Row row = (Row) component; 283 Border border = (Border) row.getRenderProperty(Row.PROPERTY_BORDER); 284 String elementId = ContainerInstance.getElementId(row); 285 Document document = parentNode.getOwnerDocument(); 286 287 Element divElement = document.createElement("div"); 288 divElement.setAttribute("id", elementId); 289 parentNode.appendChild(divElement); 290 291 CssStyle divCssStyle = new CssStyle(); 292 BorderRender.renderToStyle(divCssStyle, border); 293 ColorRender.renderToStyle(divCssStyle, (Color) row.getRenderProperty(Row.PROPERTY_FOREGROUND), 294 (Color) row.getRenderProperty(Row.PROPERTY_BACKGROUND)); 295 FontRender.renderToStyle(divCssStyle, (Font) row.getRenderProperty(Row.PROPERTY_FONT)); 296 Insets insets = (Insets) row.getRenderProperty(Row.PROPERTY_INSETS); 297 if (insets == null) { 298 divCssStyle.setAttribute("padding", "0px"); 299 } else { 300 InsetsRender.renderToStyle(divCssStyle, "padding", insets); 301 } 302 divElement.setAttribute("style", divCssStyle.renderInline()); 303 304 Element tableElement = document.createElement("table"); 305 tableElement.setAttribute("id", elementId + "_table"); 306 tableElement.setAttribute("style", "padding:0px;border-collapse:collapse;"); 307 308 AlignmentRender.renderToElement(divElement, 309 ((Alignment) row.getRenderProperty(Row.PROPERTY_ALIGNMENT)), row); 310 311 divElement.appendChild(tableElement); 312 313 Element tbodyElement = document.createElement("tbody"); 314 tbodyElement.setAttribute("id", elementId + "_tbody"); 315 tableElement.appendChild(tbodyElement); 316 317 Element trElement = document.createElement("tr"); 318 trElement.setAttribute("id", elementId + "_tr"); 319 tbodyElement.appendChild(trElement); 320 321 Component[] children = row.getVisibleComponents(); 322 for (int i = 0; i < children.length; ++i) { 323 renderChild(rc, update, trElement, component, children[i]); 324 } 325 326 storeRenderState(rc, row); 327 } 328 329 337 private void renderRemoveChildren(RenderContext rc, ServerComponentUpdate update) { 338 Component[] removedChildren = update.getRemovedChildren(); 339 Component parent = update.getParent(); 340 String parentId = ContainerInstance.getElementId(parent); 341 for (int i = 0; i < removedChildren.length; ++i) { 342 String childId = ContainerInstance.getElementId(removedChildren[i]); 343 DomUpdate.renderElementRemove(rc.getServerMessage(), 344 parentId + "_cell_" + childId); 345 DomUpdate.renderElementRemove(rc.getServerMessage(), 346 parentId + "_spacing_" + childId); 347 } 348 349 int componentCount = parent.getVisibleComponentCount(); 350 if (componentCount > 0) { 351 DomUpdate.renderElementRemove(rc.getServerMessage(), parentId + "_spacing_" 352 + ContainerInstance.getElementId(parent.getVisibleComponent(componentCount - 1))); 353 } 354 } 355 356 365 private void renderSpacingCell(Node parentNode, Row row, Component child) { 366 Extent cellSpacing = (Extent) row.getRenderProperty(Row.PROPERTY_CELL_SPACING); 367 if (!ExtentRender.isZeroLength(cellSpacing) && row.visibleIndexOf(child) != row.getVisibleComponentCount() - 1) { 368 Element spacingElement = parentNode.getOwnerDocument().createElement("td"); 369 spacingElement.setAttribute("id", ContainerInstance.getElementId(row) + "_spacing_" 370 + ContainerInstance.getElementId(child)); 371 CssStyle spacingCssStyle = new CssStyle(); 372 spacingCssStyle.setAttribute("width", ExtentRender.renderCssAttributeValue(cellSpacing)); 373 spacingCssStyle.setAttribute("font-size", "1px"); 374 spacingCssStyle.setAttribute("line-height", "0px"); 375 spacingElement.setAttribute("style", spacingCssStyle.renderInline()); 376 parentNode.appendChild(spacingElement); 377 } 378 } 379 380 384 public boolean renderUpdate(RenderContext rc, ServerComponentUpdate update, String targetId) { 385 boolean fullReplace = false; 387 if (update.hasUpdatedLayoutDataChildren()) { 388 fullReplace = true; 390 } else if (update.hasUpdatedProperties()) { 391 if (!partialUpdateManager.canProcess(rc, update)) { 392 fullReplace = true; 393 } 394 } 395 396 if (fullReplace) { 397 DomUpdate.renderElementRemove(rc.getServerMessage(), ContainerInstance.getElementId(update.getParent())); 399 renderAdd(rc, update, targetId, update.getParent()); 400 } else { 401 if (update.hasRemovedChildren()) { 403 renderRemoveChildren(rc, update); 404 } 405 if (update.hasUpdatedProperties()) { 406 partialUpdateManager.process(rc, update); 407 } 408 if (update.hasAddedChildren()) { 409 renderAddChildren(rc, update); 410 } 411 } 412 413 storeRenderState(rc, update.getParent()); 414 return fullReplace; 415 } 416 417 423 private void storeRenderState(RenderContext rc, Component component) { 424 int componentCount = component.getVisibleComponentCount(); 425 RowPeerRenderState renderState = new RowPeerRenderState(); 426 if (componentCount > 0) { 427 renderState.lastChild = component.getVisibleComponent(componentCount - 1); 428 } 429 rc.getContainerInstance().setRenderState(component, renderState); 430 } 431 } 432 | Popular Tags |