001: /*
002: * MyGWT Widget Library
003: * Copyright(c) 2007, MyGWT.
004: * licensing@mygwt.net
005: *
006: * http://mygwt.net/license
007: */
008: package net.mygwt.ui.client.widget;
009:
010: import net.mygwt.ui.client.Events;
011: import net.mygwt.ui.client.MyDOM;
012: import net.mygwt.ui.client.Style;
013: import net.mygwt.ui.client.event.BaseEvent;
014: import net.mygwt.ui.client.event.Listener;
015: import net.mygwt.ui.client.event.SelectionListener;
016: import net.mygwt.ui.client.fx.FXStyle;
017: import net.mygwt.ui.client.util.Format;
018: import net.mygwt.ui.client.util.Markup;
019:
020: import com.google.gwt.user.client.DOM;
021: import com.google.gwt.user.client.Element;
022: import com.google.gwt.user.client.Event;
023: import com.google.gwt.user.client.ui.MouseListener;
024: import com.google.gwt.user.client.ui.MouseListenerCollection;
025: import com.google.gwt.user.client.ui.SimplePanel;
026: import com.google.gwt.user.client.ui.SourcesMouseEvents;
027: import com.google.gwt.user.client.ui.WidgetHelper;
028:
029: /**
030: * A <code>Container</code> with an optional header that can be expanded and
031: * collapsed.
032: *
033: * <dl>
034: * <dt><b>Styles:</b></dt>
035: * <dd>COLLAPSE, HEADER, CLOSE</dd>
036: *
037: * <dt><b>Events:</b></dt>
038: *
039: * <dd><b>BeforeExpand</b> : (widget)<br>
040: * <div>Fires before the panel is expanded. Listeners can set the
041: * <code>doit</code> field to <code>false</code> to cancel the expand.</div>
042: * <ul>
043: * <li>widget : this</li>
044: * </ul>
045: * </dd>
046: *
047: * <dd><b>Expand</b> : (widget)<br>
048: * <div>Fires after the panel is expanded</div>
049: * <ul>
050: * <li>widget : this</li>
051: * </ul>
052: * </dd>
053: *
054: * <dd><b>BeforeCollapse</b> : (widget)<br>
055: * <div>Fires before the panel is collpased. Listeners can set the
056: * <code>doit</code> field <code>false</code> to cancel the collapse.</div>
057: * <ul>
058: * <li>widget : this</li>
059: * </ul>
060: * </dd>
061: *
062: * <dd><b>Collapse</b> : (widget)<br>
063: * <div>Fires after the panel is collapsed.</div>
064: * <ul>
065: * <li>widget : this</li>
066: * </ul>
067: * </dd>
068: *
069: * <dd><b>BeforeClose</b> : (widget)<br>
070: * <div>Fires before a content panel is closed. Listeners can set the
071: * <code>doit</code> field to <code>false</code> to cancel the operation.</div>
072: * <ul>
073: * <li>widget : this</li>
074: * </ul>
075: * </dd>
076: *
077: * <dd><b>Close</b> : (widget)<br>
078: * <div>Fires after a content panel is closed.</div>
079: * <ul>
080: * <li>widget : this</li>
081: * </ul>
082: * </dd>
083: *
084: * <dt><b>CSS:</b></dt>
085: * <dd>.my-cpanel ( the panel panel)</dd>
086: * <dd>.my-cpanel .my-cpanel-hdr-text (the header text)</dd>
087: * <dd>.my-cpanel-small ( smaller header section )</dd>
088: * <dd>.my-cpanel-small .my-cpanel-hdr-text (the header text)</dd>
089: * </dl>
090: */
091: public class ContentPanel extends WidgetContainer implements
092: SourcesMouseEvents {
093:
094: protected Item header;
095: protected SimplePanel body;
096:
097: private boolean animateCollapse = true;
098: private boolean titleCollapse;
099: private String text, iconStyle;
100: private boolean expanded = true;
101: private boolean animating;
102: private ToolButton collapseBtn;
103: private MouseListenerCollection mouseListeners;
104: private int padding;
105: private String expandHeight;
106: private boolean frame, collapse;
107: private ToolBar toolBar;
108:
109: /**
110: * Creates a new content panel with a header.
111: */
112: public ContentPanel() {
113: this (Style.HEADER);
114: }
115:
116: /**
117: * Creates a new content panel.
118: *
119: * @param style the style information
120: */
121: public ContentPanel(int style) {
122: this (style, "my-cpanel");
123: }
124:
125: /**
126: * Creates a new content panel.
127: *
128: * @param style the style information
129: * @param baseStyle an alternate base style.
130: */
131: public ContentPanel(int style, String baseStyle) {
132: this .style = style;
133: this .baseStyle = baseStyle;
134:
135: if ((style & Style.COLLAPSE) != 0) {
136: collapse = true;
137: }
138: header = new Item() {
139: protected void onClick(BaseEvent be) {
140: super .onClick(be);
141: if (collapse && titleCollapse) {
142: setExpanded(!isExpanded());
143: }
144: }
145: };
146: }
147:
148: /**
149: * Adds a listener interface to receive mouse events.
150: *
151: * @param listener the listener interface to add
152: */
153: public void addMouseListener(MouseListener listener) {
154: if (mouseListeners == null) {
155: mouseListeners = new MouseListenerCollection();
156: }
157: mouseListeners.add(listener);
158: }
159:
160: /**
161: * Returns <code>true</code> if animations are enabled.
162: *
163: * @return the animation state
164: */
165: public boolean getAnimateCollapse() {
166: return animateCollapse;
167: }
168:
169: /**
170: * Returns <code>true</code> if the panel can be collapsed.
171: *
172: * @return the collapse state
173: */
174: public boolean getCollapse() {
175: return collapse;
176: }
177:
178: /**
179: * @return <code>true</code> if the panel is framed.
180: */
181: public boolean getFrame() {
182: return frame;
183: }
184:
185: /**
186: * Returns the panel's header widget.
187: *
188: * @return the header
189: */
190: public Item getHeader() {
191: return header;
192: }
193:
194: public Element getLayoutTarget() {
195: return body.getElement();
196: }
197:
198: /**
199: * Returns the panel's title text.
200: *
201: * @return the text
202: */
203: public String getText() {
204: return text;
205: }
206:
207: /**
208: * Returns <code>true</code> if clicks on the header will expand and
209: * collapse the panel.
210: *
211: * @return the title collpase state
212: */
213: public boolean getTitleCollapse() {
214: return titleCollapse;
215: }
216:
217: /**
218: * Returns the panel's tool bar.
219: *
220: * @return the tool bar or <code>null</code>
221: */
222: public ToolBar getToolBar() {
223: return toolBar;
224: }
225:
226: /**
227: * Returns <code>true</code> if the panel is expanded.
228: *
229: * @return the expand state
230: */
231: public boolean isExpanded() {
232: return expanded;
233: }
234:
235: public void onBaseEvent(BaseEvent be) {
236: super .onBaseEvent(be);
237: switch (be.type) {
238: case Event.ONMOUSEDOWN:
239: case Event.ONMOUSEUP:
240: case Event.ONMOUSEMOVE:
241: case Event.ONMOUSEOVER:
242: case Event.ONMOUSEOUT: {
243: if (mouseListeners != null) {
244: mouseListeners.fireMouseEvent(this , be.event);
245: }
246: break;
247: }
248: }
249: }
250:
251: /**
252: * Removes a previously added listener interface.
253: *
254: * @param listener the listener interface to remove
255: */
256: public void removeMouseListener(MouseListener listener) {
257: if (mouseListeners != null) {
258: mouseListeners.remove(listener);
259: }
260: }
261:
262: /**
263: * Sets the animation state. When <code>true</code>, the expanding and
264: * collpasing of the panel will be animated. Default value is
265: * <code>true</code>.
266: *
267: * @param animateCollapse <code>true</code> if enabled
268: */
269: public void setAnimateCollapse(boolean animateCollapse) {
270: this .animateCollapse = animateCollapse;
271: }
272:
273: /**
274: * Sets whether the panel can be collapsed. Default value is <code>true</code>.
275: * Has no effect if called after the panel is rendered.
276: *
277: * @param collapse <code>true</code> to enable collapsing
278: */
279: public void setCollapse(boolean collapse) {
280: this .collapse = collapse;
281: }
282:
283: /**
284: * Sets the panel's expand state.
285: *
286: * @param expanded <code>true<code> true to expand
287: */
288: public void setExpanded(boolean expanded) {
289: if (animating) {
290: return;
291: }
292: this .expanded = expanded;
293: if (rendered) {
294: if (expanded && fireEvent(Events.BeforeExpand)) {
295: onExpand();
296: } else if (fireEvent(Events.BeforeCollapse)) {
297: onCollapse();
298: }
299: }
300:
301: }
302:
303: /**
304: * Sets whether the panel is framed. Default value is <code>false</code>.
305: * Has no effect if called after the panel is rendered.
306: *
307: * @param frame the frame state
308: */
309: public void setFrame(boolean frame) {
310: this .frame = frame;
311: }
312:
313: /**
314: * Sets the panel's icon style.
315: *
316: * @param style the icon style
317: */
318: public void setIconStyle(String style) {
319: this .iconStyle = style;
320: if (rendered && header != null) {
321: header.setIconStyle(style);
322: }
323: }
324:
325: /**
326: * Sets the padding of the content element.
327: *
328: * @param padding the new padding
329: */
330: public void setPadding(int padding) {
331: this .padding = padding;
332: if (rendered) {
333: DOM.setIntStyleAttribute(body.getElement(), "padding",
334: padding);
335: }
336: }
337:
338: /**
339: * Sets the panel's style. Has no effect if called after the panel is
340: * rendered.
341: *
342: * @param style the style
343: */
344: public void setStyle(int style) {
345: if (!isRendered()) {
346: this .style = style;
347: }
348: }
349:
350: /**
351: * Sets the header's text. Does nothing if the header is not visible.
352: *
353: * @param text the new header text
354: */
355: public void setText(String text) {
356: this .text = text;
357: if (rendered && header != null) {
358: header.setText(text);
359: }
360: }
361:
362: /**
363: * Sets the title collapse state. When <code>true</code>, the panel will be
364: * expanded and collapsed when clicking on the header. Defualt value is
365: * <code>false</code>.
366: *
367: * @param enabled <code>true</code> to enable title collapsing
368: */
369: public void setTitleCollapse(boolean enabled) {
370: this .titleCollapse = enabled;
371: }
372:
373: /**
374: * Sets the panel's tool bar.
375: *
376: * @param toolBar the toolbar
377: */
378: public void setToolBar(ToolBar toolBar) {
379: this .toolBar = toolBar;
380: if (rendered) {
381: MyDOM.insertBefore(toolBar.getElement(), body.getElement());
382: if (isAttached()) {
383: WidgetHelper.doAttach(toolBar);
384: }
385: onResize(getOffsetWidth(), getOffsetHeight());
386: }
387: }
388:
389: protected void afterCollapse() {
390: setHeight(header.getOffsetHeight());
391: expanded = false;
392: animating = false;
393: fireEvent(Events.Collapse);
394: fireEvent(Events.Resize);
395: }
396:
397: protected void afterExpand() {
398: expanded = true;
399: animating = false;
400: layout(true);
401: fireEvent(Events.Expand);
402: fireEvent(Events.Resize);
403: }
404:
405: protected void afterRender() {
406: super .afterRender();
407:
408: if (padding != 0) {
409: setPadding(padding);
410: }
411:
412: if (collapse && !expanded) {
413: setExpanded(expanded);
414: }
415: }
416:
417: protected void doAttachChildren() {
418: super .doAttachChildren();
419: if (header != null)
420: WidgetHelper.doAttach(header);
421: if (toolBar != null)
422: WidgetHelper.doAttach(toolBar);
423: WidgetHelper.doAttach(body);
424: }
425:
426: protected void doDetachChildren() {
427: super .doDetachChildren();
428: if (header != null)
429: WidgetHelper.doDetach(header);
430: if (toolBar != null)
431: WidgetHelper.doDetach(toolBar);
432: WidgetHelper.doDetach(body);
433: }
434:
435: protected void onCollapse() {
436: expandHeight = DOM.getStyleAttribute(getElement(), "height");
437: collapseBtn.changeStyle("my-tool-down");
438: if (animateCollapse && !animating) {
439: animating = true;
440: FXStyle fx = new FXStyle(body.getElement());
441: fx.duration = 300;
442: fx.addListener(Events.EffectComplete, new Listener() {
443: public void handleEvent(BaseEvent be) {
444: afterCollapse();
445: }
446: });
447: fx.slideOut(Style.NORTH);
448: } else {
449: body.setVisible(false);
450: afterCollapse();
451: }
452: }
453:
454: protected void onExpand() {
455: setHeight(expandHeight);
456: collapseBtn.changeStyle("my-tool-up");
457: if (animateCollapse && !animating) {
458: animating = true;
459: FXStyle fx = new FXStyle(body.getElement());
460: fx.duration = 300;
461: fx.addListener(Events.EffectComplete, new Listener() {
462: public void handleEvent(BaseEvent be) {
463: afterExpand();
464: }
465: });
466: fx.slideIn(Style.SOUTH);
467: } else {
468: body.setVisible(true);
469: afterExpand();
470: }
471: }
472:
473: protected void onRender() {
474: setElement(DOM.createDiv());
475: setStyleName(baseStyle);
476: header.baseStyle = baseStyle + "-hdr";
477:
478: MyDOM.setVisibility(getElement(), false);
479:
480: if ((style & Style.HEADER) != 0) {
481: DOM.appendChild(getElement(), header.getElement());
482: header.setWidth("100%");
483: addStyleName(baseStyle + "-showheader");
484:
485: if (text != null) {
486: header.setText(text);
487: }
488: if (iconStyle != null) {
489: header.setIconStyle(iconStyle);
490: }
491:
492: if (collapse) {
493: collapseBtn = new ToolButton("my-tool-up");
494: collapseBtn.addListener(Events.Click, new Listener() {
495: public void handleEvent(BaseEvent be) {
496: be.stopEvent();
497: setExpanded(!isExpanded());
498: }
499: });
500:
501: collapseBtn.render();
502: collapseBtn.setSize(15, 15);
503:
504: header.addWidget(collapseBtn);
505:
506: }
507:
508: if ((style & Style.CLOSE) != 0) {
509: ToolButton closeBtn = new ToolButton("my-tool-close");
510: closeBtn.addSelectionListener(new SelectionListener() {
511: public void widgetSelected(BaseEvent be) {
512: if (fireEvent(Events.BeforeClose)) {
513: removeFromParent();
514: fireEvent(Events.Close);
515: }
516: }
517: });
518: header.addWidget(closeBtn);
519: }
520:
521: }
522:
523: body = new SimplePanel();
524: body.setStyleName(baseStyle + "-body");
525:
526: if (frame) {
527: addStyleName(baseStyle + "-frame");
528: String html = Format.substitute(Markup.BOTTOM_BOX,
529: baseStyle + "-box");
530: DOM.appendChild(getElement(), MyDOM.create(html));
531: Element center = MyDOM.findChild(baseStyle + "-box-mc",
532: getElement());
533: DOM.appendChild(center, body.getElement());
534: } else {
535: DOM.appendChild(getElement(), body.getElement());
536: }
537:
538: if (header != null) {
539: body.addStyleName(baseStyle + "-body-header");
540: }
541:
542: if (toolBar != null) {
543: MyDOM.insertBefore(toolBar.getElement(), body.getElement());
544: }
545:
546: if (!expanded) {
547: addListener(Events.Collapse, new Listener() {
548: public void handleEvent(BaseEvent be) {
549: removeListener(Events.Collapse, this );
550: MyDOM.setVisibility(getElement(), true);
551: }
552: });
553: setExpanded(false);
554: } else {
555: MyDOM.setVisibility(getElement(), true);
556: }
557: }
558:
559: protected void onResize(int width, int height) {
560: if (height != Style.DEFAULT) {
561: if (header != null) {
562: height -= header.getHeight();
563: }
564: if (frame) {
565: height -= 12;
566: }
567: if (toolBar != null) {
568: height -= toolBar.getHeight();
569: }
570: MyDOM.setHeight(body.getElement(), height, true);
571: }
572: if (width != Style.DEFAULT) {
573: if (frame) {
574: width -= 12;
575: }
576: MyDOM.setWidth(body.getElement(), width, true);
577: }
578: layout();
579: }
580:
581: }
|