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.dom.client.Style;
004import org.vectomatic.dom.svg.*;
005import votorola.a.count.gwt.*;
006import votorola.a.voter.*;
007import votorola.g.lang.*;
008import votorola.g.web.gwt.*;
009import votorola.g.web.gwt.svg.*;
010
011
012/** A view of a count node.
013  */
014abstract class NodeV extends SVGParaNest<Circle<?>>
015{
016
017
018    /** Constructs a NodeV.
019      *
020      *     @see #dartSector()
021      */
022    NodeV( final VotespaceV votespaceV, int _dartSector )
023    {
024        dartSector = _dartSector;
025
026        final OMSVGDocument document = votespaceV.document();
027        svgView = document.createSVGGElement();
028        setVisible( false ); // hide by default
029
030        localView = document.createSVGGElement();
031        svgView.appendChild( localView );
032        localView.addClassNameBaseVal( "countNode" );
033        localView.addClickHandler( votespaceV.pathExtender() ); // no need to unregister, registry does not outlive the handler
034
035        mnemonicTextNode = document.createTextNode( "" );
036     // mnemonicTextNode.setData( Integer.toString( dartSector )); // TEST code
037    }
038
039
040
041   // - C o u n t - N o d e - V ----------------------------------------------------------
042
043
044    /** The dart sector of this view.
045      *
046      *     @see votorola.a.count.CountNode#dartSector()
047      */
048    final int dartSector() { return dartSector; }
049
050
051        private final int dartSector;
052
053
054
055    /** Answers whether this node is to be shown as a "mosquito", because its vote volume
056      * falls below the circle's mosquito bar.
057      *
058      *     @see Circle#mosquitoBar()
059      */
060    final boolean isMosquito() { return isMosquito; }
061
062
063        private boolean isMosquito;
064
065
066        /** Sets whether this node is to be shown as a "mosquito".
067          */
068        final void setMosquito( final boolean is )
069        {
070            if( is == isMosquito ) return;
071
072            if( is ) localView.addClassNameBaseVal( "mosquito" );
073            else localView.removeClassNameBaseVal( "mosquito" );
074            isMosquito = is;
075        }
076
077
078
079    /** Answers whether the SVG component is nominally visible, returning 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        private final void setVisible( 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 view of the node in itself, separate from any radial line or surrounding
103      * circles of voters.  The local view is oriented upright (inverse rotation from
104      * parent SVG view) for sake of readability.  It is also made clickable.
105      *
106      *     @see #svgView()
107      */
108    final OMSVGGElement localView() { return localView; }
109
110
111        private final OMSVGGElement localView;
112
113
114
115    /** The count node on which this view is modelled, or null if none is modelled.
116      *
117      *     @see #setModel(CountNodeJS)
118      */
119    final CountNodeJS model() { return model; }
120
121
122        private CountNodeJS model;
123
124
125        /** Sets the count node on which this view is modelled, and adjusts rotation,
126          * styles and other view properties to match the current ancestry of the node.
127          * This assumes no subsequent changes among ancestor properties from model
128          * changes or rotation transforms.
129          *
130          *     @return true if the model was set, false if it already was set.
131          *     @throws IllegalArgumentException if the model does not have the same dart
132          *       sector as this view.
133          */
134        boolean setModel( final CountNodeJS newModel )
135        {
136            if( ObjectX.nullEquals( newModel, model )) return false;
137
138            model = newModel;
139            if( model == null )
140            {
141                setVisible( false );
142             // mnemonicTextNode.setData( Integer.toString( dartSector )); // TEST code
143             // mnemonicTextNode.setData( "X" );
144                return true;
145            }
146
147            if( model.dartSector() != dartSector ) throw new IllegalArgumentException( "dart sector mismatch" );
148
149            final OMSVGMatrix currentTransforms = svgView.getCTM();
150            final OMSVGMatrix i = currentTransforms.inverse();
151            localView.setAttribute( "transform", "matrix(" // inverse rotation only
152              + i.getA() + " " + i.getB() + " " + i.getC() + " " + i.getD() + " 0 0)" );
153
154            mnemonicTextNode.setData( IDPair.buildUserMnemonic(
155              model.name(), GWTX.stringBuilderClear() ).toString() );
156            setVisible( true );
157            return true;
158        }
159
160
161
162    /** A text node that shows the abbreviated username.
163      */
164    final OMText mnemonicTextNode() { return mnemonicTextNode; }
165
166
167        private final OMText mnemonicTextNode;
168
169
170
171    /** Repaints the view of the superaccount register.
172      *
173      *     @see SacJS#accountName()
174      */
175    abstract void repaintRegister( CountingMethodJS.SwitchMnemonic mCM, String accountName );
176
177
178
179    /** The radix 21 votepath from this view.  The value is set by subclasses as the
180      * "votepath" property of the underlying local view, whence it is accessible to event
181      * handlers.
182      *
183      *     @see #setModel(CountNodeJS)
184      *     @see #localView()
185      *     @see DartScoping#votepath()
186      */
187    final String votepath() { return localView().getElement().getPropertyString( "votepath" ); }
188       // see possible fix for this hack in votorola.g.web.gwt.SVGNest.parent()
189
190
191
192   // - S  V  G - P a r a - N e s t ------------------------------------------------------
193
194
195    public final @Override void setParent( final Circle<?> circle )
196    {
197        super.setParent( circle );
198        circle.setCountNodeV( NodeV.this, dartSector - 1 );
199    }
200
201
202
203   // - S  V  G - W r a p p e r ----------------------------------------------------------
204
205
206    /** @see #localView()
207      */
208    public final OMSVGGElement svgView() { return svgView; }
209
210
211        private final OMSVGGElement svgView;
212
213
214}