001: package org.zkforge.timeline;
002:
003: import java.util.ArrayList;
004: import java.util.Date;
005: import java.util.Iterator;
006: import java.util.List;
007: import java.util.SortedSet;
008: import java.util.TimeZone;
009: import java.util.TreeSet;
010:
011: import org.zkforge.json.simple.JSONArray;
012: import org.zkforge.timeline.data.OccurEvent;
013: import org.zkforge.timeline.decorator.HighlightDecorator;
014: import org.zkforge.timeline.event.BandScrollEvent;
015: import org.zkforge.timeline.impl.TimelineComponent;
016: import org.zkforge.timeline.util.TimelineUtil;
017: import org.zkoss.lang.Objects;
018: import org.zkoss.xml.HTMLs;
019: import org.zkoss.zk.au.AuScript;
020: import org.zkoss.zk.au.Command;
021: import org.zkoss.zk.ui.Component;
022: import org.zkoss.zk.ui.UiException;
023: import org.zkoss.zk.ui.event.Event;
024: import org.zkoss.zk.ui.event.EventListener;
025: import org.zkoss.zul.ListModel;
026: import org.zkoss.zul.ListModelList;
027: import org.zkoss.zul.event.ListDataEvent;
028: import org.zkoss.zul.event.ListDataListener;
029:
030: /**
031: * The Bandinfo component.
032: *
033: * <p>
034: * See also <a href="http://simile.mit.edu/timeline">MIT Timeline</a>
035: *
036: * @author WeiXing Gu, China
037: */
038: public class Bandinfo extends TimelineComponent {
039:
040: private ListModel _model;
041:
042: private SortedSet _events = new TreeSet();//
043:
044: private ArrayList _eventList = new ArrayList();// store the event's index;
045:
046: private Date _min;
047:
048: private Date _max;
049:
050: private transient ListDataListener _dataListener;
051:
052: private String _width = "70%";
053:
054: private String _intervalUnit = "month";
055:
056: private int _intervalPixels = 100;
057:
058: private boolean _highlight = true;
059:
060: private boolean _showEventText = true;
061:
062: private String _syncWith;
063:
064: private TimeZone _timeZone = TimeZone.getDefault();
065:
066: private float _trackHeight = (float) 1.5;
067:
068: private float _trackGap = (float) 0.5;
069:
070: private Date _date = new Date();
071:
072: private String _eventSourceUrl;
073:
074: // public String getOuterAttrs() {
075: //
076: // return "";
077: // }
078:
079: // public String getContent() {
080: //
081: // return "";
082: // }
083:
084: public String getInnerAttrs() {
085: final String attrs = super .getInnerAttrs();
086: final StringBuffer sb = new StringBuffer(64);
087: if (attrs != null) {
088: sb.append(attrs);
089: }
090:
091: HTMLs.appendAttribute(sb, "z.pid", getParent().getUuid());
092: HTMLs.appendAttribute(sb, "z.highlight", isHighlight());
093: HTMLs.appendAttribute(sb, "z.width", getWidth());
094: HTMLs.appendAttribute(sb, "z.intervalUnit", TimelineUtil
095: .convertIntervalUnitFromName(_intervalUnit));
096: HTMLs.appendAttribute(sb, "z.intervalPixels",
097: getIntervalPixels());
098: HTMLs.appendAttribute(sb, "z.showEventText", isShowEventText());
099: HTMLs.appendAttribute(sb, "z.timeZone", _timeZone
100: .getRawOffset()
101: / (1000 * 60 * 60));
102: HTMLs.appendAttribute(sb, "z.trackHeight", String
103: .valueOf(getTrackHeight()));
104: HTMLs.appendAttribute(sb, "z.syncWith",
105: findSyncWithIndex(_syncWith));
106: HTMLs.appendAttribute(sb, "z.trackGap", String
107: .valueOf(getTrackGap()));
108:
109: HTMLs.appendAttribute(sb, "z.date", TimelineUtil
110: .formatDateTime(getDate()));
111: HTMLs.appendAttribute(sb, "z.eventSourceUrl", _eventSourceUrl);
112: return sb.toString();
113: }
114:
115: public void setParent(Component parent) {
116: if (parent != null && !(parent instanceof Timeline))
117: throw new UiException("Unsupported parent for bandinfo: "
118: + parent);
119: super .setParent(parent);
120: }
121:
122: /**
123: * @return the width
124: */
125: public String getWidth() {
126: return _width;
127: }
128:
129: /**
130: * @param width
131: * the width to set
132: */
133: public void setWidth(String width) {
134: if (!Objects.equals(_width, width)) {
135: _width = width;
136: // smartUpdate("z.width", _width);
137: invalidate();
138: }
139: }
140:
141: /**
142: * @return the intervalPixels
143: */
144: public int getIntervalPixels() {
145: return _intervalPixels;
146: }
147:
148: /**
149: * @param intervalPixels
150: * the intervalPixels to set
151: */
152: public void setIntervalPixels(int intervalPixels) {
153: if (intervalPixels != _intervalPixels) {
154: _intervalPixels = intervalPixels;
155: // smartUpdate("z.intervalPixels", intervalPixels);
156: invalidate();
157: }
158: }
159:
160: /**
161: * @return the intervalUnit
162: */
163: public String getIntervalUnit() {
164: return _intervalUnit;
165: }
166:
167: /**
168: * @param intervalUnit
169: * the intervalUnit to set
170: */
171: public void setIntervalUnit(String intervalUnit) {
172: if (!Objects.equals(intervalUnit, _intervalUnit)) {
173: _intervalUnit = intervalUnit;
174: // smartUpdate("z.intervalUnit", intervalUnit);
175: invalidate();
176: }
177:
178: }
179:
180: /**
181: * @return the showEventText
182: */
183: public boolean isShowEventText() {
184: return _showEventText;
185: }
186:
187: /**
188: * @param showEventText
189: * the showEventText to set
190: */
191: public void setShowEventText(boolean showEventText) {
192: if (showEventText != _showEventText) {
193: _showEventText = showEventText;
194: // smartUpdate("z.showEventText", showEventText);
195: invalidate();
196: }
197: }
198:
199: private String findSyncWithIndex(String id) {
200: Timeline parent = (Timeline) getParent();
201: List l = parent.getChildren();
202: for (int i = 0; i < l.size(); i++) {
203: Bandinfo b = (Bandinfo) l.get(i);
204:
205: if (b.getId().equals(id)) {
206: return String.valueOf(i);
207: }
208: }
209: return "";
210: }
211:
212: /**
213: * @return the _syncWith
214: */
215: public String getSyncWith() {
216: return _syncWith;
217: }
218:
219: /**
220: * @param syncWith
221: * the _syncWith to set
222: */
223: public void setSyncWith(String syncWith) {
224: if (!Objects.equals(syncWith, _syncWith)) {
225: _syncWith = syncWith;
226: // smartUpdate("z.syncWith", syncIndex);
227: invalidate();
228: }
229:
230: }
231:
232: /**
233: * @return the highlight
234: */
235: public boolean isHighlight() {
236: return _highlight;
237: }
238:
239: /**
240: * @param highlight
241: * the _highlight to set
242: */
243: public void setHighlight(boolean highlight) {
244: if (highlight != _highlight) {
245: _highlight = highlight;
246: // smartUpdate("z.highlight", highlight);
247: invalidate();
248: }
249: }
250:
251: public TimeZone getTimeZone() {
252: return _timeZone;
253: }
254:
255: public void setTimeZone(TimeZone timeZone) {
256: if (!Objects.equals(timeZone, _timeZone)) {
257: _timeZone = timeZone;
258:
259: // smartUpdate("z.timeZone", timeZone.toString());
260: invalidate();
261: }
262: }
263:
264: public float getTrackGap() {
265: return _trackGap;
266: }
267:
268: public void setTrackGap(float trackGap) {
269: if (trackGap != _trackGap) {
270: _trackGap = trackGap;
271: // smartUpdate("z.trackGap", String.valueOf(trackGap));
272: invalidate();
273: }
274: }
275:
276: public float getTrackHeight() {
277: return _trackHeight;
278: }
279:
280: public void setTrackHeight(float trackHeight) {
281: if (trackHeight != _trackHeight) {
282: _trackHeight = trackHeight;
283: // smartUpdate("z.trackHeight", String.valueOf(trackHeight));
284: invalidate();
285: }
286: }
287:
288: public Date getDate() {
289: return _date;
290: }
291:
292: public void setDate(Date date) {
293: if (!Objects.equals(date, _date)) {
294: _date = date;
295: // smartUpdate("z.date", date.toString());
296: invalidate();
297: }
298: }
299:
300: // -- Component --//
301: public boolean insertBefore(Component child, Component insertBefore) {
302: if (!(child instanceof Hotzone))
303: throw new UiException("Unsupported child for timeline: "
304: + child);
305: return super .insertBefore(child, insertBefore);
306: }
307:
308: public void addOccurEvent(OccurEvent event) {
309: // if (!Objects.equals(event, _event)) {
310: // _event = event;
311: if (event == null)
312: return;
313:
314: response("addOccurEvent" + event.getId(), new AuScript(this ,
315: "zkBandInfo.addOccurEvent(\"" + getUuid() + "\"" + ","
316: + event.toString() + ")"));
317:
318: // }
319: }
320:
321: public void removeOccurEvent(OccurEvent event) {
322: if (event == null)
323: return;
324: response("removeOccurEvent" + event.getId(), new AuScript(this ,
325: "zkBandInfo.removeOccurEvent(\"" + getUuid() + "\""
326: + "," + "\"" + event.getId() + "\")"));
327: }
328:
329: public void modifyOccurEvent(OccurEvent event) {
330: if (event == null)
331: return;
332: response("modifyOccurEvent" + event.getId(), new AuScript(this ,
333: "zkBandInfo.modifyOccurEvent(\"" + getUuid() + "\""
334: + "," + event.toString() + ")"));
335: }
336:
337: // -- Component --//
338:
339: public String getEventSourceUrl() {
340: return _eventSourceUrl;
341: }
342:
343: public void setEventSourceUrl(String eventSourceUrl) {
344: if (!Objects.equals(eventSourceUrl, _eventSourceUrl)) {
345: _eventSourceUrl = eventSourceUrl;
346: smartUpdate("z.eventSourceUrl", eventSourceUrl);
347: }
348: }
349:
350: /*
351: * (non-Javadoc)
352: *
353: * @see org.zkoss.zk.ui.AbstractComponent#invalidate()
354: */
355: // @Override
356: public void invalidate() {
357: // TODO Auto-generated method stub
358: super .invalidate();
359: if (getParent() != null)
360: getParent().invalidate();
361: }
362:
363: public void addManyOccurEvents(Iterator iter) {
364: if (iter == null)
365: return;
366: JSONArray list = new JSONArray();
367: while (iter.hasNext()) {
368: OccurEvent e = (OccurEvent) iter.next();
369: list.add(e);
370: }
371:
372: response("addManyOccurEvent" + iter.hashCode(), new AuScript(
373: this , "zkBandInfo.addManyOccurEvent(\"" + getUuid()
374: + "\"" + "," + list.toString() + ")"));
375:
376: }
377:
378: public void addHighlightDecorator(HighlightDecorator hd) {
379: // decorators.add(hd);
380: if (hd == null)
381: return;
382: response("addHighlightDecorator" + hd.getId(), new AuScript(
383: this , "zkBandInfo.addHighlightDecorator(\"" + getUuid()
384: + "\"" + "," + hd.toString() + ")"));
385: }
386:
387: public void removeHighlightDecorator(HighlightDecorator hd) {
388: // decorators.remove(hd);
389: if (hd == null)
390: return;
391: response("removeHighlightDecorator" + hd.getId(), new AuScript(
392: this , "zkBandInfo.removeHighlightDecorator(\""
393: + getUuid() + "\"" + "," + hd.getId() + ")"));
394:
395: }
396:
397: public void showLoadingMessage(boolean show) {
398: if (show) {
399: response("showLoadingMessage", new AuScript(this ,
400: "zkTimeline.showLoadingMessage(\""
401: + getParent().getUuid() + "\"" + ")"));
402: } else {
403: response("hideLoadingMessage", new AuScript(this ,
404: "zkTimeline.hideLoadingMessage(\""
405: + getParent().getUuid() + "\"" + ")"));
406: }
407:
408: }
409:
410: public void scrollToCenter(Date date) {
411: if (date == null)
412: return;
413: response("scrollToCenter", new AuScript(this ,
414: "zkBandInfo.scrollToCenter(\"" + getUuid() + "\""
415: + ",\"" + date.toString() + "\")"));
416: }
417:
418: static {
419: new BandScrollCommand("onBandScroll", Command.IGNORE_OLD_EQUIV);
420: }
421:
422: /**
423: * @return the model
424: */
425: public ListModel getModel() {
426: return _model;
427: }
428:
429: /**
430: * @param model
431: * the model to set
432: */
433: public void setModel(ListModel model) {
434: if (_model != null)
435: _model.removeListDataListener(_dataListener);
436: _model = model;
437:
438: if (_model != null) {
439: _dataListener = new ListDataListener() {
440: public void onChange(ListDataEvent event) {
441: // TODO Auto-generated method stub
442: onListDataChange(event);
443: }
444: };
445: _model.addListDataListener(_dataListener);
446: _events.clear();
447: _eventList.clear();
448: invalidate();
449:
450: int count = _model.getSize();
451: for (int i = 0; i < count; i++) {
452: Object o = _model.getElementAt(i);
453: _events.add(o);
454: _eventList.add(o);
455: }
456: }
457: // listening band scroll event
458: addEventListener("onBandScroll", new BandScrollListener());
459: }
460:
461: private class BandScrollListener implements EventListener {
462:
463: public boolean isAsap() {
464: // TODO Auto-generated method stub
465: return true;
466: }
467:
468: public void onEvent(Event event) {
469: // TODO Auto-generated method stub
470: BandScrollEvent e = (BandScrollEvent) event;
471: Date newmin = e.getMin();
472: Date newmax = e.getMax();
473: if (_min == null && _max == null) {
474: _min = newmin;
475: _max = newmax;
476: syncModel(_min, _max);
477: }
478:
479: if (newmin.compareTo(_min) < 0) {
480: syncModel(newmin, _min);
481: _min = newmin;
482: }
483:
484: if (newmax.compareTo(_max) > 0) {
485: syncModel(_max, newmax);
486: _max = newmax;
487: }
488:
489: }
490: };
491:
492: protected void syncModel(Date min, Date max) {
493: OccurEvent e1 = new OccurEvent();
494: e1.setStart(min);
495: OccurEvent e2 = new OccurEvent();
496: e2.setStart(max);
497: SortedSet ss = _events.subSet(e1, e2);
498: Iterator iter = ss.iterator();
499: // System.out.println("live date :"+ss.size());
500: addManyOccurEvents(iter);
501:
502: }
503:
504: protected void onListDataChange(ListDataEvent event) {
505: // TODO Auto-generated method stub
506: int lower = event.getIndex0();
507: int upper = event.getIndex1();
508: // System.out.println("lower=" + lower + "upper=" + upper);
509: OccurEvent e1 = new OccurEvent();
510: e1.setStart(_min);
511: OccurEvent e2 = new OccurEvent();
512: e2.setStart(_max);
513: switch (event.getType()) {
514: case ListDataEvent.INTERVAL_ADDED:
515: for (int i = lower; i <= upper; i++) {
516: OccurEvent oe = (OccurEvent) _model.getElementAt(i);
517: _events.add(oe);
518: _eventList.add(oe);
519:
520: if (oe.compareTo(e1) >= 0 && oe.compareTo(e2) <= 0)// lazy-load
521: this .addOccurEvent(oe);// if the event is in [_min,_max]
522: // then display it.
523: }
524: break;
525: case ListDataEvent.INTERVAL_REMOVED:
526:
527: for (int i = upper; i >= lower; i--) {
528: OccurEvent oe = (OccurEvent) _eventList.get(i);
529: _events.remove(oe);
530: _eventList.remove(oe);
531: this .removeOccurEvent(oe);
532: oe = null;
533: }
534: break;
535: case ListDataEvent.CONTENTS_CHANGED:
536: for (int i = lower; i <= upper; i++) {
537: OccurEvent oe = (OccurEvent) _model.getElementAt(i);
538: OccurEvent e = (OccurEvent) _eventList.get(i);
539:
540: _eventList.set(i, oe);
541:
542: _events.remove(e);
543: _events.add(oe);
544: this .removeOccurEvent(e);
545: if (oe.compareTo(e1) >= 0 && oe.compareTo(e2) <= 0)
546: // if the event is in [_min,_max]
547: this .addOccurEvent(oe);// then display it.
548:
549: }
550: break;
551:
552: }
553: }
554:
555: }
|