//----------------------------------------------------------------------------// // // // T e x t // // // //----------------------------------------------------------------------------// // <editor-fold defaultstate="collapsed" desc="hdr"> // // Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. // // This software is released under the GNU General Public License. // // Goto http://kenai.com/projects/audiveris to report bugs or suggestions. // //----------------------------------------------------------------------------// // </editor-fold> package omr.score.entity; import omr.glyph.facets.Glyph; import omr.score.visitor.ScoreVisitor; import omr.text.TextLine; import omr.text.TextRole; import omr.text.TextRoleInfo; import omr.text.TextWord; import omr.ui.symbol.TextFont; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Font; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.Collections; import java.util.List; /** * Class {@code Text} handles any textual score entity. * * <p><b>Nota</b>: There is exactly one Text entity per sentence, except for * lyrics items for which we build one {@code LyricsItem} (subclass of Text) * for each textual glyph. * The reason is that, except for lyrics, only the full sentence * is meaningful: for example "Ludwig van Beethoven" is meaningful as a Creator * Text, but the various words "Ludwig", "van", "Beethoven" are not. * For lyrics, since we can have very long sentences, and since the positioning * of every syllable must be done with precision, we handle one LyricsItem Text * entity per isolated word.</p> * * <p>Working at the sentence level also allows a better accuracy in the setting * of parameters (such as baseline or font) for the whole sentence.</p> * * <h4>Synoptic of Text Translation:<br/> * <img src="doc-files/TextTranslation.jpg"/> * </h4> * * @author Hervé Bitteur */ public abstract class Text extends PartNode { //~ Static fields/initializers --------------------------------------------- /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger(Text.class); //~ Instance fields -------------------------------------------------------- // /** The containing sentence. */ private final TextLine sentence; //~ Constructors ----------------------------------------------------------- //------// // Text // //------// /** * Creates a new Text object. * * @param sentence the larger sentence */ public Text (TextLine sentence) { this(sentence, sentence.getLocation()); } //------// // Text // //------// /** * Creates a new Text object, with a specific location, different * from the sentence location. * * @param sentence the larger sentence * @param location specific location */ public Text (TextLine sentence, Point location) { super(sentence.getSystemPart()); this.sentence = sentence; setReferencePoint(location); setBox(sentence.getBounds()); logger.debug("Created {}", this); } //~ Methods ---------------------------------------------------------------- //--------// // accept // //--------// @Override public boolean accept (ScoreVisitor visitor) { return visitor.visit(this); } //------------// // getContent // //------------// /** * Report the current string value of this text * * @return the string value of this text */ public String getContent () { return sentence.getValue(); } //---------------------// // getExportedFontSize // //---------------------// /** * Report the font size to be exported for this text * * @return the exported font size */ public int getExportedFontSize () { return (int) Math.rint( sentence.getMeanFont().pointsize * TextFont.TO_POINT); } //---------------// // getLyricsFont // //---------------// /** * Report the font to be used for handling lyrics text * * @return the lyrics text font */ public static Font getLyricsFont () { return TextFont.baseTextFont; } //-------------------// // getLyricsFontSize // //-------------------// /** * Report the font size to be exported for the lyrics * * @return the exported lyrics font size */ public static int getLyricsFontSize () { return TextFont.baseTextFont.getSize(); } //-------------// // getSentence // //-------------// /** * Report the sentence that relates to this text * * @return the related sentence */ public TextLine getSentence () { return sentence; } //---------------------// // getTranslationLinks // //---------------------// @Override public List<Line2D> getTranslationLinks (Glyph glyph) { return Collections.emptyList(); // By default } //----------// // getWidth // //----------// /** * Report the width of this text * * @return the text width */ public int getWidth () { return getBox().width; } //----------// // populate // //----------// /** * Allocate the proper score entity (or entities) that correspond * to this textual sentence. * This word or sequence of words may be: * <ul> * <li>a Direction</li> * <li>a part Name</li> * <li>a part Number</li> * <li>a Creator</li> * <li>a Copyright</li> * <li>one or several LyricsItem entities</li> * <li>a Chord Statement</li> * </ul> * * @param sentence the whole sentence * @param location its starting reference wrt containing system */ public static void populate (TextLine sentence, Point location) { final SystemPart systemPart = sentence.getSystemPart(); final TextRoleInfo roleInfo = sentence.getRole(); final TextRole role = roleInfo.role; if ((role == null) || (role == TextRole.UnknownRole)) { systemPart.addError( sentence.getFirstWord().getGlyph(), "Sentence with no role defined"); } logger.debug( "Populating {} {} \"{}\"", sentence, role, sentence.getValue()); if (role == null) { return; } switch (role) { case Lyrics: // Create as many lyrics items as needed for (TextWord word : sentence.getWords()) { Glyph glyph = word.getGlyph(); Rectangle itemBox = word.getBounds(); String itemStr = word.getValue(); if (itemStr == null) { // A very rough char count ... // int nbChar = (int) Math.rint( // (double) itemBox.width / sentence.getTextHeight()); int nbChar = 5; itemStr = role.getStringHolder(nbChar); } Point2D p1 = word.getBaseline() .getP1(); Point start = new Point( (int) Math.rint(p1.getX()), (int) Math.rint(p1.getY())); glyph.setTranslation( new LyricsItem( sentence, start, glyph, itemBox.width, itemStr)); } break; case Title: sentence.setGlyphsTranslation(new TitleText(sentence)); break; case Direction: Measure measure = systemPart.getMeasureAt(location); sentence.setGlyphsTranslation( new DirectionStatement( measure, location, measure.getDirectionChord(location), new DirectionText(sentence))); break; case Number: sentence.setGlyphsTranslation(new NumberText(sentence)); break; case Name: sentence.setGlyphsTranslation(new NameText(sentence)); break; case Creator: sentence.setGlyphsTranslation(new CreatorText(sentence)); break; case Rights: sentence.setGlyphsTranslation(new RightsText(sentence)); break; case Chord: measure = systemPart.getMeasureAt(location); sentence.setGlyphsTranslation( new ChordSymbol( measure, location, measure.getEventChord(location), new ChordText(sentence))); break; case UnknownRole: default: sentence.setGlyphsTranslation(new DefaultText(sentence)); } } //----------// // toString // //----------// /** * {@inheritDoc} */ @Override public String toString () { StringBuilder sb = new StringBuilder(); sb.append("{Text"); if (sentence.getRole() != null) { sb.append(" ") .append(sentence.getRole()); } sb.append(internalsString()); if (getContent() != null) { sb.append(" \"") .append(getContent()) .append("\""); } sb.append(" loc:") .append(getReferencePoint()); sb.append(" S") .append(getSystem().getId()); sb.append("P") .append(getPart().getId()); sb.append("}"); return sb.toString(); } //-----------------------// // computeReferencePoint // //-----------------------// @Override protected void computeReferencePoint () { setReferencePoint(sentence.getLocation()); } //-----------------// // internalsString // //-----------------// /** * Return the string of the internals of this class, for inclusion * in a toString(). * * @return the string of internals */ protected String internalsString () { return ""; // By default } //~ Inner Classes ---------------------------------------------------------- //-----------// // ChordText // //-----------// /** Subclass of Text, dedicated to a chord marker. */ public static class ChordText extends Text { //~ Constructors ------------------------------------------------------- public ChordText (TextLine sentence) { super(sentence); } } //-------------// // CreatorText // //-------------// /** Subclass of Text, dedicated to a Creator (composer, lyricist, * etc...). */ public static class CreatorText extends Text { //~ Enumerations ------------------------------------------------------- public enum CreatorType { //~ Enumeration constant initializers ------------------------------ composer, lyricist, arranger; } //~ Constructors ------------------------------------------------------- public CreatorText (TextLine sentence) { super(sentence); } } //-------------// // DefaultText // //-------------// /** * Subclass of Text, with no precise role assigned. */ public static class DefaultText extends Text { //~ Constructors ------------------------------------------------------- public DefaultText (TextLine sentence) { super(sentence); } } //---------------// // DirectionText // //---------------// /** Subclass of Text, dedicated to a Direction instruction. */ public static class DirectionText extends Text { //~ Constructors ------------------------------------------------------- public DirectionText (TextLine sentence) { super(sentence); } } //----------// // NameText // //----------// /** Subclass of Text, dedicated to a part Name. */ public static class NameText extends Text { //~ Constructors ------------------------------------------------------- public NameText (TextLine sentence) { super(sentence); if (getContent() != null) { sentence.getSystemPart() .setName(getContent()); } } } //------------// // NumberText // //------------// /** Subclass of Text, dedicated to a score Number. */ public static class NumberText extends Text { //~ Constructors ------------------------------------------------------- public NumberText (TextLine sentence) { super(sentence); } } //------------// // RightsText // //------------// /** Subclass of Text, dedicated to a copyright statement. */ public static class RightsText extends Text { //~ Constructors ------------------------------------------------------- public RightsText (TextLine sentence) { super(sentence); } } //-----------// // TitleText // //-----------// /** Subclass of Text, dedicated to a score Title. */ public static class TitleText extends Text { //~ Constructors ------------------------------------------------------- public TitleText (TextLine sentence) { super(sentence); } } }