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}