001/** 002 * Note -- Holds a textual note String located at a point in model space with a fixed size 003 * and orientation on the screen. 004 * 005 * Copyright (C) 2014-2015, Joseph A. Huwaldt. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or modify it under the terms 008 * of the GNU Lesser General Public License as published by the Free Software Foundation; 009 * either version 2.1 of the License, or (at your option) any later version. 010 * 011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License along with 016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 018 */ 019package geomss.geom; 020 021import java.awt.Font; 022import java.util.Objects; 023import static java.util.Objects.requireNonNull; 024import javax.measure.converter.ConversionException; 025import javax.measure.quantity.Length; 026import javax.measure.unit.Unit; 027import javolution.context.ObjectFactory; 028import javolution.lang.ValueType; 029import javolution.xml.XMLFormat; 030import javolution.xml.stream.XMLStreamException; 031 032/** 033 * Represents a textual note located at a point in model space with a fixed size and 034 * orientation on the screen. 035 * 036 * <p> Modified by: Joseph A. Huwaldt </p> 037 * 038 * @author Joseph A. Huwaldt, Date: February 5, 2014 039 * @version November 26, 2015 040 */ 041@SuppressWarnings({"serial", "CloneableImplementsClone"}) 042public final class Note extends GenScreenNote implements ValueType { 043 044 /** 045 * The text string displayed in the note. 046 */ 047 private String text; 048 049 /** 050 * Holds the location of the note and defines it's units. 051 */ 052 private Point location; 053 054 /** 055 * The font used to display the note. 056 */ 057 private Font font; 058 059 /** 060 * Construct and return a new instance of a Note that uses the specified text string, 061 * the specified display font, and is located at the specified location in space. 062 * 063 * @param text The text to be displayed in this geometry object. May not be null. 064 * @param location The location of this geometry object in model space. May not be null. 065 * @param font The font used to display this note. May not be null. 066 * @return A new Note using the specified inputs. 067 */ 068 public static Note valueOf(CharSequence text, GeomPoint location, Font font) { 069 requireNonNull(text); 070 requireNonNull(location); 071 requireNonNull(font); 072 073 Note note = FACTORY.object(); 074 note.text = text.toString(); 075 note.location = location.immutable(); 076 note.font = font; 077 078 return note; 079 } 080 081 /** 082 * Construct and return a new instance of a Note that uses the specified text string, 083 * the default display font at the specified size, and is located at the specified 084 * location in space. 085 * 086 * @param text The text to be displayed in this geometry object. May not be 087 * null. 088 * @param location The location of this geometry object in model space. May not be 089 * null. 090 * @param fontPoints The size of the default font in pixels. 091 * @return A new Note using the specified inputs. 092 */ 093 public static Note valueOf(CharSequence text, GeomPoint location, int fontPoints) { 094 return Note.valueOf(text, location, DEFAULT_FONT.deriveFont((float)fontPoints)); 095 } 096 097 /** 098 * Construct and return a new instance of a Note that uses the specified text string, 099 * the default display font, and is located at the specified location in space. 100 * 101 * @param text The text to be displayed in this geometry object. May not be null. 102 * @param location The location of this geometry object in model space. May not be null. 103 * @return A new Note using the specified inputs. 104 */ 105 public static Note valueOf(CharSequence text, GeomPoint location) { 106 return Note.valueOf(text, location, DEFAULT_FONT); 107 } 108 109 /** 110 * Returns a new Note instance that is identical to the specified Note. 111 * 112 * @param note the Note to be copied into a new Note. May not be null. 113 * @return A new not identical to the input note. 114 */ 115 public static Note valueOf(Note note) { 116 return copyOf(requireNonNull(note)); 117 } 118 119 /** 120 * Return the text string associated with this note object. 121 * 122 * @return The text string associated with this note object. 123 */ 124 @Override 125 public String getNote() { 126 return text; 127 } 128 129 /** 130 * Return the location of this note in model space. 131 * 132 * @return The location of this note in model space. 133 */ 134 @Override 135 public Point getLocation() { 136 return location; 137 } 138 139 /** 140 * Return the font used to display this note. 141 * 142 * @return The font used to display this note. 143 */ 144 @Override 145 public Font getFont() { 146 return font; 147 } 148 149 /** 150 * Return an immutable version of this note. 151 * 152 * @return An immutable version of this note. 153 */ 154 @Override 155 public Note immutable() { 156 return this; 157 } 158 159 /** 160 * Return a new note object identical to this one, but with the specified font. 161 * 162 * @param font The font to use in the copy of this note returned. May not be null. 163 * @return A new note object identical to this one, but with the specified font. 164 */ 165 @Override 166 public Note changeFont(Font font) { 167 Note note = Note.valueOf(text, location, requireNonNull(font)); 168 copyState(note); 169 return note; 170 } 171 172 /** 173 * Return a new note object identical to this one, but with the specified location in 174 * model space. 175 * 176 * @param location The location for the copy of this note returned. May not be null. 177 * @return A new note object identical to this one, but with the specified location in 178 * model space. 179 */ 180 @Override 181 public Note changeLocation(GeomPoint location) { 182 Note note = Note.valueOf(text, requireNonNull(location), font); 183 copyState(note); 184 return note; 185 } 186 187 /** 188 * Returns the number of physical dimensions of the geometry element. This 189 * implementation will return the physical dimensions of the point indicating the 190 * location of the note in space. 191 * 192 * @return The number of physical dimensions of the geometry element. 193 */ 194 @Override 195 public int getPhyDimension() { 196 return location.getPhyDimension(); 197 } 198 199 /** 200 * Return <code>true</code> if this Note contains valid and finite numerical 201 * components. A value of <code>false</code> will be returned if any of the location 202 * coordinate values are NaN or Inf. 203 * 204 * @return true if this Note contains valid and finite numerical components. 205 */ 206 @Override 207 public boolean isValid() { 208 return location.isValid(); 209 } 210 211 /** 212 * Returns a copy of this Note instance 213 * {@link javolution.context.AllocatorContext allocated} by the calling thread 214 * (possibly on the stack). 215 * 216 * @return an identical and independent copy of this note. 217 */ 218 @Override 219 public Note copy() { 220 return copyOf(this); 221 } 222 223 /** 224 * Return a copy of this object with any transformations or subranges removed 225 * (applied). 226 * 227 * @return A copy of this object with any transformations or subranges removed. 228 */ 229 @Override 230 public Note copyToReal() { 231 return copy(); 232 } 233 234 /** 235 * Returns the unit in which the note location Point is stored. 236 * 237 * @return The unit in which the note location Point is stored. 238 */ 239 @Override 240 public final Unit<Length> getUnit() { 241 return location.getUnit(); 242 } 243 244 /** 245 * Returns the equivalent to this note but with the location stated in the specified 246 * unit. 247 * 248 * @param unit the length unit of the note to be returned. May not be null. 249 * @return an equivalent of this note but with location stated in the specified unit. 250 * @throws ConversionException if the the input unit is not a length unit. 251 */ 252 @Override 253 public Note to(Unit<Length> unit) throws ConversionException { 254 if (unit.equals(getUnit())) 255 return this; 256 257 Note note = FACTORY.object(); 258 note.text = text; 259 note.location = location.to(unit); 260 copyState(note); 261 262 return note; 263 } 264 265 /** 266 * Return the equivalent of this note converted to the specified number of physical 267 * dimensions. If the number of dimensions is greater than this element, then zeros 268 * are added to the additional dimensions. If the number of dimensions is less than 269 * this element, then the extra dimensions are simply dropped (truncated). If the new 270 * dimensions are the same as the dimension of this element, then this element is 271 * simply returned. 272 * 273 * @param newDim The dimension of the note to return. 274 * @return The equivalent to this note converted to the new dimensions. 275 */ 276 @Override 277 public Note toDimension(int newDim) { 278 int thisDim = this.getPhyDimension(); 279 if (newDim == thisDim) 280 return this; 281 282 // Convert the underlying geometry. 283 Point nloc = location.toDimension(newDim); 284 285 // Create and return a new note with the new geometry. 286 Note note = Note.valueOf(text, nloc, font); 287 copyState(note); 288 289 return note; 290 } 291 292 /** 293 * Compares this Note against the specified object for strict equality (same values 294 * and same units). 295 * 296 * @param obj the object to compare with. 297 * @return <code>true</code> if this note is identical to that note; 298 * <code>false</code> otherwise. 299 */ 300 @Override 301 public boolean equals(Object obj) { 302 if (this == obj) 303 return true; 304 if ((obj == null) || (obj.getClass() != this.getClass())) 305 return false; 306 307 Note that = (Note)obj; 308 return this.text.equals(that.text) 309 && this.location.equals(that.location) 310 && super.equals(obj); 311 } 312 313 /** 314 * Returns the hash code for this Note object. 315 * 316 * @return the hash code value. 317 */ 318 @Override 319 public int hashCode() { 320 return 31*super.hashCode() + Objects.hash(text, location); 321 } 322 323 /** 324 * Holds the default XML representation for this object. 325 */ 326 @SuppressWarnings("FieldNameHidesFieldInSuperclass") 327 protected static final XMLFormat<Note> XML = new XMLFormat<Note>(Note.class) { 328 329 @Override 330 public Note newInstance(Class<Note> cls, XMLFormat.InputElement xml) throws XMLStreamException { 331 return FACTORY.object(); 332 } 333 334 @Override 335 public void read(XMLFormat.InputElement xml, Note obj) throws XMLStreamException { 336 // Read in the font information. 337 String fontStr = xml.getAttribute("font", DEFAULT_FONT_CODE); 338 Font font = Font.decode(fontStr); 339 340 GenScreenNote.XML.read(xml, obj); // Call parent read. 341 342 // Read in the text string. 343 String text = xml.get("Note", String.class); 344 345 // Read in the location. 346 Point location = xml.get("Location", Point.class); 347 348 // Fill in the object definition. 349 obj.text = text; 350 obj.font = font; 351 obj.location = location; 352 } 353 354 @Override 355 public void write(Note obj, XMLFormat.OutputElement xml) throws XMLStreamException { 356 // Write out a font string. 357 Font font = obj.getFont(); 358 String fontStr = encodeFont(font.getName(), font.getStyle(), font.getSize()); 359 xml.setAttribute("font", fontStr); 360 361 GenScreenNote.XML.write(obj, xml); // Call parent write. 362 363 // Write out the text string. 364 xml.add(obj.getNote(), "Note", String.class); 365 366 // Write out the location of the note in model space. 367 xml.add(obj.getLocation(), "Location", Point.class); 368 } 369 }; 370 371 /////////////////////// 372 // Factory creation. // 373 /////////////////////// 374 private Note() { } 375 376 @SuppressWarnings("unchecked") 377 private static final ObjectFactory<Note> FACTORY = new ObjectFactory<Note>() { 378 @Override 379 protected Note create() { 380 return new Note(); 381 } 382 383 @Override 384 protected void cleanup(Note obj) { 385 obj.reset(); 386 obj.text = null; 387 obj.location = null; 388 } 389 }; 390 391 @SuppressWarnings("unchecked") 392 private static Note copyOf(Note original) { 393 Note obj = FACTORY.object(); 394 obj.text = original.text; 395 obj.location = original.location.copy(); 396 obj.font = original.font; 397 original.copyState(obj); 398 return obj; 399 } 400}