Package com.positive.charts.util

Source Code of com.positive.charts.util.TextUtilities

package com.positive.charts.util;

import java.text.BreakIterator;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontMetrics;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;

public class TextUtilities {

  /**
   * Creates a {@link TextBlock} from a <code>String</code>. Line breaks are
   * added where the <code>String</code> contains '\n' characters.
   *
   * @param text
   *            the text.
   * @param font
   *            the font.
   * @param paint
   *            the paint.
   *
   * @return A text block.
   */
  public static TextBlock createTextBlock(final String text, final Font font,
      final Color paint) {
    if (text == null) {
      throw new IllegalArgumentException("Null 'text' argument.");
    }
    final TextBlock result = new TextBlock();
    String input = text;
    boolean moreInputToProcess = (text.length() > 0);
    final int start = 0;
    while (moreInputToProcess) {
      final int index = input.indexOf("\n");
      if (index > start) {
        final String line = input.substring(start, index);
        if (index < input.length() - 1) {
          result.addLine(line, font, paint);
          input = input.substring(index + 1);
        } else {
          moreInputToProcess = false;
        }
      } else if (index == start) {
        if (index < input.length() - 1) {
          input = input.substring(index + 1);
        } else {
          moreInputToProcess = false;
        }
      } else {
        result.addLine(input, font, paint);
        moreInputToProcess = false;
      }
    }
    return result;
  }

  /**
   * Creates a new text block from the given string, breaking the text into
   * lines so that the <code>maxWidth</code> value is respected.
   *
   * @param text
   *            the text.
   * @param font
   *            the font.
   * @param paint
   *            the paint.
   * @param maxWidth
   *            the maximum width for each line.
   * @param maxLines
   *            the maximum number of lines.
   * @param measurer
   *            the text measurer.
   *
   * @return A text block.
   */
  public static TextBlock createTextBlock(final String text, final Font font,
      final Color paint, final float maxWidth, final int maxLines,
      final TextMeasurer measurer) {

    final TextBlock result = new TextBlock();
    final BreakIterator iterator = BreakIterator.getLineInstance();
    iterator.setText(text);
    int current = 0;
    int lines = 0;
    final int length = text.length();
    while ((current < length) && (lines < maxLines)) {
      final int next = nextLineBreak(text, current, maxWidth, iterator,
          measurer);
      if (next == BreakIterator.DONE) {
        result.addLine(text.substring(current), font, paint);
        return result;
      }
      result.addLine(text.substring(current, next), font, paint);
      lines++;
      current = next;
      while ((current < text.length()) && (text.charAt(current) == '\n')) {
        current++;
      }
    }
    if (current < length) {
      final TextLine lastLine = result.getLastLine();
      final TextFragment lastFragment = lastLine.getLastTextFragment();
      final String oldStr = lastFragment.getText();
      String newStr = "...";
      if (oldStr.length() > 3) {
        newStr = oldStr.substring(0, oldStr.length() - 3) + "...";
      }

      lastLine.removeFragment(lastFragment);
      final TextFragment newFragment = new TextFragment(newStr,
          lastFragment.getFont(), lastFragment.getPaint());
      lastLine.addFragment(newFragment);
    }
    return result;
  }

  /**
   * A utility method that calculates the rotation anchor offsets for a
   * string. These offsets are relative to the text starting coordinate
   * (BASELINE_LEFT).
   *
   * @param g2
   *            the graphics device.
   * @param text
   *            the text.
   * @param anchor
   *            the anchor point.
   *
   * @return The offsets.
   */
  private static float[] deriveRotationAnchorOffsets(final GC g2,
      final String text, final TextAnchor anchor) {

    final float[] result = new float[2];
    final FontMetrics fm = g2.getFontMetrics();
    final Rectangle bounds = TextUtilities.getTextBounds(text, g2);
    final float ascent = fm.getAscent();
    final float halfAscent = ascent / 2.0f;
    final float descent = fm.getDescent();
    final float leading = fm.getLeading();
    float xAdj = 0.0f;
    float yAdj = 0.0f;

    if ((anchor == TextAnchor.TOP_LEFT)
        || (anchor == TextAnchor.CENTER_LEFT)
        || (anchor == TextAnchor.BOTTOM_LEFT)
        || (anchor == TextAnchor.BASELINE_LEFT)
        || (anchor == TextAnchor.HALF_ASCENT_LEFT)) {

      xAdj = 0.0f;

    } else if ((anchor == TextAnchor.TOP_CENTER)
        || (anchor == TextAnchor.CENTER)
        || (anchor == TextAnchor.BOTTOM_CENTER)
        || (anchor == TextAnchor.BASELINE_CENTER)
        || (anchor == TextAnchor.HALF_ASCENT_CENTER)) {

      xAdj = bounds.width / 2.0f;

    } else if ((anchor == TextAnchor.TOP_RIGHT)
        || (anchor == TextAnchor.CENTER_RIGHT)
        || (anchor == TextAnchor.BOTTOM_RIGHT)
        || (anchor == TextAnchor.BASELINE_RIGHT)
        || (anchor == TextAnchor.HALF_ASCENT_RIGHT)) {

      xAdj = bounds.width;

    }

    if ((anchor == TextAnchor.TOP_LEFT)
        || (anchor == TextAnchor.TOP_CENTER)
        || (anchor == TextAnchor.TOP_RIGHT)) {

      yAdj = descent + leading - bounds.height;

    } else if ((anchor == TextAnchor.CENTER_LEFT)
        || (anchor == TextAnchor.CENTER)
        || (anchor == TextAnchor.CENTER_RIGHT)) {

      yAdj = descent + leading - (float) (bounds.height / 2.0);

    } else if ((anchor == TextAnchor.HALF_ASCENT_LEFT)
        || (anchor == TextAnchor.HALF_ASCENT_CENTER)
        || (anchor == TextAnchor.HALF_ASCENT_RIGHT)) {

      yAdj = -halfAscent;

    } else if ((anchor == TextAnchor.BASELINE_LEFT)
        || (anchor == TextAnchor.BASELINE_CENTER)
        || (anchor == TextAnchor.BASELINE_RIGHT)) {

      yAdj = 0.0f;

    } else if ((anchor == TextAnchor.BOTTOM_LEFT)
        || (anchor == TextAnchor.BOTTOM_CENTER)
        || (anchor == TextAnchor.BOTTOM_RIGHT)) {

      yAdj = fm.getDescent() + fm.getLeading();

    }
    result[0] = xAdj;
    result[1] = yAdj;
    return result;

  }

  /**
   * A utility method that calculates the anchor offsets for a string.
   * Normally, the (x, y) coordinate for drawing text is a point on the
   * baseline at the left of the text string. If you add these offsets to (x,
   * y) and draw the string, then the anchor point should coincide with the
   * (x, y) point.
   *
   * @param g2
   *            the graphics device (not <code>null</code>).
   * @param text
   *            the text.
   * @param anchor
   *            the anchor point.
   * @param textBounds
   *            the receiver for resulting text bounds
   *
   * @return The offsets.
   */
  private static float[] deriveTextBoundsAnchorOffsets(final GC g2,
      final String text, final TextAnchor anchor,
      final Rectangle textBounds) {

    final float[] result = new float[2];
    final FontMetrics fm = g2.getFontMetrics();
    final Rectangle bounds = TextUtilities.getTextBounds(text, g2);
    final float ascent = fm.getAscent();
    final float halfAscent = ascent / 2.0f;
    final float leading = fm.getLeading();

    float xAdj = 0.0f;
    float yAdj = 0.0f;

    // Horizontal adjustment
    if (anchor.isCenterAligned()) {
      xAdj = -bounds.width / 2.0f;

    } else if (anchor.isRightAligned()) {
      xAdj = -bounds.width;
    }

    // Vertical adjustment
    if (anchor.isTopAligned()) {

      yAdj = 0.0f;

    } else if ((anchor == TextAnchor.HALF_ASCENT_LEFT)
        || (anchor == TextAnchor.HALF_ASCENT_CENTER)
        || (anchor == TextAnchor.HALF_ASCENT_RIGHT)) {

      yAdj = -leading - halfAscent;

    } else if (anchor.isVerticallyCenterAligned()) {

      yAdj = (float) (-bounds.height / 2.0);

    } else if ((anchor == TextAnchor.BASELINE_LEFT)
        || (anchor == TextAnchor.BASELINE_CENTER)
        || (anchor == TextAnchor.BASELINE_RIGHT)) {

      yAdj = -leading - ascent;

    } else if ((anchor == TextAnchor.BOTTOM_LEFT)
        || (anchor == TextAnchor.BOTTOM_CENTER)
        || (anchor == TextAnchor.BOTTOM_RIGHT)) {

      yAdj = -bounds.height;

    }

    if (textBounds != null) {
      RectangleUtil.setRect(textBounds, bounds);
    }

    result[0] = xAdj;
    result[1] = yAdj;
    return result;
  }

  /**
   * Draws a string such that the specified anchor point is aligned to the
   * given (x, y) location.
   *
   * @param text
   *            the text.
   * @param g2
   *            the graphics device.
   * @param x
   *            the x coordinate (Java 2D).
   * @param y
   *            the y coordinate (Java 2D).
   * @param anchor
   *            the anchor location.
   *
   * @return The text bounds (adjusted for the text position).
   */
  public static Rectangle drawAlignedString(final String text, final GC g2,
      final float x, final float y, final TextAnchor anchor) {

    final Rectangle textBounds = new Rectangle(0, 0, 0, 0);
    final float[] adjust = deriveTextBoundsAnchorOffsets(g2, text, anchor,
        textBounds);
    // adjust text bounds to match string position
    RectangleUtil.setRect(textBounds, (int) (x + adjust[0]),
        (int) (y + adjust[1]), textBounds.width, textBounds.height);
    g2.drawString(text, textBounds.x, textBounds.y, true);
    return textBounds;
  }

  /**
   * A utility method for drawing rotated text.
   * <P>
   * A common rotation is -Math.PI/2 which draws text 'vertically' (with the
   * top of the characters on the left).
   *
   * @param text
   *            the text.
   * @param g2
   *            the graphics device.
   * @param angle
   *            the angle of the (clockwise) rotation (in radians).
   * @param x
   *            the x-coordinate.
   * @param y
   *            the y-coordinate.
   */
  public static void drawRotatedString(final String text, final GC g2,
      final double angle, final float x, final float y) {
    drawRotatedString(text, g2, x, y, angle, x, y);
  }

  /**
   * A utility method for drawing rotated text.
   * <P>
   * A common rotation is -Math.PI/2 which draws text 'vertically' (with the
   * top of the characters on the left).
   *
   * @param text
   *            the text.
   * @param g2
   *            the graphics device.
   * @param textX
   *            the x-coordinate for the text (before rotation).
   * @param textY
   *            the y-coordinate for the text (before rotation).
   * @param angle
   *            the angle of the (clockwise) rotation (in radians).
   * @param rotateX
   *            the point about which the text is rotated.
   * @param rotateY
   *            the point about which the text is rotated.
   */
  public static void drawRotatedString(final String text, final GC g2,
      final float textX, final float textY, final double angle,
      final float rotateX, final float rotateY) {

    if ((text == null) || (text.length() == 0)) {
      return;
    }

    if (angle != 0.0) {
      final Transform transform = new Transform(g2.getDevice());
      transform.translate(rotateX, rotateY);
      transform.rotate((float) (-angle * 180 / Math.PI));
      transform.translate(-rotateX, -rotateY);
      g2.setTransform(transform);
      transform.dispose();
    }

    g2.drawString(text, (int) textX, (int) textY, true);

    if (angle != 0.0) {
      g2.setTransform(null);
    }
  }

  /**
   * Draws a string that is aligned by one anchor point and rotated about
   * another anchor point.
   *
   * @param text
   *            the text.
   * @param g2
   *            the graphics device.
   * @param x
   *            the x-coordinate for positioning the text.
   * @param y
   *            the y-coordinate for positioning the text.
   * @param textAnchor
   *            the text anchor.
   * @param angle
   *            the rotation angle.
   * @param rotationX
   *            the x-coordinate for the rotation anchor point.
   * @param rotationY
   *            the y-coordinate for the rotation anchor point.
   */
  public static void drawRotatedString(final String text, final GC g2,
      final float x, final float y, final TextAnchor textAnchor,
      final double angle, final float rotationX, final float rotationY) {

    if ((text == null) || (text.length() == 0)) {
      return;
    }
    final float[] textAdj = deriveTextBoundsAnchorOffsets(g2, text,
        textAnchor, null);
    drawRotatedString(text, g2, x + textAdj[0], y + textAdj[1], angle,
        rotationX, rotationY);
  }

  /**
   * Draws a string that is aligned by one anchor point and rotated about
   * another anchor point.
   *
   * @param text
   *            the text.
   * @param g2
   *            the graphics device.
   * @param x
   *            the x-coordinate for positioning the text.
   * @param y
   *            the y-coordinate for positioning the text.
   * @param textAnchor
   *            the text anchor.
   * @param angle
   *            the rotation angle (in radians).
   * @param rotationAnchor
   *            the rotation anchor.
   */
  public static void drawRotatedString(final String text, final GC g2,
      final float x, final float y, final TextAnchor textAnchor,
      final double angle, final TextAnchor rotationAnchor) {

    if ((text == null) || (text.length() == 0)) {
      return;
    }
    final float[] textAdj = deriveTextBoundsAnchorOffsets(g2, text,
        textAnchor, null);
    final float[] rotateAdj = deriveRotationAnchorOffsets(g2, text,
        rotationAnchor);
    // final float[] rotateAdj = new float[] { 0.0f, 0.0f };
    drawRotatedString(text, g2, x + textAdj[0], y + textAdj[1], angle, x
        + textAdj[0] + rotateAdj[0], y + textAdj[1] + rotateAdj[1]);

  }

  /**
   * Returns the bounds for the specified text.
   *
   * @param text
   *            the text (<code>null</code> permitted).
   * @param g2
   *            the graphics context (not <code>null</code>).
   * @return The text bounds (<code>null</code> if the <code>text</code>
   *         argument is <code>null</code>).
   *
   */
  public static Rectangle getTextBounds(final String text, final GC g2) {
    final Point extent = g2.textExtent(text);
    return new Rectangle(0, 0, extent.x, extent.y);
  }

  /**
   * Returns the character index of the next line break.
   *
   * @param text
   *            the text.
   * @param start
   *            the start index.
   * @param width
   *            the target display width.
   * @param iterator
   *            the word break iterator.
   * @param measurer
   *            the text measurer.
   *
   * @return The index of the next line break.
   */
  private static int nextLineBreak(final String text, final int start,
      final float width, final BreakIterator iterator,
      final TextMeasurer measurer) {

    // this method is (loosely) based on code in JFreeReport's
    // TextParagraph class
    int current = start;
    int end;
    float x = 0.0f;
    boolean firstWord = true;
    int newline = text.indexOf('\n', start);
    if (newline < 0) {
      newline = Integer.MAX_VALUE;
    }
    while (((end = iterator.next()) != BreakIterator.DONE)) {
      if (end > newline) {
        return newline;
      }
      x += measurer.getStringWidth(text, current, end);
      if (x > width) {
        if (firstWord) {
          while (measurer.getStringWidth(text, start, end) > width) {
            end--;
            if (end <= start) {
              return end;
            }
          }
          return end;
        } else {
          end = iterator.previous();
          return end;
        }
      }
      // we found at least one word that fits ...
      firstWord = false;
      current = end;
    }
    return BreakIterator.DONE;
  }

  /**
   * Private constructor prevents object creation.
   */
  private TextUtilities() {
  }

}
TOP

Related Classes of com.positive.charts.util.TextUtilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.