001package votorola.s.gwt.stage.vote; // Copyright 2012, 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.Scheduler; 004import votorola.a.diff.*; 005import votorola.g.lang.*; 006import votorola.g.web.gwt.*; 007import votorola.g.web.gwt.event.*; 008import votorola.s.gwt.stage.*; 009import votorola.s.gwt.stage.link.*; 010 011import static votorola.s.gwt.stage.link.NominalDifferenceTargeter.NOMINAL_DIFF; 012 013 014/** The stager of differences for the {@linkplain DifferenceLight difference light}. 015 * Whenever the staged actor and poll match a lighted difference, the stager sets the 016 * {@linkplain Stage#getDifference() difference on the stage}. If the difference cannot 017 * be staged and {@linkplain NominalDifferenceLight nominal targeting} is enabled, then 018 * any incompatible difference on stage is cleared to allow the difference link to be set 019 * to the nominal target. 020 */ 021final class DifferenceStager implements PropertyChangeHandler 022{ 023 024 025 /** Constructs a DifferenceStager. 026 */ 027 DifferenceStager( final DifferenceLight<?> light, final Stage stage ) 028 { 029 keyLight = light.hasDiffLooks()? light: null; 030 GWTX.i().bus().addHandlerToSource( PropertyChange.TYPE, /*source*/stage, 031 DifferenceStager.this ); // no need to unregister, registry does not outlive this listener 032 restage( stage, stage.getActorName(), /*toClobber*/false ); 033 } 034 035 036 037 // - P r o p e r t y - C h a n g e - H a n d l e r ------------------------------------ 038 039 040 public void onPropertyChange( final PropertyChange e ) 041 { 042 final String name = e.propertyName(); 043 // if( name.equals( "difference" )) clean( (Stage)e.getSource() ); else 044 if( name.equals( "actorName" )) 045 { 046 final Stage stage = (Stage)e.getSource(); 047 final String actorName = stage.getActorName(); 048 restage( stage, actorName, 049 // /*toClobber*/!ObjectX.nullEquals(actorName,stage.getDefaultActorName()) ); 050 // // allow clobber for non-default actor under assumption he/she was 051 // // deliberately staged by user in order to light difference 052 /////// but then cannot deselect other author to clear the inverted DiffLook1 below, 053 /////// so allow all author de-selections to clobber, which also makes sense: 054 /*toClobber*/true ); 055 } 056 else if( name.equals( "pollName" )) 057 { 058 final Stage stage = (Stage)e.getSource(); 059 restage( stage, stage.getActorName(), /*toClobber*/false ); 060 } 061 } 062 063 064 065//// P r i v a t e /////////////////////////////////////////////////////////////////////// 066 067 068 private final boolean isTargetingNominal = NominalDifferenceTargeter.isEnabled(); 069 070 071 072 private final DifferenceLight<?> keyLight; // or null if !hasDiffLooks 073 074 075 076 private final @Warning("init call") void restage( final Stage stage, final String actorName, 077 final boolean toClobber ) 078 { 079 final DiffLook dOld = stage.getDifference(); 080 final String pollName = stage.getPollName(); 081 if( dOld != null ) 082 { 083 if( LightableDifference.TYPIFIER.isInstance( dOld )) 084 { 085 final LightableDifference dOldL = (LightableDifference)dOld; 086 if( dOldL.personName().equals(actorName) 087 && dOldL.pollName().equals(pollName) ) return; // diff already staged 088 } 089 else if( !toClobber ) return; // diff set by another controller, do not clobber 090 } 091 092 final DiffLook dNew; 093 dNew: if( keyLight != null ) dNew = (DiffLook)keyLight.differenceFor( actorName, pollName ); 094 else 095 { 096 if( sceneName != null && sceneName.equals( actorName )) // other author of scene diff staged 097 { 098 final DiffLook d = stage.getDefaultDifference(); 099 if( d != null ) 100 { 101 // Stage the same diff as scene, but with selectand inverted. So diff 102 // link will simply switch selectand even if diff is old. Nominal 103 // targeting (below) would instead link to latest diff. 104 dNew = new DiffLook1( d.key(), 105 /*selectand, other*/"a".equals(d.selectand())?"b":"a", /*toPersist*/true ); 106 break dNew; 107 } 108 } 109 110 if( isTargetingNominal ) dNew = NOMINAL_DIFF; // cannot stage, so clear instead 111 else return; // nothing helpful to do, so do nothing 112 } 113 114 stage.setDifference( dNew ); 115 } 116 117 118 119 private final String sceneName = DifferenceLight.sceneName(); 120 121 122}