001/* 002 * ============================================================================ 003 * Copyright © 2002-2021 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.svg; 019 020import static java.lang.String.join; 021import static java.util.stream.Collectors.joining; 022import static org.apiguardian.api.API.Status.STABLE; 023import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_STRING; 024import static org.tquadrat.foundation.lang.Objects.nonNull; 025import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 026import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_ClipPathUnits; 027import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_LengthAdjust; 028import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_MarkerHeight; 029import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_MarkerUnits; 030import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_MarkerWidth; 031import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_Orientation; 032import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_PathDefinition; 033import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_Position; 034import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_ReferenceX; 035import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_ReferenceY; 036import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_Rotate; 037import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_TextLength; 038import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_dx; 039import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_dy; 040import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_x; 041import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_x1; 042import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_x2; 043import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_y; 044import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_y1; 045import static org.tquadrat.foundation.svg.SVGUtils.SVGATTRIBUTE_y2; 046import static org.tquadrat.foundation.svg.SVGUtils.number; 047import static org.tquadrat.foundation.util.StringUtils.isNotEmptyOrBlank; 048import static org.tquadrat.foundation.util.StringUtils.stream; 049 050import java.util.ArrayList; 051import java.util.Arrays; 052import java.util.List; 053import java.util.Optional; 054 055import org.apiguardian.api.API; 056import org.tquadrat.foundation.annotation.ClassVersion; 057import org.tquadrat.foundation.annotation.MountPoint; 058import org.tquadrat.foundation.svg.internal.SVGElementImpl; 059import org.tquadrat.foundation.svg.type.SVGMarkerOrientation; 060import org.tquadrat.foundation.svg.type.SVGNumber; 061import org.tquadrat.foundation.svg.type.SVGNumber.SVGDegree; 062import org.tquadrat.foundation.svg.type.SVGPathElement; 063 064/** 065 * <p>{@summary This is the base class for a custom type that wants to extend 066 * an SVG element with additional features.}</p> 067 * <p>Basically, an implementation may look like this (in this example, for 068 * an SVG {@code <symbol>} extension:</p> 069 * <pre><code> … 070 * public class MySymbol extends SVGElementBase 071 * { 072 * … 073 * public MySymbol() 074 * { 075 * super( SVGUtils.SVGELEMENT_Symbol, ALLOW_CHILDREN ); 076 * … 077 * } 078 * … 079 * }</code></pre> 080 * 081 * @note Such a custom element implements all the other interfaces; it is 082 * all the other element type <i>at the same time</i>! But that does not 083 * mean that it will inherit their features automatically! Especially it 084 * will not validate children or attributes! 085 * 086 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 087 * @version $Id: SVGElementAdapter.java 980 2022-01-06 15:29:19Z tquadrat $ 088 * @since 0.0.5 089 * 090 * @UMLGraph.link 091 */ 092@SuppressWarnings( {"AbstractClassExtendsConcreteClass", "OverlyCoupledClass"} ) 093@ClassVersion( sourceVersion = "$Id: SVGElementAdapter.java 980 2022-01-06 15:29:19Z tquadrat $" ) 094@API( status = STABLE, since = "0.0.5" ) 095public abstract non-sealed class SVGElementAdapter extends SVGElementImpl 096 implements AllowsDocumentElementEventAttributes, AllowsDocumentEventAttributes, SVGClipPath, SVGGroup, SVGLine, SVGPath, SVGPositionedMarker, SVGRectangle, SVGStyle, SVGSymbol, SVGText, SVGTSpan, SVGUse 097{ 098 /*------------*\ 099 ====** Attributes **======================================================= 100 \*------------*/ 101 /** 102 * The lines of the CSS style definitions. 103 */ 104 private final List<String> m_StyleDefinitions = new ArrayList<>(); 105 106 /*--------------*\ 107 ====** Constructors **===================================================== 108 \*--------------*/ 109 /** 110 * Creates a new {@code SVGElementAdapter} instance. 111 * 112 * @param elementName The name of the element. 113 * @param flags The flags that determine the behaviour of the new 114 * element. 115 */ 116 protected SVGElementAdapter( final String elementName, final Flags... flags ) 117 { 118 super( elementName, flags ); 119 } // SVGElementAdapter() 120 121 /*---------*\ 122 ====** Methods **========================================================== 123 \*---------*/ 124 /** 125 * {@inheritDoc} 126 */ 127 @MountPoint 128 @Override 129 public void addStyle( final CharSequence... styles ) 130 { 131 for( final var style : requireNonNullArgument( styles, "styles" ) ) 132 { 133 if( isNotEmptyOrBlank( style ) ) 134 { 135 stream( style, '\n' ).forEach( m_StyleDefinitions::add ); 136 } 137 else 138 { 139 m_StyleDefinitions.add( EMPTY_STRING ); 140 } 141 } 142 } // addStyle() 143 144 /** 145 * {@inheritDoc} 146 */ 147 @SuppressWarnings( "UseOfConcreteClass" ) 148 @MountPoint 149 @Override 150 public void defineLine( final SVGNumber x1, final SVGNumber y1, final SVGNumber x2, final SVGNumber y2 ) 151 { 152 setStartPoint( x1, y1 ); 153 setEndPoint( x2, y2 ); 154 } // defineLine() 155 156 /** 157 * {@inheritDoc} 158 */ 159 @MountPoint 160 @Override 161 public void setPathLength( final double length ) 162 { 163 setPathLength( number( length ) ); 164 } // setPathLength() 165 166 /** 167 * {@inheritDoc} 168 */ 169 @MountPoint 170 @Override 171 public void setPathLength( final long length ) 172 { 173 setPathLength( number( length ) ); 174 } // setPathLength() 175 176 /** 177 * {@inheritDoc} 178 */ 179 @MountPoint 180 @Override 181 public String getStyleSheet() 182 { 183 final var retValue = join( "\n", m_StyleDefinitions ); 184 185 //---* Done *---------------------------------------------------------- 186 return retValue; 187 } // getStyleSheet() 188 189 /** 190 * {@inheritDoc} 191 */ 192 @MountPoint 193 @Override 194 public void merge( final SVGStyle other ) 195 { 196 addStyle( other.getStyleSheet() ); 197 } // merge() 198 199 /** 200 * {@inheritDoc} 201 */ 202 @MountPoint 203 @Override 204 public void setClipPathUnits( final boolean flag ) 205 { 206 setAttribute( SVGATTRIBUTE_ClipPathUnits, flag ? "objectBoundingBox" : "userSpaceOnUse" ); 207 } // setClipPathUnits() 208 209 /** 210 * {@inheritDoc} 211 */ 212 @SuppressWarnings( "UseOfConcreteClass" ) 213 @MountPoint 214 @Override 215 public void setDx( final SVGNumber... values ) 216 { 217 final var value = nonNull( values ) && (values.length != 0) 218 ? Arrays.stream( values ) 219 .map( SVGNumber::toString ) 220 .collect( joining( "," ) ) 221 : null; 222 setAttribute( SVGATTRIBUTE_dx, value ); 223 } // setDx() 224 225 /** 226 * {@inheritDoc} 227 */ 228 @SuppressWarnings( "UseOfConcreteClass" ) 229 @MountPoint 230 @Override 231 public void setDy( final SVGNumber... values ) 232 { 233 final var value = nonNull( values ) && (values.length != 0) 234 ? Arrays.stream( values ) 235 .map( SVGNumber::toString ) 236 .collect( joining( "," ) ) 237 : null; 238 setAttribute( SVGATTRIBUTE_dy, value ); 239 } // setDy() 240 241 /** 242 * {@inheritDoc} 243 */ 244 @MountPoint 245 @Override 246 public void setLengthAdjust( final boolean flag ) 247 { 248 final var value = flag ? "spacingAndGlyphs" : "spacing"; 249 setAttribute( SVGATTRIBUTE_LengthAdjust, value ); 250 } // setLengthAdjust() 251 252 /** 253 * {@inheritDoc} 254 */ 255 @SuppressWarnings( "UseOfConcreteClass" ) 256 @MountPoint 257 @Override 258 public void setMarkerHeight( final SVGNumber value ) 259 { 260 setAttribute( SVGATTRIBUTE_MarkerHeight, value ); 261 } // setMarkerHeight() 262 263 /** 264 * {@inheritDoc} 265 */ 266 @MountPoint 267 @Override 268 public void setMarkerUnits( final boolean flag ) 269 { 270 setAttribute( SVGATTRIBUTE_MarkerUnits, flag ? "userSpaceOnUse" : "strokeWidth" ); 271 } // setMarkerUnits() 272 273 /** 274 * {@inheritDoc} 275 */ 276 @SuppressWarnings( "UseOfConcreteClass" ) 277 @MountPoint 278 @Override 279 public void setMarkerWidth( final SVGNumber value ) 280 { 281 setAttribute( SVGATTRIBUTE_MarkerWidth, value ); 282 } // setMarkerWidth() 283 284 /** 285 * {@inheritDoc} 286 */ 287 @MountPoint 288 @Override 289 public void setOrientation( final SVGMarkerOrientation value ) 290 { 291 setAttribute( SVGATTRIBUTE_Orientation, nonNull( value ) ? value.toString() : null ); 292 } // setOrientation() 293 294 /** 295 * {@inheritDoc} 296 */ 297 @SuppressWarnings( "UseOfConcreteClass" ) 298 @MountPoint 299 @Override 300 public void setOrientation( final SVGNumber.SVGDegree value ) 301 { 302 setAttribute( SVGATTRIBUTE_Orientation, nonNull( value ) ? value.toString() : null ); 303 } // setOrientation() 304 305 /** 306 * {@inheritDoc} 307 */ 308 @MountPoint 309 @Override 310 public void setPathDefinition( final SVGPathElement... pathElements ) 311 { 312 final var value = nonNull( pathElements ) ? SVGPathElement.toString( pathElements ) : null; 313 setAttribute( SVGATTRIBUTE_PathDefinition, value, Optional.of( " " ) ); 314 } // setPathDefinition() 315 316 /** 317 * {@inheritDoc} 318 */ 319 @SuppressWarnings( "UseOfConcreteClass" ) 320 @MountPoint 321 @Override 322 public void setPosition( final SVGNumber value ) 323 { 324 setAttribute( SVGATTRIBUTE_Position, value ); 325 } // setPosition() 326 327 /** 328 * {@inheritDoc} 329 */ 330 @SuppressWarnings( "UseOfConcreteClass" ) 331 @MountPoint 332 @Override 333 public void setReferenceX( final SVGNumber value ) 334 { 335 setAttribute( SVGATTRIBUTE_ReferenceX, value ); 336 } // setReferenceX() 337 338 /** 339 * {@inheritDoc} 340 */ 341 @SuppressWarnings( "UseOfConcreteClass" ) 342 @MountPoint 343 @Override 344 public void setReferenceY( final SVGNumber value ) 345 { 346 setAttribute( SVGATTRIBUTE_ReferenceY, value ); 347 } // setReferenceY() 348 349 /** 350 * {@inheritDoc} 351 */ 352 @SuppressWarnings( "UseOfConcreteClass" ) 353 @MountPoint 354 @Override 355 public void setRotate( final SVGNumber.SVGDegree... values ) 356 { 357 final var value = nonNull( values ) && (values.length != 0) 358 ? Arrays.stream( values ) 359 .map( SVGDegree::toString ) 360 .collect( joining( "," ) ) 361 : null; 362 setAttribute( SVGATTRIBUTE_Rotate, value ); 363 } // setRotate() 364 365 /** 366 * {@inheritDoc} 367 */ 368 @SuppressWarnings( "UseOfConcreteClass" ) 369 @MountPoint 370 @Override 371 public void setTextLength( final SVGNumber value ) 372 { 373 setAttribute( SVGATTRIBUTE_TextLength, value ); 374 } // setTextLength() 375 376 /** 377 * {@inheritDoc} 378 */ 379 @SuppressWarnings( "UseOfConcreteClass" ) 380 @MountPoint 381 @Override 382 public void setX( final SVGNumber... values ) 383 { 384 final var value = nonNull( values ) && (values.length != 0) 385 ? Arrays.stream( values ) 386 .map( SVGNumber::toString ) 387 .collect( joining( "," ) ) 388 : null; 389 setAttribute( SVGATTRIBUTE_x, value ); 390 } // setX() 391 392 /** 393 * {@inheritDoc} 394 */ 395 @SuppressWarnings( "UseOfConcreteClass" ) 396 @MountPoint 397 @Override 398 public void setX1( final SVGNumber value ) 399 { 400 setAttribute( SVGATTRIBUTE_x1, value ); 401 } // setX1() 402 403 /** 404 * {@inheritDoc} 405 */ 406 @SuppressWarnings( "UseOfConcreteClass" ) 407 @MountPoint 408 @Override 409 public void setX2( final SVGNumber value ) 410 { 411 setAttribute( SVGATTRIBUTE_x2, value ); 412 } // setX2() 413 414 /** 415 * {@inheritDoc} 416 */ 417 @SuppressWarnings( "UseOfConcreteClass" ) 418 @MountPoint 419 @Override 420 public void setY( final SVGNumber... values ) 421 { 422 final var value = nonNull( values ) && (values.length != 0) 423 ? Arrays.stream( values ) 424 .map( SVGNumber::toString ) 425 .collect( joining( "," ) ) 426 : null; 427 setAttribute( SVGATTRIBUTE_y, value ); 428 } // setY() 429 430 /** 431 * {@inheritDoc} 432 */ 433 @SuppressWarnings( "UseOfConcreteClass" ) 434 @MountPoint 435 @Override 436 public void setY1( final SVGNumber value ) 437 { 438 setAttribute( SVGATTRIBUTE_y1, value ); 439 } // setY1() 440 441 /** 442 * {@inheritDoc} 443 */ 444 @SuppressWarnings( "UseOfConcreteClass" ) 445 @MountPoint 446 @Override 447 public void setY2( final SVGNumber value ) 448 { 449 setAttribute( SVGATTRIBUTE_y2, value ); 450 } // setY2() 451 452 /** 453 * {@inheritDoc} 454 */ 455 @MountPoint 456 @Override 457 public String toString( final int indentationLevel, final boolean prettyPrint ) 458 { 459 return super.toString( indentationLevel, prettyPrint ); 460 } // toString() 461} 462// class SVGElementAdapter 463 464/* 465 * End of File 466 */