001package votorola.s.gwt.scene.feed; // Copyright 2010-2011, Michael Allan. 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. 002 003import com.google.gwt.core.client.*; 004import com.google.web.bindery.event.shared.*; 005import com.google.gwt.view.client.*; 006import com.google.gwt.user.client.ui.*; 007import java.util.List; 008import votorola.a.web.gwt.*; 009import votorola.s.gwt.scene.*; 010import votorola.s.gwt.scene.diff.*; 011import votorola.s.gwt.scene.dum.*; 012import votorola.g.hold.*; 013import votorola.g.web.gwt.*; 014import votorola.g.web.gwt.event.*; 015 016/** A temporal sequence of real-world events (bites) unfolding in semi-real time. 017 */ 018public abstract class Feed extends ListDataProvider<BiteJS> 019{ 020 021 022 /** Constructs a Feed. 023 */ 024 public Feed( List<BiteJS> listToWrap ) { super( listToWrap ); } 025 026 027 028 // ==================================================================================== 029 030 031 /** Short names designating particular feed types, suitable for use in a ({@linkplain 032 * Scenes#cCompositionSwitch() composition switch}). Each name begins with a single 033 * ASCII uppercase letter which may be followed by zero or more ASCII lowercase 034 * letters and digits. 035 * 036 * @see votorola.s.gwt.scene.Scene.SwitchMnemonic 037 */ 038 public static enum SwitchMnemonic 039 { 040 041 042 /** Designating a {@linkplain DiffFeed DiffFeed}. 043 */ 044 D 045 { 046 public Hold emplace() 047 { 048 final Spool spool = new Spool1(); 049 final DiffFeed feed = new DiffFeed(); 050 spool.add( feed ); 051 052 final FeedVCellList feedV = new FeedVCellList( new DiffBiteVCell() ); 053 feed.addDataDisplay( feedV ); 054 addView( feedV, spool ); 055 return new SpoolHold( spool ); 056 } 057 }, 058 059 060 061 /** Designating a {@linkplain DummyFeed DummyFeed}. 062 */ 063 Dum 064 { 065 public Hold emplace() 066 { 067 final Spool spool = new Spool1(); 068 final DummyFeed feed = new DummyFeed(); 069 spool.add( feed ); 070 071 final FeedVCellList feedV = new FeedVCellList( new DummyBiteVCell() ); 072 feed.addDataDisplay( feedV ); 073 addView( feedV, spool ); 074 return new SpoolHold( spool ); 075 } 076 }; 077 078 079 080 // -------------------------------------------------------------------------------- 081 082 083 private static void addView( final Widget feedV, final Spool spool ) 084 { 085 ScenesV.i().setFeed( feedV ); 086 spool.add( new Hold() { public void release() { feedV.removeFromParent(); }}); 087 } 088 089 090 091 /** Constructs and emplaces the designated feed model, views and controllers. 092 * 093 * @return a hold the release of which undoes the emplacement. 094 */ 095 public abstract Hold emplace(); 096 097 098 } 099 100 101 102 // ==================================================================================== 103 104 105 /** A filter-based feed scoper that works from an unfiltered reference list. 106 */ 107 protected final class UnScoper implements ScopeChangeHandler, PropertyChangeHandler, 108 Scheduler.RepeatingCommand 109 { 110 111 112 /** Constructs an UnScoper. 113 * 114 * @see #listMaxSize() 115 * @see #unList() 116 * @param spool for release of internal holds. When unwound, this instance will 117 * release its internal holds and become disabled. 118 */ 119 public UnScoper( int _listMaxSize, List<BiteJS> _unList, final Spool spool ) 120 { 121 listMaxSize = _listMaxSize; 122 unList = _unList; 123 assert listMaxSize <= FeedVCellList.PAGE_SIZE: "listMaxSize cannot exceed " + FeedVCellList.PAGE_SIZE; 124 125 spool.add( new Hold() 126 { 127 final HandlerRegistration hR = ScopeChangeEvent.addHandler( UnScoper.this ); 128 public void release() { hR.removeHandler(); } 129 }); 130 spool.add( new Hold() 131 { 132 final HandlerRegistration hR = GWTX.i().bus().addHandlerToSource( 133 PropertyChange.TYPE, /*source*/Scenes.i(), UnScoper.this ); 134 public void release() { hR.removeHandler(); } 135 }); 136 } 137 138 139 140 private void executeLater() { spreadScheduler.schedule(); } 141 // Spread the load for a snappier response during scene or scope changes. This 142 // also has the effect of allowing some extra time for scoping to initialize. 143 // Geoscoping in particular is slow to learn the extent of a newly constructed 144 // geomap. 145 146 147 148 private final CoalescingSchedulerR spreadScheduler = new CoalescingSchedulerR( 149 new CoalescingSchedulerR.FixedPeriod(500/*ms*/), UnScoper.this ); 150 151 152 153 // -------------------------------------------------------------------------------- 154 155 156 /** The length limit for the feed list. The scoper will not allow it to grow 157 * longer regardless of the degree of filtering. This limit has no bearing on 158 * the capacity of the {@linkplain #unList() unfiltered reference list}, which 159 * ought normally to be much larger. 160 * 161 * @see Feed#getList() 162 */ 163 public int listMaxSize() { return listMaxSize; }; 164 165 166 private final int listMaxSize; 167 168 169 170 /** The unfiltered reference list of bites from which the filtered list is derived 171 * during scoping. 172 */ 173 public final List<BiteJS> unList() { return unList; } 174 175 176 private final List<BiteJS> unList; 177 178 179 180 // - P r o p e r t y - C h a n g e - H a n d l e r -------------------------------- 181 182 183 public void onPropertyChange( final PropertyChange e ) 184 { 185 if( !"scene".equals( e.propertyName() )) return; 186 187 if( Scenes.i().scene() == Scene0.i() ) return; // in transition, ignore it 188 189 executeLater(); 190 } 191 192 193 194 // - S c h e d u l e r . R e p e a t i n g - C o m m a n d ------------------------ 195 196 197 public boolean execute() 198 { 199 final Scene scene = Scenes.i().scene(); 200 final List<BiteJS> list = getList(); 201 list.clear(); 202 for( final BiteJS bite: unList ) 203 { 204 if( !scene.inScope( bite )) continue; 205 206 list.add( bite ); 207 if( list.size() >= listMaxSize ) break; 208 } 209 210 return /*to repeat*/false; 211 } 212 213 214 215 // - S c o p e - C h a n g e - H a n d l e r -------------------------------------- 216 217 218 public void onScopeChange( final ScopeChangeEvent e ) { executeLater(); } 219 220 221 } 222 223 224 225}