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}