001: /*
002: * This file is part of the Tucana Echo2 Library.
003: * Copyright (C) 2006.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package tucana.echo2.webcontainer;
031:
032: import nextapp.echo2.app.Component;
033: import nextapp.echo2.app.update.ServerComponentUpdate;
034: import nextapp.echo2.webcontainer.ComponentSynchronizePeer;
035: import nextapp.echo2.webcontainer.ContainerInstance;
036: import nextapp.echo2.webcontainer.DomUpdateSupport;
037: import nextapp.echo2.webcontainer.PropertyUpdateProcessor;
038: import nextapp.echo2.webcontainer.RenderContext;
039: import nextapp.echo2.webcontainer.SynchronizePeerFactory;
040: import nextapp.echo2.webrender.ServerMessage;
041: import nextapp.echo2.webrender.Service;
042: import nextapp.echo2.webrender.WebRenderServlet;
043: import nextapp.echo2.webrender.servermessage.DomUpdate;
044: import nextapp.echo2.webrender.service.JavaScriptService;
045:
046: import org.w3c.dom.DocumentFragment;
047: import org.w3c.dom.Element;
048: import org.w3c.dom.Node;
049:
050: import tucana.echo2.app.widgetdash.WidgetContainer;
051: import tucana.echo2.app.widgetdash.WidgetPosition;
052:
053: public class WidgetContainerPeer implements ComponentSynchronizePeer,
054: DomUpdateSupport, PropertyUpdateProcessor {
055:
056: public static final String PROPERTY_POSITION = "widgetPosition";
057:
058: /**
059: * Service to provide supporting JavaScript library.
060: */
061: private static final Service WIDGET_CONTAINER_SERVICE = JavaScriptService
062: .forResource("Tucana.WidgetContainer",
063: "/tucana/echo2/webcontainer/resource/js/WidgetContainer.js");
064:
065: static {
066: WebRenderServlet.getServiceRegistry().add(
067: WIDGET_CONTAINER_SERVICE);
068: }
069:
070: public String getContainerId(Component child) {
071: return ContainerInstance.getElementId(child.getParent());
072: }
073:
074: public void renderAdd(RenderContext rc,
075: ServerComponentUpdate update, String targetId,
076: Component component) {
077: Element domAddElement = DomUpdate.renderElementAdd(rc
078: .getServerMessage());
079: DocumentFragment htmlFragment = rc.getServerMessage()
080: .getDocument().createDocumentFragment();
081: renderHtml(rc, update, htmlFragment, component);
082: DomUpdate.renderElementAddContent(rc.getServerMessage(),
083: domAddElement, targetId, htmlFragment);
084: }
085:
086: public void renderDispose(RenderContext rc,
087: ServerComponentUpdate update, Component component) {
088: ServerMessage serverMessage = rc.getServerMessage();
089: serverMessage.addLibrary(WIDGET_CONTAINER_SERVICE.getId());
090: Element partElement = serverMessage.addPart(
091: ServerMessage.GROUP_ID_UPDATE,
092: "TucanaWidgetContainer.MessageProcessor");
093: Element disposeElement = serverMessage.getDocument()
094: .createElement("dispose");
095:
096: String elementId = ContainerInstance.getElementId(component);
097:
098: disposeElement.setAttribute("eid", elementId);
099:
100: partElement.appendChild(disposeElement);
101: }
102:
103: public boolean renderUpdate(RenderContext rc,
104: ServerComponentUpdate update, String targetId) {
105: DomUpdate.renderElementRemove(rc.getServerMessage(),
106: ContainerInstance.getElementId(update.getParent()));
107: renderAdd(rc, update, targetId, update.getParent());
108: return false;
109: }
110:
111: public void renderHtml(RenderContext rc,
112: ServerComponentUpdate update, Node parentNode,
113: Component component) {
114: ServerMessage serverMessage = rc.getServerMessage();
115: serverMessage.addLibrary(WIDGET_CONTAINER_SERVICE.getId());
116:
117: Element divElement = parentNode.getOwnerDocument()
118: .createElement("div");
119: parentNode.appendChild(divElement);
120:
121: String id = ContainerInstance.getElementId(component);
122: divElement.setAttribute("id", id);
123: divElement.setAttribute("class", "widgetContainer");
124: divElement.setAttribute("style", "overflow: hidden;");
125:
126: renderInitDirective(rc, component);
127:
128: Component[] visibleChildren = component.getVisibleComponents();
129: for (int i = 0; i < visibleChildren.length; i++) {
130: renderAddChild(rc, update, divElement, visibleChildren[i]);
131: }
132: }
133:
134: /**
135: * Renders a child component.
136: *
137: * @param rc the relevant <code>RenderContext</code>
138: * @param update the update
139: * @param parentNode the HTML element which should contain the child
140: * @param child the child component to render
141: */
142: private void renderAddChild(RenderContext rc,
143: ServerComponentUpdate update, Node parentNode,
144: Component child) {
145: ComponentSynchronizePeer syncPeer = SynchronizePeerFactory
146: .getPeerForComponent(child.getClass());
147: if (syncPeer instanceof DomUpdateSupport) {
148: ((DomUpdateSupport) syncPeer).renderHtml(rc, update,
149: parentNode, child);
150: } else {
151: syncPeer
152: .renderAdd(rc, update, getContainerId(child), child);
153: }
154: }
155:
156: private void renderInitDirective(RenderContext rc,
157: Component component) {
158: ServerMessage serverMessage = rc.getServerMessage();
159: Element partElement = serverMessage.addPart(
160: ServerMessage.GROUP_ID_UPDATE,
161: "TucanaWidgetContainer.MessageProcessor");
162: Element initElement = serverMessage.getDocument()
163: .createElement("init");
164:
165: String elementId = ContainerInstance.getElementId(component);
166: String targetId = ContainerInstance.getElementId(component
167: .getParent());
168:
169: initElement.setAttribute("eid", elementId);
170: initElement.setAttribute("widgetdash-eid", targetId);
171:
172: WidgetPosition position = (WidgetPosition) component
173: .getProperty(WidgetContainer.PROPERTY_POSITION);
174: if (position != null) {
175: Element positionElement = serverMessage.getDocument()
176: .createElement("position");
177: positionElement.setAttribute("column", Integer
178: .toString(position.getColumn()));
179: positionElement.setAttribute("column-position", Integer
180: .toString(position.getColumnPosition()));
181: initElement.appendChild(positionElement);
182: }
183:
184: partElement.appendChild(initElement);
185: }
186:
187: public void processPropertyUpdate(ContainerInstance ci,
188: Component component, Element propertyElement) {
189: String propertyName = propertyElement
190: .getAttribute(PROPERTY_NAME);
191: if (propertyName.equals(PROPERTY_POSITION)) {
192: Element positionElement = (Element) propertyElement
193: .getFirstChild();
194: String column = positionElement.getAttribute("column");
195: String columnPosition = positionElement
196: .getAttribute("column-position");
197: WidgetPosition position = null;
198: try {
199: position = new WidgetPosition(Integer.parseInt(column),
200: Integer.parseInt(columnPosition));
201: } catch (NumberFormatException e) {
202: throw new RuntimeException(
203: "Cannot parse position update", e);
204: }
205: ci
206: .getUpdateManager()
207: .getClientUpdateManager()
208: .setComponentProperty(component,
209: WidgetContainer.PROPERTY_POSITION, position);
210: }
211: }
212:
213: }
|