package votorola.s.gwt.stage.talk; // Copyright 2012, Christian Weilbach. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import java.util.Date; import java.util.Iterator; import votorola.a.web.gwt.App; import votorola.g.hold.Hold; import votorola.g.hold.Spool; import votorola.g.hold.Spool1; import votorola.g.lang.Warning; import votorola.g.web.gwt.GWTX; import votorola.g.web.gwt.event.Change; import votorola.g.web.gwt.event.ChangeHandler; import votorola.g.web.gwt.event.PropertyChange; import votorola.g.web.gwt.event.PropertyChangeHandler; import votorola.s.gwt.stage.Stage; import votorola.s.gwt.stage.StageV; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JsArray; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiFactory; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Widget; import com.google.web.bindery.event.shared.HandlerRegistration; /** * A view for difference messages. Views are on a chain from right to left, * clipped on the right side of C. When the view is filled with data, newest * data is on the right between 0 and F. UPDATE_BUTTON is the inline button to * kick the harvesters through {@linkplain votorola.s.wap.KickWAP}. * *
 * VIEW_COUNT... clipped ... C ... hidden views ... F ... filled ... 1 0 UPDATE_BUTTON
 * 
* */ public final class TalkTrackV extends Composite { private static TalkTrackV instance; { if (instance != null) throw new IllegalStateException(); // grep "instance" for reason instance = TalkTrackV.this; } /** * Returns the {@linkplain StageV staged instance} of PolltrackV, or null if * none is staged. */ public static TalkTrackV i(final StageV stageV) { final Iterator ww = stageV.iterator(); while (ww.hasNext()) { final Widget w = ww.next(); if (w instanceof TalkTrackV) return (TalkTrackV) w; } return null; } // - M o d e l ------------------------------------------------------------ /** * The number of views created by the view on startup and used to fill in * data. */ public final static int VIEW_COUNT = 200; private final TalkTrack track; private final Spool spool = new Spool1(); private final ChangeHandler trackHandler = new ChangeHandler() { @Override public void onChange(Change e) { stageUpdate(); } }; private final PropertyChangeHandler stageHandler = new PropertyChangeHandler() { @Override public void onPropertyChange(PropertyChange e) { if (e.propertyName().equals("actorName")) { updateButton.reset(); } } }; // - U i ------------------------------------------------------------ private final TalkV[] talkVs = new TalkV[VIEW_COUNT]; private final String historySeparatorUrl = App.getServletContextLocation() + "/stage/talk/historySeparator.png"; private final class HistorySeparator extends Image { HistorySeparator() { super(historySeparatorUrl); addStyleName("HistorySeparator"); } }; private final HistorySeparator[] historySeparators = new HistorySeparator[VIEW_COUNT+6]; @Warning("non-API") interface UiBinderI extends UiBinder { } { final UiBinderI uiBinder = GWT.create(UiBinderI.class); initWidget(uiBinder.createAndBindUi(TalkTrackV.this)); } @UiField @Warning("non-API") HTMLPanel panel; @UiField @Warning("non-API") UpdateButton updateButton; @UiFactory @Warning("non-API") HeadsUpDisplay newHeadsUpDisplay() { return new HeadsUpDisplay( TalkTrackV.this ); } @UiFactory UpdateButton makeUpdateButton() { return new UpdateButton(this); } /** * Constructs a TalkTrackV. * */ public TalkTrackV(final TalkTrack _track, final StageV _stageV) { track = _track; spool.add(new Hold() { final HandlerRegistration hR = GWTX.i().bus() .addHandlerToSource(Change.TYPE, /* source */ _track, trackHandler); public void release() { hR.removeHandler(); } }); spool.add(new Hold() { final HandlerRegistration hR = GWTX.i().bus() .addHandlerToSource(PropertyChange.TYPE, /* source */ Stage.i(), stageHandler); public void release() { hR.removeHandler(); } }); // allow two markers at the beginning if discussion is old historySeparators[0] = new HistorySeparator(); historySeparators[0].setVisible(false); panel.add(historySeparators[0]); historySeparators[1] = new HistorySeparator(); historySeparators[1].setVisible(false); panel.add(historySeparators[1]); historySeparators[2] = new HistorySeparator(); historySeparators[2].setVisible(false); panel.add(historySeparators[2]); // direction is rtl, so 0 is rightest. for (int i = 0; i < VIEW_COUNT; i++) { historySeparators[i+3] = new HistorySeparator(); historySeparators[i+3].setVisible(false); panel.add(historySeparators[i+3]); talkVs[i] = new TalkV(spool); panel.add(talkVs[i]); } // allow two markers at the end if discussion is young historySeparators[VIEW_COUNT] = new HistorySeparator(); historySeparators[VIEW_COUNT].setVisible(false); panel.add(historySeparators[VIEW_COUNT]); historySeparators[VIEW_COUNT+1] = new HistorySeparator(); historySeparators[VIEW_COUNT+1].setVisible(false); panel.add(historySeparators[VIEW_COUNT+1]); historySeparators[VIEW_COUNT+2] = new HistorySeparator(); historySeparators[VIEW_COUNT+2].setVisible(false); panel.add(historySeparators[VIEW_COUNT+2]); } protected @Override void onUnload() { spool.unwind(); super.onUnload(); } private void stageUpdate() { JsArray dMsgs = track.messages(); if (dMsgs == null) { return; } final long day = 1000 * 60 * 60 * 24; final long week = day * 7; final long month = day * 30; final long year = day * 365; // manage history separators boolean changed = false; final long now = new Date().getTime(); long prev = now; int separatorsLeft = 3; for (int i = 0; i < VIEW_COUNT; i++) { if (i >= dMsgs.length()) { talkVs[i].setMsg(null); historySeparators[i].setVisible(false); } else { final DiffMessageJS dMsg = dMsgs.get(i); final long current = (long)dMsg.sentDate(); if (i==0) { // show separators at end if discussion is young if(current < now-week) { historySeparators[0].setVisible(true); separatorsLeft--; } else { historySeparators[0].setVisible(false); } if(current < now-month) { historySeparators[1].setVisible(true); separatorsLeft--; } else { historySeparators[1].setVisible(false); } if(current < now-year) { historySeparators[2].setVisible(true); separatorsLeft--; } else { historySeparators[2].setVisible(false); } } if (!DiffMessageJS.EQUATOR.equals(talkVs[i].getMsg(), dMsgs.get(i))) { talkVs[i].setMsg(dMsg); changed = true; } if( prev > now-week && current < now-week && i!=0 // otherwise it is set in the block above || prev > now-month && current < now-month && i!=0 || prev > now-year && current < now-year && i!=0 ) { historySeparators[i+3].setVisible(true); separatorsLeft--; } else { historySeparators[i+3].setVisible(false); } prev = current; } } // show separators at end if discussion is young if(prev < now-week && separatorsLeft > 0) { historySeparators[VIEW_COUNT].setVisible(true); } else { historySeparators[VIEW_COUNT].setVisible(false); } if(prev < now-month && separatorsLeft > 0) { historySeparators[VIEW_COUNT].setVisible(true); } else { historySeparators[VIEW_COUNT].setVisible(false); } if(prev < now-year && separatorsLeft > 0) { historySeparators[VIEW_COUNT+1].setVisible(true); } else { historySeparators[VIEW_COUNT+1].setVisible(false); } updateButton.update(changed); } }