Package plotter

Source Code of plotter.MultiLineLabelUI

/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package plotter;

import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.LEADING;
import static javax.swing.SwingConstants.LEFT;
import static javax.swing.SwingConstants.RIGHT;
import static javax.swing.SwingConstants.TOP;
import static javax.swing.SwingConstants.TRAILING;

import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Component.BaselineResizeBehavior;
import java.awt.geom.AffineTransform;
import java.util.StringTokenizer;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import javax.swing.plaf.basic.BasicLabelUI;

/**
* This code was found at http://codeguru.earthweb.com/java/articles/198.shtml.
* This was posted by Zafir Anjum on 28-Jul-1999.
* Modified by Adam Crume.
*/
public class MultiLineLabelUI extends BasicLabelUI {
  public static final String ROTATION_KEY = Rotation.class.getName();

  public static final MultiLineLabelUI labelUI = new MultiLineLabelUI();


  protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, Icon icon, Rectangle viewR,
      Rectangle iconR, Rectangle textR) {
    String s = layoutCompoundLabel((JComponent) label, fontMetrics, splitStringByLines(text), icon, label
        .getVerticalAlignment(), label.getHorizontalAlignment(), label.getVerticalTextPosition(), label
        .getHorizontalTextPosition(), viewR, iconR, textR, label.getIconTextGap());

    if(s.equals(""))
      return text;
    return s;
  }


  /**
   * Compute and return the location of the icons origin, the
   * location of origin of the text baseline, and a possibly clipped
   * version of the compound labels string.  Locations are computed
   * relative to the viewR rectangle.
   * The JComponents orientation (LEADING/TRAILING) will also be taken
   * into account and translated into LEFT/RIGHT values accordingly.
   */
  public static String layoutCompoundLabel(JComponent c, FontMetrics fm, String[] text, Icon icon,
      int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition,
      Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap) {
    boolean orientationIsLeftToRight = true;
    int hAlign = horizontalAlignment;
    int hTextPos = horizontalTextPosition;


    if(c != null) {
      if(!(c.getComponentOrientation().isLeftToRight())) {
        orientationIsLeftToRight = false;
      }
    }


    // Translate LEADING/TRAILING values in horizontalAlignment
    // to LEFT/RIGHT values depending on the components orientation
    switch(horizontalAlignment) {
    case LEADING:
      hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
      break;
    case TRAILING:
      hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
      break;
    }

    // Translate LEADING/TRAILING values in horizontalTextPosition
    // to LEFT/RIGHT values depending on the components orientation
    switch(horizontalTextPosition) {
    case LEADING:
      hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
      break;
    case TRAILING:
      hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
      break;
    }

    return layoutCompoundLabel(fm, text, icon, verticalAlignment, hAlign, verticalTextPosition, hTextPos, viewR,
        iconR, textR, textIconGap);
  }


  /**
   * Compute and return the location of the icons origin, the
   * location of origin of the text baseline, and a possibly clipped
   * version of the compound labels string.  Locations are computed
   * relative to the viewR rectangle.
   * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
   * values in horizontalTextPosition (they will default to RIGHT) and in
   * horizontalAlignment (they will default to CENTER).
   * Use the other version of layoutCompoundLabel() instead.
   */
  public static String layoutCompoundLabel(FontMetrics fm, String[] text, Icon icon, int verticalAlignment,
      int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR,
      Rectangle iconR, Rectangle textR, int textIconGap) {
    /* Initialize the icon bounds rectangle iconR.
     */

    if(icon != null) {
      iconR.width = icon.getIconWidth();
      iconR.height = icon.getIconHeight();
    } else {
      iconR.width = iconR.height = 0;
    }

    /* Initialize the text bounds rectangle textR.  If a null
     * or and empty String was specified we substitute "" here
     * and use 0,0,0,0 for textR.
     */

    // Fix for textIsEmpty sent by Paulo Santos
    boolean textIsEmpty = (text == null) || (text.length == 0)
        || (text.length == 1 && ((text[0] == null) || text[0].equals("")));

    String rettext = "";
    if(textIsEmpty) {
      textR.width = textR.height = 0;
    } else {
      Dimension dim = computeMultiLineDimension(fm, text);
      textR.width = dim.width;
      textR.height = dim.height;
    }

    /* Unless both text and icon are non-null, we effectively ignore
     * the value of textIconGap.  The code that follows uses the
     * value of gap instead of textIconGap.
     */

    int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;

    if(!textIsEmpty) {

      /* If the label text string is too wide to fit within the available
       * space "..." and as many characters as will fit will be
       * displayed instead.
       */

      int availTextWidth;

      if(horizontalTextPosition == CENTER) {
        availTextWidth = viewR.width;
      } else {
        availTextWidth = viewR.width - (iconR.width + gap);
      }


      if(textR.width > availTextWidth && text.length == 1) {
        String clipString = "...";
        int totalWidth = SwingUtilities.computeStringWidth(fm, clipString);
        int nChars;
        for(nChars = 0; nChars < text[0].length(); nChars++) {
          totalWidth += fm.charWidth(text[0].charAt(nChars));
          if(totalWidth > availTextWidth) {
            break;
          }
        }
        rettext = text[0].substring(0, nChars) + clipString;
        textR.width = SwingUtilities.computeStringWidth(fm, rettext);
      }
    }


    /* Compute textR.x,y given the verticalTextPosition and
     * horizontalTextPosition properties
     */

    if(verticalTextPosition == TOP) {
      if(horizontalTextPosition != CENTER) {
        textR.y = 0;
      } else {
        textR.y = -(textR.height + gap);
      }
    } else if(verticalTextPosition == CENTER) {
      textR.y = (iconR.height / 2) - (textR.height / 2);
    } else { // (verticalTextPosition == BOTTOM)
      if(horizontalTextPosition != CENTER) {
        textR.y = iconR.height - textR.height;
      } else {
        textR.y = (iconR.height + gap);
      }
    }

    if(horizontalTextPosition == LEFT) {
      textR.x = -(textR.width + gap);
    } else if(horizontalTextPosition == CENTER) {
      textR.x = (iconR.width / 2) - (textR.width / 2);
    } else { // (horizontalTextPosition == RIGHT)
      textR.x = (iconR.width + gap);
    }

    /* labelR is the rectangle that contains iconR and textR.
     * Move it to its proper position given the labelAlignment
     * properties.
     *
     * To avoid actually allocating a Rectangle, Rectangle.union
     * has been inlined below.
     */
    int labelR_x = Math.min(iconR.x, textR.x);
    int labelR_width = Math.max(iconR.x + iconR.width, textR.x + textR.width) - labelR_x;
    int labelR_y = Math.min(iconR.y, textR.y);
    int labelR_height = Math.max(iconR.y + iconR.height, textR.y + textR.height) - labelR_y;

    int dx, dy;

    if(verticalAlignment == TOP) {
      dy = viewR.y - labelR_y;
    } else if(verticalAlignment == CENTER) {
      dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
    } else { // (verticalAlignment == BOTTOM)
      dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
    }

    if(horizontalAlignment == LEFT) {
      dx = viewR.x - labelR_x;
    } else if(horizontalAlignment == RIGHT) {
      dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
    } else { // (horizontalAlignment == CENTER)
      dx = (viewR.x + (viewR.width / 2)) - (labelR_x + (labelR_width / 2));
    }

    /* Translate textR and glypyR by dx,dy.
     */

    textR.x += dx;
    textR.y += dy;

    iconR.x += dx;
    iconR.y += dy;

    return rettext;
  }


  protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, int textY) {
    int accChar = l.getDisplayedMnemonic();
    g.setColor(l.getForeground());
    drawString(g, s, accChar, textX, textY);
  }


  protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, int textY) {
    int accChar = l.getDisplayedMnemonic();
    g.setColor(l.getBackground());
    drawString(g, s, accChar, textX, textY);
  }


  protected void drawString(Graphics g, String s, int accChar, int textX, int textY) {
    if(s.indexOf('\n') == -1)
      BasicGraphicsUtils.drawString(g, s, accChar, textX, textY);
    else {
      String[] strs = splitStringByLines(s);
      int height = g.getFontMetrics().getHeight();
      // Only the first line can have the accel char
      BasicGraphicsUtils.drawString(g, strs[0], accChar, textX, textY);
      for(int i = 1; i < strs.length; i++)
        g.drawString(strs[i], textX, textY + (height * i));
    }
  }


  public static Dimension computeMultiLineDimension(FontMetrics fm, String[] strs) {
    int i, c, width = 0;
    for(i = 0, c = strs.length; i < c; i++)
      width = Math.max(width, SwingUtilities.computeStringWidth(fm, strs[i]));
    return new Dimension(width, fm.getHeight() * strs.length);
  }


  protected String str;

  protected String[] strs;


  public String[] splitStringByLines(String str) {
    if(str.equals(this.str))
      return strs;

    this.str = str;

    int lines = 1;
    int i, c;
    for(i = 0, c = str.length(); i < c; i++) {
      if(str.charAt(i) == '\n')
        lines++;
    }
    strs = new String[lines];
    StringTokenizer st = new StringTokenizer(str, "\n");

    int line = 0;
    while(st.hasMoreTokens())
      strs[line++] = st.nextToken();

    return strs;
  }


  @Override
  public int getBaseline(JComponent c, int width, int height) {
    Rotation rotation = (Rotation) c.getClientProperty(ROTATION_KEY);
    if(rotation == Rotation.CCW || rotation == Rotation.CW) {
      return -1;
    } else if(rotation == Rotation.HALF) {
      int baseline = super.getBaseline(c, width, height);
      if(baseline < 0) {
        return baseline;
      } else {
        return height - baseline;
      }
    }
    return super.getBaseline(c, width, height);
  }


  @Override
  public BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) {
    Rotation rotation = (Rotation) c.getClientProperty(ROTATION_KEY);
    if(rotation == Rotation.CCW || rotation == Rotation.CW) {
      return BaselineResizeBehavior.OTHER;
    } else if(rotation == Rotation.HALF) {
      BaselineResizeBehavior b = super.getBaselineResizeBehavior(c);
      if(b == BaselineResizeBehavior.CONSTANT_ASCENT) {
        return BaselineResizeBehavior.CONSTANT_DESCENT;
      } else if(b == BaselineResizeBehavior.CONSTANT_DESCENT) {
        return BaselineResizeBehavior.CONSTANT_ASCENT;
      } else {
        return b;
      }
    }
    return super.getBaselineResizeBehavior(c);
  }

  private static Rectangle paintIconR = new Rectangle();

  private static Rectangle paintTextR = new Rectangle();

  private static Rectangle paintViewR = new Rectangle();

  private static Insets paintViewInsets = new Insets(0, 0, 0, 0);


  @Override
  public void paint(Graphics g, JComponent c) {
    // This method adapted from http://tech.chitgoks.com/2009/11/13/rotate-jlabel-vertically/
    JLabel label = (JLabel) c;
    String text = label.getText();
    Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon();

    if((icon == null) && (text == null)) {
      return;
    }

    Rotation rotation = getRotation(c);
    FontMetrics fm = g.getFontMetrics();
    paintViewInsets = c.getInsets(paintViewInsets);

    paintViewR.x = paintViewInsets.left;
    paintViewR.y = paintViewInsets.top;

    if(rotation.isXYSwitched()) {
      paintViewR.height = c.getWidth() - (paintViewInsets.left + paintViewInsets.right);
      paintViewR.width = c.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
    } else {
      paintViewR.width = c.getWidth() - (paintViewInsets.left + paintViewInsets.right);
      paintViewR.height = c.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
    }

    paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0;
    paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0;

    String clippedText = layoutCL(label, fm, text, icon, paintViewR, paintIconR, paintTextR);

    Graphics2D g2 = (Graphics2D) g;
    AffineTransform tr = g2.getTransform();
    switch(rotation) {
    case NONE:
      break;
    case CW:
      g2.rotate(Math.PI / 2);
      g2.translate(0, -c.getWidth());
      break;
    case CCW:
      g2.rotate(-Math.PI / 2);
      g2.translate(-c.getHeight(), 0);
      break;
    case HALF:
      g2.rotate(Math.PI);
      g2.translate(-c.getWidth(), -c.getHeight());
      break;
    }

    if(icon != null) {
      icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
    }

    if(text != null) {
      int textX = paintTextR.x;
      int textY = paintTextR.y + fm.getAscent();

      if(label.isEnabled()) {
        paintEnabledText(label, g, clippedText, textX, textY);
      } else {
        paintDisabledText(label, g, clippedText, textX, textY);
      }
    }
    g2.setTransform(tr);
  }


  private Rotation getRotation(JComponent c) {
    Rotation rotation = (Rotation) c.getClientProperty(ROTATION_KEY);
    if(rotation == null) {
      rotation = Rotation.NONE;
    }
    return rotation;
  }


  @Override
  public Dimension getPreferredSize(JComponent c) {
    Dimension d = super.getPreferredSize(c);
    if(getRotation(c).isXYSwitched()) {
      d.setSize(d.getHeight(), d.getWidth());
    }
    return d;
  }
}
TOP

Related Classes of plotter.MultiLineLabelUI

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.