Subversion Repository Public Repository

litesoft

Diff Revisions 556 vs 557 for /trunk/GWT_Sandbox/MultiModule/common/src/org/litesoft/sandbox/infrastructure/client/PlaceActivityManager.java

Diff revisions: vs.
  @@ -1,44 +1,31 @@
1 1 package org.litesoft.sandbox.infrastructure.client;
2 2
3 - import java.util.*;
4 -
5 3 import org.litesoft.logger.*;
6 4 import org.litesoft.sandbox.anywhere.util.*;
5 + import org.litesoft.sandbox.infrastructure.client.internal.*;
7 6
8 7 import com.google.gwt.event.logical.shared.*;
9 - import com.google.gwt.event.shared.*;
10 8 import com.google.gwt.place.shared.*;
11 9 import com.google.gwt.user.client.*;
12 10 import com.google.gwt.user.client.ui.*;
13 11
14 - public class PlaceActivityManager<CommonActivityParam extends CommonActivityParameter> extends ActivityFactoryRegistry implements PlaceChanger
12 + public class PlaceActivityManager<CommonActivityParam extends CommonActivityParameter> implements PlaceChanger
15 13 {
16 - private static Logger LOGGER = LoggerFactory.getLogger( PlaceActivityManager.class );
14 + private static final Logger LOGGER = LoggerFactory.getLogger( PlaceActivityManager.class );
17 15
18 - private static final Activity NULL_ACTIVITY = new AbstractActivity()
19 - {
20 - @Override
21 - public void start( AcceptsOneWidget panel )
22 - {
23 - panel.setWidget( new Label( "!" ) );
24 - }
25 - };
16 + private final PanelPlaceActivityHelper mActivityHelper;
26 17
27 - private final AcceptsOneWidget mPanel;
28 18 private final CommonActivityParam mCommonActivityParam;
29 19
30 20 private final PlaceHistoryMapper mMapper;
31 21 private final WindowClose mWindowClose;
32 22 private final Historian mHistorian;
33 - private Place mCurrentPlace = Place.NOWHERE;
34 - private Place mPendingCodePlace, mPendingAsyncPlace;
35 - private Activity mCurrentActivity = NULL_ACTIVITY;
36 - private Activity mPendingActivity;
23 + private Place mPendingCodePlace;
37 24
38 25 public PlaceActivityManager( AcceptsOneWidget pPanel, PlaceHistoryMapper pMapper, WindowClose pWindowClose, Historian pHistorian, CommonActivityParam pCommonActivityParam )
39 26 {
40 - mPanel = pPanel;
41 - mCommonActivityParam = (pCommonActivityParam != null) ? pCommonActivityParam : DefaultCommonActivityParam.<CommonActivityParam>createInstance();
27 + mCommonActivityParam = (pCommonActivityParam != null) ? pCommonActivityParam : createDefaultCommonActivityParam();
28 + mActivityHelper = new PanelPlaceActivityHelper<CommonActivityParam>( pPanel, mCommonActivityParam );
42 29 mMapper = (pMapper != null) ? pMapper : new PlaceRegistry( mCommonActivityParam );
43 30 mWindowClose = (pWindowClose != null) ? pWindowClose : new WindowCloseImpl();
44 31 mWindowClose.addWindowClosingHandler( new Window.ClosingHandler()
  @@ -91,7 +78,7 @@
91 78 @Override
92 79 public Place getWhere()
93 80 {
94 - return mCurrentPlace;
81 + return mActivityHelper.getCurrentPlace();
95 82 }
96 83
97 84 /**
  @@ -107,16 +94,17 @@
107 94 @Override
108 95 public GoToPlace goTo( Place pNewPlace )
109 96 {
110 - pNewPlace = UtilsCommon.deNull( pNewPlace, mCurrentPlace );
111 - if ( pNewPlace.equals( mCurrentPlace ) )
97 + Place zCurrentPlace = mActivityHelper.getCurrentPlace();
98 + pNewPlace = UtilsCommon.deNull( pNewPlace, zCurrentPlace );
99 + if ( pNewPlace.equals( zCurrentPlace ) )
112 100 {
113 101 return GoToPlace.AlreadyThere;
114 102 }
115 - if ( pNewPlace.equals( mPendingCodePlace ) || pNewPlace.equals( mPendingAsyncPlace ) )
103 + if ( pNewPlace.equals( mPendingCodePlace ) || mActivityHelper.isPendingAsync( pNewPlace ) )
116 104 {
117 105 return null;
118 106 }
119 - if ( null == get( PlaceIdExtractor.getPlaceId( pNewPlace ) ) ) // Check for Factory
107 + if ( null == mActivityHelper.get( pNewPlace ) ) // Check for Factory
120 108 {
121 109 return GoToPlace.NoActivity;
122 110 }
  @@ -124,7 +112,7 @@
124 112 {
125 113 return GoToPlace.CurrentActivityRejectedLeaving; // From Code, maybe the code shouldn't have allowed it!
126 114 }
127 - mPendingAsyncPlace = null;
115 + mActivityHelper.clearPendingAsync();
128 116 mPendingCodePlace = pNewPlace;
129 117 mHistorian.newItem( mMapper.getToken( pNewPlace ), true );
130 118 return null;
  @@ -132,6 +120,8 @@
132 120
133 121 private void handleHistoryToken( String pToken )
134 122 {
123 + Place zWasGoingToCodePlace = mPendingCodePlace;
124 + mPendingCodePlace = null;
135 125 mCommonActivityParam.getMessageUserSink().clearMessage();
136 126
137 127 Place zNewPlace = null;
  @@ -154,186 +144,34 @@
154 144 LOGGER.warn.log( e, "Unable to parse history token: ", pToken );
155 145 }
156 146 }
157 - zNewPlace = UtilsCommon.deNull( zNewPlace, mCurrentPlace );
158 - if ( zNewPlace.equals( mCurrentPlace ) )
147 + Place zCurrentPlace = mActivityHelper.getCurrentPlace();
148 + zNewPlace = UtilsCommon.deNull( zNewPlace, zCurrentPlace );
149 + if ( zNewPlace.equals( zCurrentPlace ) )
159 150 {
160 - mPendingCodePlace = null;
161 - mPendingAsyncPlace = null;
151 + mActivityHelper.clearPendingAsync();
162 152 return;
163 153 }
164 - if ( (mPendingCodePlace != null) && !zNewPlace.equals( mPendingCodePlace ) && userRejectedLeavingCurrentPlace( zNewPlace ) )
154 + if ( (zWasGoingToCodePlace != null) && !zNewPlace.equals( zWasGoingToCodePlace ) && userWantsToStopUrlChange( zNewPlace ) )
165 155 {
166 - mPendingCodePlace = null;
167 - mPendingAsyncPlace = null;
168 - mHistorian.newItem( mMapper.getToken( mCurrentPlace ), false ); // reset the URL back to the Current Place
156 + mActivityHelper.clearPendingAsync();
157 + resetURLbackTo( zCurrentPlace );
169 158 return;
170 159 }
171 - mPendingCodePlace = null;
172 - if ( zNewPlace.equals( mPendingAsyncPlace ) )
160 + if ( !mActivityHelper.activate( zNewPlace ) )
173 161 {
174 - return;
175 - }
176 - ActivityFactory zFactory = get( zNewPlace );
177 - if ( zFactory == null )
178 - {
179 - mPendingAsyncPlace = null;
180 162 mCommonActivityParam.getMessageUserSink().setErrorMessage( "No Activity Factory for '" + UtilsCommon.justSimpleName( zNewPlace ) + "' from: " + pToken );
181 - mHistorian.newItem( mMapper.getToken( mCurrentPlace ), false ); // reset the URL back to the Current Place
182 - return;
183 - }
184 - if ( zFactory instanceof ActivityFactory.Asynchronous ) // Un-Happy Case!
185 - {
186 - loadSyncFactory( (ActivityFactory.Asynchronous) zFactory, mPendingAsyncPlace = zNewPlace );
187 - return;
188 - }
189 - mPendingAsyncPlace = null;
190 - activate( zNewPlace, (ActivityFactory.Synchronous) zFactory );
191 - }
192 -
193 - /**
194 - * Activate the New Place and it's associated Activity (deactivating the current activity.
195 - * <p/>
196 - * Note:
197 - * The current activity's widget will be hidden immediately, which can cause
198 - * flicker if the next activity provides its widget asynchronously. That can
199 - * be minimized by decent caching. Perenially slow activities might mitigate
200 - * this by providing a widget immediately, with some kind of "loading"
201 - * treatment.
202 - */
203 - protected void activate( Place pNewPlace, ActivityFactory.Synchronous pSyncFactory )
204 - {
205 - Set<Throwable> zIssues = new LinkedHashSet<Throwable>();
206 -
207 - mCurrentPlace = pNewPlace;
208 -
209 - Activity zNewActivity = UtilsCommon.deNull( createActivity( zIssues, pSyncFactory, pNewPlace ), NULL_ACTIVITY );
210 -
211 - if ( (mPendingActivity != null) && (mPendingActivity != zNewActivity) ) // The place changed again before the new Activity showed its widget
212 - {
213 - tryCancel( zIssues, mPendingActivity );
214 - }
215 - mPendingActivity = zNewActivity;
216 -
217 - // Wrap the actual panel with a per-call instance that protects the actual panel from canceled or stopped activities, and
218 - // which handles the Pending Activity becoming the Current Activity.
219 - AcceptsOneWidget zPanel = new ProtectedDisplay( zIssues, mPendingActivity );
220 -
221 - if ( !canStart( zIssues, mPendingActivity, zPanel ) )
222 - {
223 - NULL_ACTIVITY.start( new ProtectedDisplay( zIssues, mPendingActivity = NULL_ACTIVITY ) ); // Can NOT fail!
224 - }
225 - }
226 -
227 - @SuppressWarnings({"unchecked"})
228 - protected Activity createActivity( Collection<Throwable> pIssues, ActivityFactory.Synchronous pFactory, Place pPlace )
229 - {
230 - try
231 - {
232 - return pFactory.createActivity( mCommonActivityParam, pFactory.getView(), pPlace );
233 - }
234 - catch ( Exception e )
235 - {
236 - pIssues.add( e );
237 - }
238 - return null;
239 - }
240 -
241 - private boolean canStart( Set<Throwable> pIssues, Activity pActivity, AcceptsOneWidget pPanel )
242 - {
243 - try
244 - {
245 - pActivity.start( pPanel );
246 - return true;
247 - }
248 - catch ( Exception e )
249 - {
250 - pIssues.add( e );
251 - }
252 - return false;
253 - }
254 -
255 - private void tryCancel( Collection<Throwable> pIssues, Activity pActivity )
256 - {
257 - try
258 - {
259 - pActivity.onCancel();
260 - }
261 - catch ( Exception e )
262 - {
263 - pIssues.add( e );
264 - }
265 - }
266 -
267 - private void tryStop( Collection<Throwable> pIssues, Activity pActivity )
268 - {
269 - try
270 - {
271 - pActivity.onStop();
272 - }
273 - catch ( Exception e )
274 - {
275 - pIssues.add( e );
276 - }
277 - }
278 -
279 - private void possiblyUpdateActivityAndShowWidget( Set<Throwable> pIssues, Activity pActivity, IsWidget pWidget )
280 - {
281 - if ( mPendingActivity == null ) // Normal? Happy case when No Pending Activity and request is from Current Activity
282 - {
283 - if ( pActivity == mCurrentActivity )
284 - {
285 - showWidget( pWidget );
286 - }
287 - return;
288 - }
289 - if ( pActivity != mPendingActivity ) // Is a Pending Activity, but the request is NOT from it!
290 - {
291 - return;
292 - }
293 - tryStop( pIssues, mCurrentActivity );
294 - mCurrentActivity = mPendingActivity;
295 - mPendingActivity = null;
296 - showWidget( pWidget );
297 - if ( !pIssues.isEmpty() )
298 - {
299 - throw new UmbrellaException( pIssues );
300 - }
301 - }
302 -
303 - private void showWidget( IsWidget pWidget )
304 - {
305 - if ( mPanel != null )
306 - {
307 - mPanel.setWidget( pWidget );
163 + resetURLbackTo( zCurrentPlace );
308 164 }
309 165 }
310 166
311 - @SuppressWarnings({"unchecked"})
312 - private void loadSyncFactory( final ActivityFactory.Asynchronous pAsyncFactory, final Place pPlace )
167 + protected boolean userWantsToStopUrlChange( Place pNewPlace )
313 168 {
314 - pAsyncFactory.load( mCommonActivityParam, new ActivityFactory.Asynchronous.Callback<CommonActivityParam, IsWidget, Place>()
315 - {
316 - @Override
317 - public void loaded( ActivityFactory.Synchronous<CommonActivityParam, IsWidget, Place> pSynchronousFactory )
318 - {
319 - switchAsyncToSync( pPlace, pAsyncFactory, pSynchronousFactory );
320 - }
321 - } );
169 + return userRejectedLeavingCurrentPlace( pNewPlace );
322 170 }
323 171
324 - private void switchAsyncToSync( Place pPlace, ActivityFactory.Asynchronous pAsyncFactory, ActivityFactory.Synchronous pSyncFactory )
172 + protected void resetURLbackTo( Place pCurrentPlace )
325 173 {
326 - boolean zStillGoing = pPlace.equals( mPendingAsyncPlace );
327 - mPendingAsyncPlace = null;
328 - if ( replace( pAsyncFactory, pSyncFactory ) && zStillGoing )
329 - {
330 - activate( pPlace, pSyncFactory );
331 - }
332 - }
333 -
334 - protected ActivityFactory get( Place pPlace )
335 - {
336 - return get( PlaceIdExtractor.getPlaceId( pPlace ) );
174 + mHistorian.newItem( mMapper.getToken( pCurrentPlace ), false ); // reset the URL back to the Current Place
337 175 }
338 176
339 177 protected boolean userRejectedLeavingCurrentPlace( Place newPlace )
  @@ -344,13 +182,19 @@
344 182
345 183 protected String getLeavingCurrentPlaceWarningText()
346 184 {
347 - return mCurrentActivity.mayStop();
185 + return mActivityHelper.getCurrentActivityMayStop();
186 + }
187 +
188 + @SuppressWarnings({"unchecked"})
189 + protected CommonActivityParam createDefaultCommonActivityParam()
190 + {
191 + return (CommonActivityParam) new DefaultCommonActivityParam();
348 192 }
349 193
350 194 /**
351 - * Default implementation of CommonActivityParam, based on {@link Window}.
195 + * Default implementation of CommonActivityParameter, based on {@link Window}.
352 196 */
353 - private static class DefaultCommonActivityParam implements MessageUserSinkAccessor
197 + private class DefaultCommonActivityParam implements CommonActivityParameter
354 198 {
355 199 @Override
356 200 public MessageUserSink getMessageUserSink()
  @@ -358,32 +202,16 @@
358 202 return DialogMessageUserSink.INSTANCE;
359 203 }
360 204
361 - @SuppressWarnings({"unchecked"})
362 - public static <CommonActivityParam extends MessageUserSinkAccessor> CommonActivityParam createInstance()
363 - {
364 - return (CommonActivityParam) new DefaultCommonActivityParam();
365 - }
366 - }
367 -
368 - /**
369 - * Wraps our real display to prevent an Activity from taking it over if it is
370 - * not the currentActivity.
371 - */
372 - private class ProtectedDisplay implements AcceptsOneWidget
373 - {
374 - private final Set<Throwable> mIssues;
375 - private final Activity mExpectedActivity;
376 -
377 - ProtectedDisplay( Set<Throwable> pIssues, Activity pExpectedActivity )
205 + @Override
206 + public Place getWhere()
378 207 {
379 - mIssues = pIssues;
380 - mExpectedActivity = pExpectedActivity;
208 + return PlaceActivityManager.this.getWhere();
381 209 }
382 210
383 211 @Override
384 - public void setWidget( IsWidget pWidget )
212 + public GoToPlace goTo( Place pNewPlace )
385 213 {
386 - possiblyUpdateActivityAndShowWidget( mIssues, mExpectedActivity, pWidget );
214 + return PlaceActivityManager.this.goTo( pNewPlace );
387 215 }
388 216 }
389 217 }