001package votorola.s.gwt.scene.vote; // Copyright 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.gwt.dom.client.*;
005import com.google.web.bindery.event.shared.HandlerRegistration;
006import com.google.gwt.view.client.*;
007import org.vectomatic.dom.svg.*;
008import votorola.a.count.gwt.*;
009import votorola.g.hold.*;
010import votorola.g.web.gwt.event.*;
011import votorola.g.web.gwt.svg.*;
012
013import static votorola.a.count.CountNode.DART_SECTOR_MAX;
014
015
016/** A circular view of peer nodes in votespace, ordered clockwise by dart sector.
017  */
018abstract class Circle<P extends SVGNest<?>> extends SVGParaNest<P>
019{
020
021
022    /** Constructs a Circle.
023      *
024      *     @see #inCircle()
025      *     @see #level()
026      */
027    Circle( Circle<?> _inCircle, int _level, VotespaceV _votespaceV )
028    {
029        inCircle = _inCircle;
030        level = _level;
031        votespaceV = _votespaceV;
032
033        svgView = votespaceV.document().createSVGGElement();
034        svgView.addClassNameBaseVal( "circle" );
035
036        registerPainter = new RegisterPainter();
037    }
038
039
040
041   // ------------------------------------------------------------------------------------
042
043
044    /** The current candidate view for all nodes of this circle, or null if there is none.
045      */
046    abstract NodeV candidateV();
047
048
049
050    /** The number of count node views, or the maximum number of peer nodes that can be
051      * shown in this circle.
052      */
053    static int capacity() { return DART_SECTOR_MAX; }
054
055
056
057    /** Returns the node view at the specified dart sector offset.
058      *
059      *     @param offset the dart sector offset, which is zero based.
060      *     @throws ArrayIndexOutOfBoundsException if the offset is not less than the
061      *       capacity of this circle.
062      *
063      *     @see #setCountNodeV(NodeV,int)
064      */
065    final NodeV nodeV( final int offset ) { return nodeV[offset]; }
066
067
068        private final NodeV[] nodeV = new NodeV[DART_SECTOR_MAX];
069
070
071        /** Sets a node view.
072          *
073          *     @see #nodeV(int)
074          */
075        final void setCountNodeV( final NodeV v, final int offset ) { nodeV[offset] = v; }
076
077
078
079    /** Answers whether the SVG component is nominally visible.  Returns false if the
080      * display style is "none", true otherwise.
081      *
082      *     @see #svgView()
083      *     @see #setVisible(boolean)
084      */
085    final boolean isVisible() { return !"none".equals( svgView().getStyle().getDisplay() ); }
086
087
088
089        /** Sets the visibility of the SVG component.
090          *
091          *     @see #isVisible()
092          */
093        final void setVisible( final boolean toBe )
094        {
095            final Style style = svgView.getStyle();
096            if( toBe ) style.clearDisplay();
097            else style.setDisplay( Style.Display.NONE );
098        }
099
100
101
102    /** The circle at the next level inward, or null if there is none.
103      */
104    final Circle<?> inCircle() { return inCircle; }
105
106
107        private final Circle<?> inCircle;
108
109
110
111    /** The periperal level of this circle, where zero is the center circle.
112      */
113    final int level() { return level; }
114
115
116        private final int level;
117
118
119
120    /** The volume of votes below which a node is to be shown as a "mosquito".
121      *
122      *     @see NodeV#isMosquito()
123      *     @see #setMosquitoBar(long)
124      */
125    final long mosquitoBar() { return mosquitoBar; }
126
127
128        private long mosquitoBar;
129
130
131        /** Sets the mosquito bar.
132          *
133          *     @see #mosquitoBar()
134          */
135        final void setMosquitoBar( long _mosquitoBar ) { mosquitoBar = _mosquitoBar; }
136
137
138
139    /** The radius of clear space surrounding each count node of this circle.  The
140      * standoff is generally free of voteflow radials and other graphics.
141      */
142    abstract float nodularStandOff();
143
144
145
146    /** Returns the circle at the next level outward, creating a new circle if necessary.
147      */
148    final VoterCircle outCircle()
149    {
150        if( outCircle == null ) outCircle = new VoterCircle( Circle.this, level + 1, votespaceV );
151
152        return outCircle;
153    }
154
155
156        private VoterCircle outCircle;
157
158
159
160    /** The register painter for this circle.
161      */
162    RegisterPainter registerPainter() { return registerPainter; }
163
164
165        private final RegisterPainter registerPainter;
166
167
168
169    /** The scene view of which this view is a component.
170      */
171    final VotespaceV votespaceV() { return votespaceV; }
172
173
174        private final VotespaceV votespaceV;
175
176
177
178   // - S  V  G - W r a p p e r ----------------------------------------------------------
179
180
181    public final OMSVGGElement svgView() { return svgView; }
182
183
184        private final OMSVGGElement svgView;
185
186
187
188   // ====================================================================================
189
190
191    /** A painter of the superaccount register views in each node of the circle.
192      */
193    final class RegisterPainter implements Scheduler.ScheduledCommand, SelectionChangeEvent.Handler
194    {
195
196        RegisterPainter()
197        {
198            votespaceV.spool().add( new Hold()
199            {
200                final HandlerRegistration hR
201                  = votespaceV.model().addSelectionChangeHandler( RegisterPainter.this );
202                public void release() { hR.removeHandler(); }
203            });
204        }
205
206
207        private final CoalescingSchedulerS cScheduler = new CoalescingSchedulerS(
208          CoalescingSchedulerS.FINALLY, RegisterPainter.this );
209
210
211        public void execute()
212        {
213            if( !isVisible() ) return;
214
215            final SacJS sac = votespaceV.model().getSac();
216            if( sac == null ) return; // register view invisible, no need to repaint
217
218            final CountingMethodJS.SwitchMnemonic mCM = sac.countingMethodMnemonic();
219            if( mCM == CountingMethodJS.SwitchMnemonic.nul )  return; // "
220
221            final String accountName = sac.accountName();
222            for( int n = 0, nN = capacity(); n < nN; ++n )
223            {
224                final NodeV v = nodeV( n );
225                v.repaintRegister( mCM, accountName );
226            }
227        }
228
229
230        public void onSelectionChange( SelectionChangeEvent _e ) { repaintLater(); }
231
232
233        /** Schedules a repaint.
234          */
235        void repaintLater() { cScheduler.schedule(); }
236
237
238    }
239
240
241
242}