001: package org.wings.plaf.css;
002:
003: import org.wings.SComponent;
004: import org.wings.SMenu;
005: import org.wings.SMenuItem;
006: import org.wings.SPopupMenu;
007: import org.wings.event.SParentFrameEvent;
008: import org.wings.event.SParentFrameListener;
009: import org.wings.header.SessionHeaders;
010: import org.wings.io.Device;
011: import org.wings.plaf.Update;
012: import org.wings.script.JavaScriptEvent;
013: import org.wings.script.JavaScriptListener;
014:
015: import java.awt.event.ActionListener;
016: import java.io.IOException;
017: import java.util.ArrayList;
018: import java.util.List;
019:
020: public final class PopupMenuCG extends AbstractComponentCG implements
021: org.wings.plaf.PopupMenuCG, SParentFrameListener {
022:
023: protected final List headers = new ArrayList();
024:
025: public static final JavaScriptListener BODY_ONCLICK_SCRIPT = new JavaScriptListener(
026: JavaScriptEvent.ON_CLICK, "wpm_handleBodyClicks(event)");
027:
028: public PopupMenuCG() {
029: headers
030: .add(Utils
031: .createExternalizedJSHeaderFromProperty(Utils.JS_ETC_MENU));
032: }
033:
034: public void installCG(final SComponent comp) {
035: super .installCG(comp);
036: comp.addParentFrameListener(this );
037: }
038:
039: public void uninstallCG(SComponent component) {
040: super .uninstallCG(component);
041: component.removeParentFrameListener(this );
042: if (component.getParentFrame() != null)
043: SessionHeaders.getInstance().deregisterHeaders(headers);
044: }
045:
046: public void parentFrameAdded(SParentFrameEvent e) {
047: SessionHeaders.getInstance().registerHeaders(headers);
048: }
049:
050: public void parentFrameRemoved(SParentFrameEvent e) {
051: SessionHeaders.getInstance().deregisterHeaders(headers);
052: }
053:
054: protected void writePopup(final Device device, SPopupMenu menu)
055: throws IOException {
056: if (menu.isEnabled()) {
057: String componentId = menu.getName();
058: device.print("<ul");
059: writeListAttributes(device, menu);
060: device.print(" id=\"");
061: device.print(componentId);
062: device.print("_pop\" class=\"");
063: device.print(menu.getStyle());
064: device.print("\">");
065: for (int i = 0; i < menu.getMenuComponentCount(); i++) {
066: SComponent menuItem = menu.getMenuComponent(i);
067:
068: if (menuItem.isVisible()) {
069: device.print("\n <li class=\"");
070: if (menuItem instanceof SMenuItem) {
071: if (menuItem instanceof SMenu) {
072: device.print("SMenu");
073: } else {
074: device.print("SMenuItem");
075: }
076: if (!menuItem.isEnabled()) {
077: device.print("_Disabled");
078: }
079: device.print("\"");
080: printScriptHandlers(device, menuItem,
081: "onmouseover");
082: } else {
083: device.print("SMenuComponent\"");
084: }
085: device.print(">");
086: if (menuItem instanceof SMenuItem) {
087: device.print("<a href=\"#\"");
088: if (menuItem instanceof SMenu) {
089: if (menuItem.isEnabled()) {
090: device.print(" class=\"x sub\"");
091: } else {
092: device.print(" class=\"y sub\"");
093: }
094: }
095: if (menuItem.getListeners(ActionListener.class).length == 0) {
096: // Prevent an unnecessary server roundtrip in case we've
097: // got a menu or menu item with no actions attached to it.
098: if (menuItem instanceof SMenu) {
099: // In case we've got a (sub-) menu we render the same
100: // 'ScriptHandler' as we've already done on 'mouseover'.
101: // Actually this is not mandatory but it makes menues
102: // usable on devices where 'mouseover' isn't working,
103: // e.g. on this fancy e-board in our presentation room.
104: printScriptHandlers(device, menuItem,
105: "onclick");
106: }
107: } else {
108: Utils
109: .printClickability(
110: device,
111: menuItem,
112: ((SMenuItem) menuItem)
113: .getToggleSelectionParameter(),
114: menuItem.isEnabled(),
115: menuItem
116: .getShowAsFormComponent());
117: }
118: device.print(">");
119: }
120: menuItem.write(device);
121: if (menuItem instanceof SMenuItem) {
122: device.print("</a>");
123: }
124: if (menuItem.isEnabled()
125: && menuItem instanceof SMenu) {
126: menuItem.putClientProperty("popup",
127: Boolean.TRUE);
128: menuItem.write(device);
129: menuItem.putClientProperty("popup", null);
130: }
131: device.print("</li>");
132: }
133: }
134: device.print("</ul>");
135: }
136: device.print("\n");
137: }
138:
139: /* (non-Javadoc)
140: * @see org.wings.plaf.css.PopupMenuCG#writeListAttributes(org.wings.io.Device, org.wings.SPopupMenu)
141: */
142: protected void writeListAttributes(final Device device,
143: SPopupMenu menu) throws IOException {
144: // calculate max length of children texts for sizing of layer
145: int maxLength = 0;
146: for (int i = 0; i < menu.getMenuComponentCount(); i++) {
147: if (!(menu.getMenuComponent(i) instanceof SMenuItem))
148: continue;
149: String text = ((SMenuItem) menu.getMenuComponent(i))
150: .getText();
151: if (text != null && text.length() > maxLength) {
152: maxLength = text.length();
153: if (menu.getMenuComponent(i) instanceof SMenu) {
154: maxLength = maxLength + 2; //graphics
155: }
156: }
157: }
158: device.print(" style=\"width:");
159: String stringLength = String.valueOf(maxLength
160: * menu.getWidthScaleFactor());
161: device.print(stringLength.substring(0, stringLength
162: .lastIndexOf('.') + 2));
163: device.print("em;\"");
164: }
165:
166: protected void printScriptHandlers(Device device,
167: SComponent menuItem, String handler) throws IOException {
168: // Print the script handlers if this is a SMenu OR if the parent has both, items and menus as childs.
169: // In the latter case a menu item might need to close an open submenu from a menu on the same level.
170: SMenuItem tMenuItem = (SMenuItem) menuItem;
171: if (!(tMenuItem instanceof SMenu)) {
172: if (tMenuItem.getParentMenu() != null
173: && tMenuItem.getParentMenu() instanceof SMenu) {
174: SMenu tParentMenu = (SMenu) tMenuItem.getParentMenu();
175: boolean tHasMenuChild = false;
176: boolean tHasMenuItemChild = false;
177: for (int tChildIndex = 0; tChildIndex < tParentMenu
178: .getMenuComponentCount(); tChildIndex++) {
179: SComponent tChild = tParentMenu
180: .getChild(tChildIndex);
181: if (tChild instanceof SMenu) {
182: tHasMenuChild = true;
183: } else {
184: tHasMenuItemChild = true;
185: }
186: }
187:
188: // No handler if not both types are present
189: if (!(tHasMenuChild && tHasMenuItemChild)) {
190: return;
191: }
192: }
193: }
194:
195: device.print(" ").print(handler).print(
196: "=\"wpm_openMenu(event, '");
197: device.print(tMenuItem.getName());
198: device.print("_pop','");
199: device.print(tMenuItem.getParentMenu().getName());
200: device.print("_pop');\"");
201: }
202:
203: public void writeInternal(final Device device, final SComponent _c)
204: throws IOException {
205: SPopupMenu menu = (SPopupMenu) _c;
206: writePopup(device, menu);
207: }
208:
209: public Update getComponentUpdate(SComponent component) {
210: return new ComponentUpdate(this , component);
211: }
212:
213: protected static class ComponentUpdate extends
214: AbstractComponentCG.ComponentUpdate {
215:
216: public ComponentUpdate(AbstractComponentCG cg,
217: SComponent component) {
218: super (cg, component);
219: }
220:
221: @Override
222: public Handler getHandler() {
223: UpdateHandler handler = (UpdateHandler) super .getHandler();
224:
225: handler.setName("componentMenu");
226: handler.setParameter(0, component.getName() + "_pop");
227:
228: return handler;
229: }
230:
231: }
232:
233: }
|