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.Border; 38 import nextapp.echo2.app.Color; 39 import nextapp.echo2.app.Component; 40 import nextapp.echo2.app.Extent; 41 import nextapp.echo2.app.Font; 42 import nextapp.echo2.app.ImageReference; 43 import nextapp.echo2.app.Insets; 44 import nextapp.echo2.app.Column; 45 import nextapp.echo2.app.LayoutData; 46 import nextapp.echo2.app.layout.ColumnLayoutData; 47 import nextapp.echo2.app.update.ServerComponentUpdate; 48 import nextapp.echo2.webcontainer.ContainerInstance; 49 import nextapp.echo2.webcontainer.DomUpdateSupport; 50 import nextapp.echo2.webcontainer.PartialUpdateManager; 51 import nextapp.echo2.webcontainer.RenderContext; 52 import nextapp.echo2.webcontainer.RenderState; 53 import nextapp.echo2.webcontainer.ComponentSynchronizePeer; 54 import nextapp.echo2.webcontainer.SynchronizePeerFactory; 55 import nextapp.echo2.webcontainer.image.ImageRenderSupport; 56 import nextapp.echo2.webcontainer.partialupdate.BorderUpdate; 57 import nextapp.echo2.webcontainer.partialupdate.ColorUpdate; 58 import nextapp.echo2.webcontainer.partialupdate.InsetsUpdate; 59 import nextapp.echo2.webcontainer.propertyrender.BorderRender; 60 import nextapp.echo2.webcontainer.propertyrender.CellLayoutDataRender; 61 import nextapp.echo2.webcontainer.propertyrender.ColorRender; 62 import nextapp.echo2.webcontainer.propertyrender.ExtentRender; 63 import nextapp.echo2.webcontainer.propertyrender.FontRender; 64 import nextapp.echo2.webcontainer.propertyrender.InsetsRender; 65 import nextapp.echo2.webrender.output.CssStyle; 66 import nextapp.echo2.webrender.servermessage.DomUpdate; 67 68 74 public class ColumnPeer 75 implements ComponentSynchronizePeer, DomUpdateSupport, ImageRenderSupport { 76 77 80 private static class ColumnPeerRenderState 81 implements RenderState { 82 83 90 public Component lastChild; 91 } 92 93 private PartialUpdateManager partialUpdateManager; 94 95 98 public ColumnPeer() { 99 partialUpdateManager = new PartialUpdateManager(); 100 partialUpdateManager.add(Column.PROPERTY_BORDER, new BorderUpdate(Column.PROPERTY_BORDER, null, 101 BorderUpdate.CSS_BORDER)); 102 partialUpdateManager.add(Column.PROPERTY_FOREGROUND, new ColorUpdate(Column.PROPERTY_FOREGROUND, null, 103 ColorUpdate.CSS_COLOR)); 104 partialUpdateManager.add(Column.PROPERTY_BACKGROUND, new ColorUpdate(Column.PROPERTY_BACKGROUND, null, 105 ColorUpdate.CSS_BACKGROUND_COLOR)); 106 partialUpdateManager.add(Column.PROPERTY_INSETS, new InsetsUpdate(Column.PROPERTY_INSETS, null, 107 InsetsUpdate.CSS_PADDING)); 108 } 109 110 113 public String getContainerId(Component child) { 114 return ContainerInstance.getElementId(child.getParent()) + "_cell_" + ContainerInstance.getElementId(child); 115 } 116 117 120 public ImageReference getImage(Component component, String imageId) { 121 return CellLayoutDataRender.getCellLayoutDataBackgroundImage(component, imageId); 124 } 125 126 135 private ColumnLayoutData getLayoutData(Component child) { 136 LayoutData layoutData = (LayoutData) child.getRenderProperty(Component.PROPERTY_LAYOUT_DATA); 137 if (layoutData == null) { 138 return null; 139 } else if (layoutData instanceof ColumnLayoutData) { 140 return (ColumnLayoutData) layoutData; 141 } else { 142 throw new RuntimeException ("Invalid LayoutData for Column Child: " + layoutData.getClass().getName()); 143 } 144 } 145 146 150 public void renderAdd(RenderContext rc, ServerComponentUpdate update, String targetId, Component component) { 151 Element domAddElement = DomUpdate.renderElementAdd(rc.getServerMessage()); 152 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 153 renderHtml(rc, update, htmlFragment, component); 154 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, targetId, htmlFragment); 155 } 156 157 165 private void renderAddChild(RenderContext rc, ServerComponentUpdate update, Element parentElement, Component child) { 166 ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(child.getClass()); 167 if (syncPeer instanceof DomUpdateSupport) { 168 ((DomUpdateSupport) syncPeer).renderHtml(rc, update, parentElement, child); 169 } else { 170 syncPeer.renderAdd(rc, update, getContainerId(child), child); 171 } 172 } 173 174 181 private void renderAddChildren(RenderContext rc, ServerComponentUpdate update) { 182 Element domAddElement = DomUpdate.renderElementAdd(rc.getServerMessage()); 183 Column column = (Column) update.getParent(); 184 String elementId = ContainerInstance.getElementId(column); 185 186 Component[] components = update.getParent().getVisibleComponents(); 187 Component[] addedChildren = update.getAddedChildren(); 188 189 for (int componentIndex = components.length - 1; componentIndex >= 0; --componentIndex) { 190 boolean childFound = false; 191 for (int addedChildrenIndex = 0; !childFound && addedChildrenIndex < addedChildren.length; ++addedChildrenIndex) { 192 if (addedChildren[addedChildrenIndex] == components[componentIndex]) { 193 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 194 renderChild(rc, update, htmlFragment, column, components[componentIndex]); 195 if (componentIndex == components.length - 1) { 196 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement, elementId, htmlFragment); 197 } else { 198 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement,elementId, 199 elementId + "_cell_" + ContainerInstance.getElementId(components[componentIndex + 1]), 200 htmlFragment); 201 } 202 childFound = true; 203 } 204 } 205 } 206 207 ColumnPeerRenderState renderState = (ColumnPeerRenderState) rc.getContainerInstance().getRenderState(column); 211 if (renderState != null && renderState.lastChild != null) { 212 int previousLastChildIndex = column.visibleIndexOf(renderState.lastChild); 213 if (previousLastChildIndex != -1 && previousLastChildIndex != column.getVisibleComponentCount() - 1) { 214 216 boolean lastChildMoved = false; 218 for (int i = 0; i < addedChildren.length; ++i) { 219 if (renderState.lastChild == addedChildren[i]) { 220 lastChildMoved = true; 221 } 222 } 223 if (!lastChildMoved) { 224 DocumentFragment htmlFragment = rc.getServerMessage().getDocument().createDocumentFragment(); 225 renderSpacingCell(htmlFragment, column, renderState.lastChild); 226 DomUpdate.renderElementAddContent(rc.getServerMessage(), domAddElement,elementId, 227 elementId + "_cell_" + ContainerInstance.getElementId(components[previousLastChildIndex + 1]), 228 htmlFragment); 229 } 230 } 231 } 232 } 233 234 243 private void renderChild(RenderContext rc, ServerComponentUpdate update, Node parentNode, 244 Component component, Component child) { 245 Document document = parentNode.getOwnerDocument(); 246 String childId = ContainerInstance.getElementId(child); 247 Element divElement = document.createElement("div"); 248 String cellId = ContainerInstance.getElementId(component) + "_cell_" + childId; 249 divElement.setAttribute("id", cellId); 250 251 CssStyle cssStyle = new CssStyle(); 253 ColumnLayoutData layoutData = getLayoutData(child); 254 CellLayoutDataRender.renderToElementAndStyle(divElement, cssStyle, child, layoutData, "0px"); 255 CellLayoutDataRender.renderBackgroundImageToStyle(cssStyle, rc, this, component, child); 256 if (layoutData != null) { 257 ExtentRender.renderToStyle(cssStyle, "height", layoutData.getHeight()); 258 } 259 divElement.setAttribute("style", cssStyle.renderInline()); 260 261 parentNode.appendChild(divElement); 262 263 renderSpacingCell(parentNode, (Column) component, child); 264 265 renderAddChild(rc, update, divElement, child); 266 } 267 268 272 public void renderDispose(RenderContext rc, ServerComponentUpdate update, Component component) { } 273 274 278 public void renderHtml(RenderContext rc, ServerComponentUpdate update, Node parentNode, Component component) { 279 Column column = (Column) component; 280 281 Document document = parentNode.getOwnerDocument(); 282 Element divElement = document.createElement("div"); 283 divElement.setAttribute("id", ContainerInstance.getElementId(column)); 284 285 CssStyle divCssStyle = new CssStyle(); 286 BorderRender.renderToStyle(divCssStyle, (Border) column.getRenderProperty(Column.PROPERTY_BORDER)); 287 ColorRender.renderToStyle(divCssStyle, (Color) column.getRenderProperty(Column.PROPERTY_FOREGROUND), 288 (Color) column.getRenderProperty(Column.PROPERTY_BACKGROUND)); 289 FontRender.renderToStyle(divCssStyle, (Font) column.getRenderProperty(Column.PROPERTY_FONT)); 290 Insets insets = (Insets) column.getRenderProperty(Column.PROPERTY_INSETS); 291 if (insets == null) { 292 divCssStyle.setAttribute("padding", "0px"); 293 } else { 294 InsetsRender.renderToStyle(divCssStyle, "padding", insets); 295 } 296 297 divElement.setAttribute("style", divCssStyle.renderInline()); 298 299 parentNode.appendChild(divElement); 300 301 Component[] children = column.getVisibleComponents(); 302 for (int i = 0; i < children.length; ++i) { 303 renderChild(rc, update, divElement, component, children[i]); 304 } 305 306 storeRenderState(rc, column); 307 } 308 309 317 private void renderRemoveChildren(RenderContext rc, ServerComponentUpdate update) { 318 Component[] removedChildren = update.getRemovedChildren(); 319 Component parent = update.getParent(); 320 String parentId = ContainerInstance.getElementId(parent); 321 for (int i = 0; i < removedChildren.length; ++i) { 322 String childId = ContainerInstance.getElementId(removedChildren[i]); 323 DomUpdate.renderElementRemove(rc.getServerMessage(), 324 parentId + "_cell_" + childId); 325 DomUpdate.renderElementRemove(rc.getServerMessage(), 326 parentId + "_spacing_" + childId); 327 } 328 329 int componentCount = parent.getVisibleComponentCount(); 330 if (componentCount > 0) { 331 DomUpdate.renderElementRemove(rc.getServerMessage(), parentId + "_spacing_" 332 + ContainerInstance.getElementId(parent.getVisibleComponent(componentCount - 1))); 333 } 334 } 335 336 345 private void renderSpacingCell(Node parentNode, Column column, Component child) { 346 Extent cellSpacing = (Extent) column.getRenderProperty(Column.PROPERTY_CELL_SPACING); 347 if (!ExtentRender.isZeroLength(cellSpacing) && column.visibleIndexOf(child) != column.getVisibleComponentCount() - 1) { 348 Element spacingElement = parentNode.getOwnerDocument().createElement("div"); 349 spacingElement.setAttribute("id", ContainerInstance.getElementId(column) + "_spacing_" 350 + ContainerInstance.getElementId(child)); 351 CssStyle spacingCssStyle = new CssStyle(); 352 spacingCssStyle.setAttribute("height", ExtentRender.renderCssAttributeValue(cellSpacing)); 353 spacingCssStyle.setAttribute("font-size", "1px"); 354 spacingCssStyle.setAttribute("line-height", "0px"); 355 spacingElement.setAttribute("style", spacingCssStyle.renderInline()); 356 parentNode.appendChild(spacingElement); 357 } 358 } 359 360 364 public boolean renderUpdate(RenderContext rc, ServerComponentUpdate update, String targetId) { 365 boolean fullReplace = false; 367 if (update.hasUpdatedLayoutDataChildren()) { 368 fullReplace = true; 370 } else if (update.hasUpdatedProperties()) { 371 if (!partialUpdateManager.canProcess(rc, update)) { 372 fullReplace = true; 373 } 374 } 375 376 if (fullReplace) { 377 DomUpdate.renderElementRemove(rc.getServerMessage(), ContainerInstance.getElementId(update.getParent())); 379 renderAdd(rc, update, targetId, update.getParent()); 380 } else { 381 if (update.hasRemovedChildren()) { 383 renderRemoveChildren(rc, update); 384 } 385 if (update.hasUpdatedProperties()) { 386 partialUpdateManager.process(rc, update); 387 } 388 if (update.hasAddedChildren()) { 389 renderAddChildren(rc, update); 390 } 391 } 392 393 storeRenderState(rc, update.getParent()); 394 return fullReplace; 395 } 396 397 403 private void storeRenderState(RenderContext rc, Component component) { 404 int componentCount = component.getVisibleComponentCount(); 405 ColumnPeerRenderState renderState = new ColumnPeerRenderState(); 406 if (componentCount > 0) { 407 renderState.lastChild = component.getVisibleComponent(componentCount - 1); 408 } 409 rc.getContainerInstance().setRenderState(component, renderState); 410 } 411 } 412 | Popular Tags |