001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Darrell Meyer <darrell@mygwt.net> - derived implementation
011: *******************************************************************************/package net.mygwt.ui.client.widget;
012:
013: import net.mygwt.ui.client.Events;
014: import net.mygwt.ui.client.MyDOM;
015: import net.mygwt.ui.client.Style;
016:
017: import com.google.gwt.user.client.DOM;
018:
019: /**
020: * A vertical container of <code>ExpandItems</code>.
021: *
022: * When using a style of MULTI the height of the expand bar should not be set
023: * and the expand item containers should only use a FlowLayout. The expand item
024: * container's size is not managed by the expand bar.
025: *
026: * <dl>
027: * <dt><b>Styles:</b></dt>
028: * <dd>SINGLE - Single item can be expanded (Accordian)</dd>
029: * <dd>MULTI - Multiple items can be expanded </dd>
030: * <dd>HEADER - Enables expand / collpase on expand item clicks</dd>
031: *
032: * <dt>Events:</dt>
033: * <dd><b>BeforeAdd</b> : (widget, item, index)<br>
034: * <div>Fires before an item is added or inserted. Listeners can set the
035: * <code>doit</code> field to <code>false</code> to cancel the action.</div>
036: * <ul>
037: * <li>widget : this</li>
038: * <li>item : the item being added</li>
039: * <li>index : the index at which the item will be added</li>
040: * </ul>
041: * </dd>
042: *
043: * <dd><b>BeforeRemove</b> : (widget, item)<br>
044: * <div>Fires before an item is removed. Listeners can set the <code>doit</code>
045: * field to <code>false</code> to cancel the action.</div>
046: * <ul>
047: * <li>widget : this</li>
048: * <li>item : the item being removed</li>
049: * </ul>
050: * </dd>
051: *
052: * <dd><b>BeforeExpand</b> : (widget, item)<br>
053: * <div>Fires before an item is expanded. Listeners can set the
054: * <code>doit</code> field to <code>false</code> to cancel the expand.</div>
055: * <ul>
056: * <li>widget : this</li>
057: * <li>item : the item being expanded</li>
058: * </ul>
059: * </dd>
060: *
061: * <dd><b>BeforeCollapse</b> : (widget, item)<br>
062: * <div>Fires before an item is collapsed. Listeners can set the
063: * <code>doit</code> field to <code>false</code> to cancel the collapse.</div>
064: * <ul>
065: * <li>widget : this</li>
066: * <li>item : the item being expanded</li>
067: * </ul>
068: * </dd>
069: *
070: * <dd><b>Add</b> : (widget, item, index)<br>
071: * <div>Fires after an item has been added or inserted.</div>
072: * <ul>
073: * <li>widget : this</li>
074: * <li>item : the item that was added</li>
075: * <li>index : the index at which the item will be added</li>
076: * </ul>
077: * </dd>
078: *
079: * <dd><b>Remove</b> : (widget, item)<br>
080: * <div>Fires after an item has been removed.</div>
081: * <ul>
082: * <li>widget : this</li>
083: * <li>item : the item being removed</li>
084: * </ul>
085: * </dd>
086: *
087: * <dd><b>Expand</b> : (widget, item)<br>
088: * <div>Fires after an item has been expanded.</div>
089: * <ul>
090: * <li>widget : this</li>
091: * <li>item : the item being expanded</li>
092: * </ul>
093: * </dd>
094: *
095: * <dd><b>Collapse</b> : (widget, item)<br>
096: * <div>Fires ater an item is collapsed.</div>
097: * <ul>
098: * <li>widget : this</li>
099: * <li>item : the item being collapsed</li>
100: * </ul>
101: * </dd>
102: *
103: * <dt><b>CSS:</b></dt>
104: * <dd>.my-expand-bar (the bar itself)</dd>
105: * </dl>
106: */
107: public class ExpandBar extends Container {
108:
109: boolean headerCollapse = false;
110: boolean single = false;
111: private ExpandItem expanded;
112: private int headerHeight = 22;
113:
114: /**
115: * Creates a new SINGLE expand bar.
116: */
117: public ExpandBar() {
118: this (Style.SINGLE);
119: }
120:
121: /**
122: * Creates a new expand bar.
123: *
124: * @param style the style information
125: */
126: public ExpandBar(int style) {
127: this .style = style;
128: }
129:
130: /**
131: * Adds an expand item.
132: *
133: * @param item the item to be added
134: */
135: public void add(ExpandItem item) {
136: insert(item, getItemCount());
137: }
138:
139: /**
140: * Returns the header height.
141: *
142: * @return the height
143: */
144: public int getHeaderHeight() {
145: return headerHeight;
146: }
147:
148: /**
149: * Returns the item at the given index.
150: *
151: * @param index the index of the item to return
152: * @return the item at the given index
153: */
154: public ExpandItem getItem(int index) {
155: if ((index < 0) || (index >= items.size()))
156: return null;
157: return (ExpandItem) items.get(index);
158: }
159:
160: /**
161: * Returns the item count.
162: *
163: * @return the count
164: */
165: public int getItemCount() {
166: return items.size();
167: }
168:
169: /**
170: * Returns the index of the given item.
171: *
172: * @param item the item
173: * @return the items index
174: */
175: public int indexOf(ExpandItem item) {
176: return items.indexOf(item);
177: }
178:
179: /**
180: * Inserts the item at the specified index.
181: *
182: * @param item the item
183: * @param index the insert location
184: */
185: public void insert(ExpandItem item, int index) {
186: if (fireEvent(Events.BeforeAdd, this , item, index)) {
187: items.add(index, item);
188: item.parent = this ;
189: adopt(item);
190:
191: if (rendered) {
192: renderItem(item, index);
193: adjustExpandedSize();
194: updateStyles();
195: }
196: fireEvent(Events.Add, this , item, index);
197: }
198: }
199:
200: public void recalculate() {
201: if (expanded != null) {
202: adjustExpandedSize();
203: }
204: updateStyles();
205: }
206:
207: /**
208: * Removes a item.
209: *
210: * @param item the item
211: */
212: public void remove(ExpandItem item) {
213: if (fireEvent(Events.BeforeRemove, this , item)) {
214: super .remove(item);
215: updateStyles();
216: fireEvent(Events.Remove, this , item);
217: }
218: }
219:
220: /**
221: * Removes all expand items.
222: */
223: public void removeAll() {
224: int size = getItemCount();
225: for (int i = 0; i < size; i++) {
226: ExpandItem item = getItem(0);
227: remove(item);
228: }
229: }
230:
231: /**
232: * Sets the expanded state of the item.
233: *
234: * @param item the item
235: * @param expanded the new expanded state
236: */
237: public void setExpanded(ExpandItem item, final boolean expanded) {
238: item.setExpanded(expanded);
239: }
240:
241: /**
242: * Sets the header height. Default value is 22.
243: *
244: * @param headerHeight the header height
245: */
246: public void setHeaderHeight(int headerHeight) {
247: this .headerHeight = headerHeight;
248: }
249:
250: /**
251: * Sets the expand bar's style. Has no effect if called after the expand bar
252: * has been rendered.
253: *
254: * @param style the style
255: */
256: public void setStyle(int style) {
257: if (!isRendered()) {
258: this .style = style;
259: }
260: }
261:
262: protected void afterCollapse(ExpandItem item) {
263: item.expanded = false;
264: if (expanded == item) {
265: expanded = null;
266: }
267: updateStyles();
268: item.fireEvent(Events.Collapse);
269: fireEvent(Events.Collapse, this , item);
270: }
271:
272: protected void afterExpand(ExpandItem item) {
273: item.expanded = true;
274: updateStyles();
275: item.fireEvent(Events.Expand);
276: fireEvent(Events.Expand, this , item);
277: }
278:
279: protected void onCollapse(ExpandItem item) {
280: item.getContainer().setVisible(false);
281: item.collapseBtn.changeStyle("my-tool-plus");
282: afterCollapse(item);
283: }
284:
285: protected void onExpand(ExpandItem item) {
286: item.getContainer().setVisible(true);
287: adjustExpandedSize();
288: afterExpand(item);
289: item.collapseBtn.changeStyle("my-tool-minus");
290: }
291:
292: protected void onRender() {
293: setElement(DOM.createDiv());
294: setStyleName("my-expand-bar");
295: setStyleAttribute("position", "static");
296:
297: if ((style & Style.HEADER) != 0) {
298: headerCollapse = true;
299: }
300: if ((style & Style.SINGLE) != 0) {
301: single = true;
302: }
303:
304: renderAll();
305: }
306:
307: void collapse(final ExpandItem item) {
308: onCollapse(item);
309: }
310:
311: void expand(final ExpandItem item) {
312: if (single) {
313: if (expanded != null) {
314: onCollapse(expanded);
315: }
316: expanded = item;
317: }
318: onExpand(item);
319: }
320:
321: protected void afterRender() {
322: // TODO Auto-generated method stub
323: super .afterRender();
324: }
325:
326: protected void onLoad() {
327: // TODO Auto-generated method stub
328: super .onLoad();
329: }
330:
331: private void adjustExpandedSize() {
332: if (single && expanded != null) {
333: expanded.getContainer().setWidth(getWidth(true));
334: if (single) {
335: expanded.getContainer().setHeight(10);
336: int h = getOffsetHeight();
337: int hh = 0;
338: for (int i = 0; i < getItemCount(); i++) {
339: h -= getItem(i).header.getHeight();
340: }
341: int th = h - hh;
342: expanded.getContainer().setHeight(th - 1);
343: }
344: }
345: }
346:
347: private void renderAll() {
348: int size = getItemCount();
349: for (int i = 0; i < size; i++) {
350: ExpandItem item = getItem(i);
351: renderItem(item, i);
352: }
353: }
354:
355: private void renderItem(ExpandItem item, int index) {
356: String o = single ? "auto" : "visible";
357: item.content.setStyleAttribute("overflow", o);
358: if (headerCollapse) {
359: item.setStyleAttribute("cursor", "pointer");
360: }
361: DOM.insertChild(getElement(), item.getElement(), index);
362: item.setHeight(headerHeight);
363: }
364:
365: private void updateStyles() {
366: String s = "my-expand-item-noborder";
367: for (int i = 0; i < getItemCount(); i++) {
368: ExpandItem item = getItem(i);
369: boolean add = !item.isExpanded();
370: MyDOM.setStyleName(item.getElement(), s, add);
371: }
372: if (getItemCount() > 0) {
373: ExpandItem last = getItem(getItemCount() - 1);
374: if (single && expanded != null) {
375: MyDOM.setStyleName(last.getElement(), s, !last
376: .isExpanded());
377: } else if (single) {
378: MyDOM.setStyleName(last.getElement(), s, false);
379: } else {
380: MyDOM.setStyleName(last.getElement(), s, false);
381: }
382: }
383:
384: }
385:
386: }
|