Package org.apache.harmony.awt.text

Source Code of org.apache.harmony.awt.text.TextUtils

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You 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.
*/
/**
* @author Evgeniya G. Maenkova, Alexey A. Ivanov
*/

package org.apache.harmony.awt.text;

import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.font.TextAttribute;
import java.io.IOException;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.BreakIterator;
import java.text.CharacterIterator;
import java.text.DateFormat;
import java.text.Format.Field;
import java.util.Calendar;
import java.util.Date;

import javax.swing.BoundedRangeModel;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFormattedTextField;
import javax.swing.SwingConstants;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DateFormatter;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.PlainDocument;
import javax.swing.text.Position;
import javax.swing.text.Segment;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.TabExpander;
import javax.swing.text.View;
import javax.swing.text.Position.Bias;

import org.apache.harmony.awt.ComponentInternals;
import org.apache.harmony.awt.internal.nls.Messages;


public class TextUtils {
    public TextUtils() {
    }
    static final Position.Bias backward = Position.Bias.Backward;

    static final Position.Bias forward = Position.Bias.Forward;

    /**
     * Sets new value to dot or mark of the given component caret
     * depending on <code>isMovingCaret</code> value
     */
    public static final void changeCaretPosition(
        final TextKit textKit,
        final int newPos,
        final boolean isMovingCaret) {

        TextCaret caret = textKit.getCaret();

        Point pt = caret.getMagicCaretPosition();
        if (isMovingCaret) {
            caret.moveDot(newPos, Position.Bias.Forward);
        } else {
            caret.setDot(newPos, Position.Bias.Forward);
        }
        caret.setMagicCaretPosition(pt);
    }

//  TODO remove this method as duplicate


     /**
      * Sets new value to dot or mark of the given component caret
      * depending on <code>isMovingCaret</code> value
      */
     public static final void changeCaretPosition(
         final TextKit textKit, final int newPos,
         final boolean isMovingCaret, final Position.Bias newBias) {

         TextCaret caret = textKit.getCaret();
         Point pt = caret.getMagicCaretPosition();
         if (isMovingCaret) {
             caret.moveDot(newPos, newBias);
         } else {
             caret.setDot(newPos, newBias);
         }
         //TODO in original TextAction this is after not here
         //(after getCaretMagicPosition).
         //Probably there is mistake
         caret.setMagicCaretPosition(pt);
     }


    public static final int getNextWord(final Document doc, final int pos)
        throws BadLocationException {

        BreakIterator bi = BreakIterator.getWordInstance();
        int length = doc.getLength();
        if (pos < 0 || pos >= length) {
            // awt.2F=No more words
            throwException(Messages.getString("awt.2F"), pos); //$NON-NLS-1$
        }
        String content = null;

        content = doc.getText(0, doc.getLength());
        bi.setText(content);

        int iteratorNextWord = bi.following(pos);
        while (iteratorNextWord < length
               && Character.isWhitespace(content.charAt(iteratorNextWord))) {
            iteratorNextWord = bi.following(iteratorNextWord);
        }
        if (iteratorNextWord == length) {
            // awt.2F=No more words
            throwException(Messages.getString("awt.2F"), pos); //$NON-NLS-1$
        }
        return iteratorNextWord;
    }

    public static final int getPreviousWord(final Document doc, final int pos)
        throws BadLocationException  {

        BreakIterator bi = BreakIterator.getWordInstance();
        int length = doc.getLength();
        if (pos < 0 || pos > length) {
            // awt.2F=No more words
            throwException(Messages.getString("awt.2F"), pos); //$NON-NLS-1$
        }
        String content = null;

        content = doc.getText(0, doc.getLength());
        bi.setText(content);

        int iteratorPrevWord = bi.preceding(pos);
        while (iteratorPrevWord > 0
                && ((content.charAt(iteratorPrevWord) == ' '
                    || content.charAt(iteratorPrevWord) == '\n')
                    || content.charAt(iteratorPrevWord) == '\t')) {
            iteratorPrevWord = bi.preceding(iteratorPrevWord);
        }
        return iteratorPrevWord == -1 ? 0 : iteratorPrevWord;
    }

    public static final boolean isBidirectional(final Document document) {
        if (!(document instanceof AbstractDocument)) {
            return false;
        }
        Element bidiRoot = ((AbstractDocument)document).getBidiRootElement();
        return (bidiRoot != null && bidiRoot.getElementCount() >= 2);
    }

    static final boolean isLTR(final Element element) {
        return isLTR(StyleConstants.getBidiLevel(element.getAttributes()));
    }

    public static final boolean isLTR(final int level) {
        return (level & 1) == 0;
    }

    static final boolean isRTL(final int level) {
        return (level & 1) == 1;
    }

    public static final int getTabbedTextWidth(final Segment s,
                                               final FontMetrics fm,
                                               final int x,
                                               final TabExpander t,
                                               final int pos) {
        return getTabbedTextEnd(s, fm, x, t, pos, false, null, 0) - x;
    }

    public static final int getTabbedTextOffset(final Segment s,
                                                final FontMetrics fm,
                                                final int start,
                                                final int end,
                                                final TabExpander t,
                                                final int pos) {
        return getTabbedTextOffset(s, fm, start, end, t, pos, true);
    }

    /**
     * If round equals false it needs that symbol is placed completely. If
     * round equals true it needs that more than half of the symbol is placed.
     */
    public static final int getTabbedTextOffset(final Segment s,
                                                final FontMetrics fm,
                                                final int start,
                                                final int end,
                                                final TabExpander t,
                                                final int pos,
                                                final boolean round) {
        String str = ""; //$NON-NLS-1$
        int segmentOffset = pos - s.getBeginIndex();
        boolean isTab = false;
        boolean isNullTabExpander = (t == null);
        int currentEnd = start < 0 ? 0 : start;
        int x1 = start < 0 ? start : 0;
        int currentIndex = 0;
        int prevEnd = currentEnd;
        int tabEnd = currentEnd;
        for (char c = s.first(); c != CharacterIterator.DONE; c = s.next()) {
            isTab = (c == '\t');
            if (isTab && !isNullTabExpander) {
                tabEnd = (int)t.nextTabStop(currentEnd, s.getIndex()
                        + segmentOffset);
                str = ""; //$NON-NLS-1$
            } else {
                str += (isTab) ? ' ' : c;
                isTab = false;
            }
            int tmpEnd = tabEnd + x1;
            currentEnd = isTab ?  tmpEnd: tmpEnd + fm.stringWidth(str);
            int delta = (round) ? (currentEnd - prevEnd) / 2 : 0;
            if (currentEnd > end + delta) {
                break;
            }
            currentIndex++;
            prevEnd = currentEnd;
        }
        return currentIndex;
    }

    public static final int drawTabbedText(final Segment s, final int x,
                                           final int y, final Graphics g,
            final TabExpander t, final int pos) {
        return getTabbedTextEnd(s, g.getFontMetrics(), x, t, pos, true, g, y);
    }

    public static final int drawComposedText(final TextKit textKit,
                                      final AttributedString text,
                                      final Graphics g,
                                      final int x,
                                      final int y) {
        text.addAttribute(TextAttribute.FONT, textKit.getComponent().getFont());
        final AttributedCharacterIterator iterator = text.getIterator();

        g.drawString(iterator, x, y);

        final int width = g.getFontMetrics().getStringBounds(iterator,
                iterator.getBeginIndex(), iterator.getEndIndex(),
                g).getBounds().width;
        return width + x;
    }

    public static final int getBreakLocation(final Segment s,
                                             final FontMetrics fm,
                                             final int start,
                                             final int end,
                                             final TabExpander t,
                                             final int pos) {
        int offset = s.offset;
        int index = TextUtils.getTabbedTextOffset(s, fm, start, end, t, pos,
                false);
        int fullIndex = offset +  index;

        BreakIterator bi = BreakIterator.getWordInstance();
        bi.setText(s);
        if (bi.last() <= fullIndex) {
            return bi.last() - offset;
        }
        if (bi.isBoundary(fullIndex)) {
            return Character.isWhitespace(s.array[fullIndex])
                   ? index + 1 : index;
        }
        int prev = bi.preceding(fullIndex);
        if (prev == bi.first()) {
            return index;
        }
        return prev - offset;
    }

    public static final int getRowStart(final TextKit tk, final int pos)
            throws BadLocationException {
        Dimension d = tk.getVisibleRect().getSize();
        if (d != null && (d.height == 0 || d.width == 0)) {
            return -1;
        }
        int length = tk.getDocument().getLength();
        if (pos < 0 || pos > length) {
            // awt.2A=Position not represented by view
            throwException(Messages.getString("awt.2A"), pos); //$NON-NLS-1$
        }
        int y = tk.modelToView(pos).y;
        Rectangle tmp = null;
        for (int i = pos - 1; i >= 0; i--) {
            tmp = tk.modelToView(i);
            if (tmp.y < y) {
                return i + 1;
            }
        }
        return 0;
    }
    public static final int getWordEnd(final TextKit tk, final int pos)
        throws BadLocationException {

        Document doc = tk.getDocument();
        BreakIterator bi = BreakIterator.getWordInstance();
        int length = doc.getLength();
        if (pos < 0 || pos > length) {
            // awt.2B=No word at {0}
            throwException(Messages.getString("awt.2B", pos), pos); //$NON-NLS-1$
        }
        String content = doc.getText(0, doc.getLength());
        bi.setText(content);
        return (pos < bi.last()) ? bi.following(pos) : pos;
   }

   public static final int getWordStart(final TextKit tk, final int pos)
        throws BadLocationException {
        Document doc = tk.getDocument();
        BreakIterator bi = BreakIterator.getWordInstance();
        int length = doc.getLength();
        if (pos < 0 || pos > length) {
            // awt.2B=No word at {0}
            throwException(Messages.getString("awt.2B", pos), pos); //$NON-NLS-1$
        }
        String content = null;

        content = doc.getText(0, doc.getLength());
        bi.setText(content);
        int iteratorWordStart = pos;
        if (pos < length - 1) {
            iteratorWordStart = bi.preceding(pos + 1);
        } else {
             bi.last();
             iteratorWordStart = bi.previous();
        }
        return iteratorWordStart;
   }

    /**
     * Finds row above, calculates modelToView for all the positions from this view
     * and selects the closest one.
     */
    public static final int getPositionAbove(final TextKit textKit,
                                             final int p, final int x)
            throws BadLocationException {
        int p0 = getRowStart(textKit, p);
        if (p0 <= 0) {
            return -1;
        }
        int end = p0 - 1;
        int offset = end;
        int dy = 0;
        Rectangle rect = textKit.modelToView(end);
        int lastY = rect.y;
        int dx = Math.abs(rect.x - x);
        int index = end;
        do { if (index != end) {
                rect = textKit.modelToView(index);
             }
             dy = rect.y - lastY;
             int locDiff = Math.abs(rect.x - x);
             if (locDiff <= dx && dy == 0) {
                 dx = locDiff;
                 offset = index;
             }
             index--;
             lastY = rect.y;
        } while(dx >= 1 && dy == 0 && index >= 0);
        return offset;
    }

    /**
     * Finds row below, calculates modelToView for all the positions from this view
     * and selects the closest one.
     */
    public static final int getPositionBelow(final TextKit textKit,
                                             final int p, final int x)
            throws BadLocationException {
        int p0 = getRowEnd(textKit, p);
        if (p0 == -1) {
            return -1;
        }
        int length = textKit.getDocument().getLength();
        if (p0 == length) {
            return p;
        }
        int start = p0 + 1;
        int offset = p0 + 1;
        int dy = 0;
        Rectangle rect = textKit.modelToView(start);
        int lastY = rect.y;
        int dx = Math.abs(rect.x - x);
        int index = start;
        do { rect = textKit.modelToView(index);
             dy = rect.y - lastY;
             int locDiff = Math.abs(rect.x - x);
             if (locDiff < dx && dy == 0) {
                 dx = locDiff;
                 offset = index;
             }
             index++;
             lastY = rect.y;
        } while(index <= length && dy == 0 && dx >= 1);

        return offset;
    }

    public static final TextKit getTextKit(final Component c) {
        return ComponentInternals.getComponentInternals().getTextKit(c);
    }

    public static final TextFieldKit getTextFieldKit(final Component c) {
        return ComponentInternals.getComponentInternals().getTextFieldKit(c);
    }

    public static final int getRowEnd(final TextKit tk, final int pos)
            throws BadLocationException {
        Dimension d = tk.getVisibleRect().getSize();
        if (d != null && (d.height == 0 || d.width == 0)) {
            return -1;
        }
        int length = tk.getDocument().getLength();
        if (pos < 0 || pos > length) {
            // awt.2A=Position not represented by view
            throwException(Messages.getString("awt.2A"), pos); //$NON-NLS-1$
        }

        int y = tk.modelToView(pos).y;
        Rectangle r = null;
        for (int i = pos + 1; i <= length; i++) {
            r = tk.modelToView(i);
            if (r.y > y) {
                return i - 1;
            }
        }
        return length;
    }

    //TODO Probably here is a bug:
    //Why NORTH?
    //Where bias?
    public static final void setCurrentPositionAsMagic(final TextKit textKit) {
        TextCaret caret = textKit.getCaret();
        int newPos = caret.getDot();
        try {
            Point pt = textKit.modelToView(newPos,
                                           caret.getDotBias())
                                           .getLocation();
            caret.setMagicCaretPosition(newPos, SwingConstants.NORTH, pt);
        } catch (BadLocationException e) {
        }
    }

    /**
     * If the component document is an instance of AbstractDocument then its
     * {@link AbstractDocument#getParagraphElement(int)} method is called.
     * Otherwise {@link Document#getDefaultRootElement()} is used to search
     * paragraph element.
     */
    public static final Element getParagraphElement(final Document doc,
                                                    final int p) {
        if (doc instanceof AbstractDocument) {
            AbstractDocument abstrDoc = (AbstractDocument) doc;
            abstrDoc.readLock();
            Element elem = null;
            int length = 0;
            boolean incorrectPosition = false;
            try {
                length = doc.getLength();
                incorrectPosition = (p < 0 || p > length)
                        && (doc instanceof PlainDocument);
                if (!incorrectPosition) {
                    elem = abstrDoc.getParagraphElement(p);
                }
            } finally {
                abstrDoc.readUnlock();
            }
            return elem;
        }

        Element root = doc.getDefaultRootElement();
        int index = root.getElementIndex(p);
        return index == -1 ? null : root.getElement(index);
    }

    /*
     * Returns end x-coordinate of tabbed text. Uses by drawTabbedText and
     * getTabbedTextWidth.
     */
    private static int getTabbedTextEnd(final Segment s, final FontMetrics fm,
                                        final int x, final TabExpander t,
                                        final int pos, final boolean needDraw,
                                        final Graphics g, final int y) {
        int x1 = x < 0 ? x : 0;
        int res = x < 0 ? 0 : x;
        String buffer = s.toString();
        int tabIndex = buffer.indexOf("\t"); //$NON-NLS-1$
        int currentIndex = pos - s.getBeginIndex() + s.offset;
        if (t == null) {
            String buf =  buffer.replaceAll("\t", " "); //$NON-NLS-1$ //$NON-NLS-2$
            drawString(buf, needDraw, g, x, y);
            return fm.stringWidth(buf) + x;
        }
        String substr = null;
        int lastTabIndex = -1;
        while (tabIndex >= 0) {
            substr = buffer.substring(lastTabIndex + 1, tabIndex);
            drawString(substr, needDraw, g, res + x1, y);
            res = (int)t.nextTabStop(res + fm.stringWidth(substr),
                                     tabIndex + currentIndex);
            lastTabIndex = tabIndex;
            tabIndex = buffer.indexOf("\t", tabIndex + 1); //$NON-NLS-1$
        }
        int tmp = res + x1;
        substr = buffer.substring(lastTabIndex + 1, buffer.length());
        drawString(substr, needDraw, g, tmp, y);
        return (tabIndex >= 0) ? tmp : tmp + fm.stringWidth(substr);
    }

    private static void drawString(final String text, final boolean needDraw,
                                   final Graphics g,
                                   final int x, final int y) {
        if (needDraw) {
            g.drawString(text, x, y);
        }
    }

    public static final void readLock(final Document document) {
        if (document instanceof AbstractDocument) {
            ((AbstractDocument)document).readLock();
        }
    }

    public static final void readUnlock(final Document document) {
        if (document instanceof AbstractDocument) {
            ((AbstractDocument)document).readUnlock();
        }
    }

    private static void throwException(final String s, final int i)
        throws BadLocationException {
        throw new BadLocationException(s, i);
    }

    //---NextVisualPosition---------------------------------------------
//  for a stub (getNexVisualPositionFrom)
    public static final int getNextVisualPositionFrom(
                                               final TextKit textKit,
                                               final View v, final int pos,
                                               final Position.Bias bias,
                                               final Shape shape,
                                               final int direction,
                                               final Position.Bias[] biasRet)
            throws BadLocationException {
        int length = v.getDocument().getLength();
        if (pos < 0 || pos > length) {
            // awt.2C=Invalid position: {0}
            throwException(Messages.getString("awt.2C", pos), pos); //$NON-NLS-1$
        }
        biasRet[0] = Position.Bias.Forward;
        if (direction == SwingConstants.WEST
                || direction == SwingConstants.EAST) {
            return getNextVisualPosition(v, pos, bias, direction, biasRet);
        }
        Point pt = textKit.getCaret().getMagicCaretPosition();
        if (direction == SwingConstants.NORTH) {
            return TextUtils.getPositionAbove(textKit, pos,
                                              pt != null ? pt.x
                    : v.modelToView(pos, shape, bias).getBounds().x);
        } else if (direction == SwingConstants.SOUTH) {
            return TextUtils.getPositionBelow(textKit, pos, pt != null ? pt.x
                    : v.modelToView(pos, shape, bias).getBounds().x);
        }

        // awt.2D=Invalid direction
        throw new IllegalArgumentException(Messages.getString("awt.2D")); //$NON-NLS-1$
    }


    private static Element getElementByPosition(final Element rootElement,
                                                final int pos) {
        int index = rootElement.getElementIndex(pos);
        return rootElement.getElement(index);
    }

    private static int getNextVisualPosition(final View v, final int pos,
                                             final Position.Bias b0,
            final int direction, final Position.Bias[] biasRet) {
        boolean toWest = (direction == SwingConstants.WEST);
        Document document = v.getDocument();
        int length = document.getLength();
        if (!isBidirectional(document)) {
            return getTrivialVisualPosition(toWest, pos, b0, length, biasRet,
                                            true);
        }
        Element bidiRoot = ((AbstractDocument)document).getBidiRootElement();
        Element elem = getElementByPosition(bidiRoot, pos);
        boolean isLTR = isLTR(elem);
        int start = elem.getStartOffset();
        int end = elem.getEndOffset() - 1;

        int posInNeighboringElement = toWest ? Math.max(start - 1, 0)
                                             : Math.min(end + 1, length);
        Element neighboringElement = getElementByPosition(bidiRoot,
                                                       posInNeighboringElement);

        Element paragraph = getElementByPosition(document
                                                 .getDefaultRootElement(), pos);
        int startParagraph = paragraph.getStartOffset();
        int endParagraph = paragraph.getEndOffset() - 1;

        boolean nextIsLTR = isLTR(getElementByPosition(bidiRoot,
                                                       Math.min(endParagraph
                                                                + 1,
                                                                length)));

        int result = checkBoundaryCondition(pos, b0, biasRet,
                                            neighboringElement,
                                            isLTR, toWest, start,
                                            length, startParagraph,
                                            endParagraph, nextIsLTR);

        return result >= 0 ? result
                : getBidiVisualPosition(start, end, neighboringElement, pos, b0,
                                     biasRet, length, toWest, isLTR);
    }

    private static int checkBoundaryCondition(final int pos,
                                                    final Position.Bias b0,
                                                    final Position.Bias[] biasRet,
                                                    final Element neighboringElement,
                                                    final boolean isLTR,
                                                    final boolean toWest,
                                                    final int start,
                                                    final int length,
                                                    final int startParagraph,
                                                    final int endParagraph,
                                                    final boolean nextIsLTR) {

    if (toWest && isLTR) {
        if (pos == startParagraph) {
             return Math.max(0, pos - 1);
        } else if (neighboringElement.getStartOffset() == startParagraph
            && pos == start  && b0 == backward) {
             return Math.max(0, startParagraph - 1);
        }
    } else if (!toWest) {
        if (b0 == forward && pos == length) {
            biasRet[0] = b0;
            return pos;
        }
        if (b0 == forward && pos == endParagraph) {
                if (nextIsLTR) {
                    return pos + 1;
                }
                biasRet[0] = backward;
                return neighboringElement.getEndOffset();
            }
        }
        return -1;
    }

    static final int getBidiVisualPosition(final int start,
                                           final int end,
                                           final Element neighbouringElement,
                                           final int pos,
                                           final Position.Bias b0,
                                           final Position.Bias[] biasRet,
                                           final int length,
                                           final boolean toWest,
                                           final boolean isLTR) {
        boolean direction = toWest ^ isLTR;
        if (pos == end && direction && b0 == forward) {
            biasRet[0] = backward;
            return pos + 1;
        } else if (pos == start + 1 && pos <= end && !direction) {
            return pos - 1;
        } else if (pos == start) {
            if (direction) {
                return (b0 == forward) ? pos + 1 : pos - 1;
            }
            biasRet[0] = b0;
            return neighbouringElement.getStartOffset();
        } else {
            return getTrivialVisualPosition(toWest, pos, b0, length, biasRet, isLTR);
        }
    }

    private static int getTrivialVisualPosition(final boolean toWest,
                                                final int pos,
                                                final Position.Bias bias,
                                                final int docLength,
                                                final Position.Bias[] biasRet,
                                                final boolean isLTR) {
        boolean condition = (toWest && isLTR) || (!toWest && !isLTR);
        return condition ? Math.max(pos - 1, 0) : Math.min(pos + 1, docLength);
    }

    //-------TextField Methods
    public static final Shape getFieldViewAllocation(final View v,
                                              final TextFieldKit tfk,
                                              final Shape shape,
                                              final ComponentOrientation
                                              orientation) {
        if (tfk == null || shape == null) {
            return null;
        }

        Rectangle bounds = shape.getBounds();
        int prefWidth = (int)v.getPreferredSpan(View.X_AXIS);
        int height = (int)v.getPreferredSpan(View.Y_AXIS);
        int diff = bounds.width - prefWidth;
        int alignment = tfk.getHorizontalAlignment();
        boolean toLeft = isToLeft(orientation, alignment);
        int offset = 0;
        if (alignment == SwingConstants.CENTER) {
            offset = diff / 2;
        } else {
            offset = toLeft ? 0 : diff;
        }
        int extent = bounds.width - 1;
        int max = Math.max(extent, prefWidth);
        BoundedRangeModel brm = tfk.getHorizontalVisibility();
        int value = Math.min(brm.getValue(), max - extent);
        brm.setRangeProperties(value, extent, brm.getMinimum(), max, false);

        int x = (diff < 0 ? -value + tfk.getInsets().left : bounds.x + offset);
        int y = (bounds.height - height) / 2 + bounds.y;
        if (!toLeft) {
            x--;
        }
        return new Rectangle(x, y, prefWidth + 1, height);
    }

    private static boolean isToLeft(final ComponentOrientation orientation,
                                    final int alignment) {
        boolean isRTL = !orientation.isLeftToRight();
        return isRTL && alignment == SwingConstants.TRAILING
               || !isRTL && alignment == SwingConstants.LEADING
               || alignment == SwingConstants.LEFT;
    }

    //-------Highlight painting

    public static Shape paintLayer(final Graphics g, final int p0, final int p1,
                            final Shape shape, final Color color,
                            final View view, final boolean fill) {
        if (shape == null) {
            return null;
        }
        Shape result = null;
        try {
            result = view.modelToView(Math.min(p0, p1),
                                                   Position.Bias.Forward,
                                                   Math.max(p0, p1),
                                                   Position.Bias.Backward,
                                                   shape);
            Rectangle bounds = result.getBounds();
            g.setColor(color);
            if (fill) {
                g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
            } else {
                g.drawRect(bounds.x, bounds.y, bounds.width - 1, bounds.height - 1);
            }
        } catch (final BadLocationException e) {
        }
        return result;
    }

    //------IM support
    public static ComposedTextParams getComposedTextParams(final TextKit tk) {
        Document doc = tk.getDocument();
        Object currentProperty = tk.getDocument()
           .getProperty(PropertyNames.COMPOSED_TEXT_PROPERTY);
        if (!(currentProperty instanceof ComposedTextParams)) {
           ComposedTextParams result = new ComposedTextParams(doc);
           int caretPosition = tk.getCaret().getDot();
           result.setComposedTextStart(caretPosition);
           result.setLastCommittedTextStart(caretPosition);
           return result;
        }
        return (ComposedTextParams)currentProperty;
    }
    public static void processIMEvent(final InputMethodListener listener,
                                 final InputMethodEvent e) {
        if (e.getID() == InputMethodEvent.CARET_POSITION_CHANGED) {
            listener.caretPositionChanged(e);
        }
        if (e.getID() == InputMethodEvent.INPUT_METHOD_TEXT_CHANGED) {
            listener.inputMethodTextChanged(e);
        }
    }

    //----highlighter
    public static final Rectangle getBoundsByOffsets(final TextKit tk,
                                         final int p0, final int p1) {
        Rectangle r0 = null;
        Rectangle r1 = null;
        Rectangle rect = new Rectangle();
        if (tk == null) {
            return null;
        }
        try {
            r0 = tk.modelToView(p0, Position.Bias.Forward);
            r1 = tk.modelToView(p1, Position.Bias.Forward);
        } catch (final BadLocationException e) {
        }
        if (r0 == null || r1 == null) {
            return null;
        }
        if (r0.y == r1.y) {
            rect.x = Math.min(r0.x, r1.x);
            rect.y = r0.y;
            rect.width = Math.max(r0.x, r1.x) - rect.x + 1;
            rect.height = Math.max(r0.height, r1.height);
            return rect;
        }
        Rectangle visibleRect = tk.getVisibleRect();
        rect.x = visibleRect.x;
        rect.y = Math.min(r0.y, r1.y);
        rect.width = visibleRect.width;
        rect.height = Math.max(r0.y, r1.y) - rect.y
                      + Math.max(r0.height, r1.height);
        return rect;
    }

    public static final void setNativeCaretPosition(final Rectangle rect,
                                                    final Component comp) {
        ComponentInternals.getComponentInternals()
             .setCaretPos(comp, rect.x, rect.y);
    }

    //-----clipboard operations (Perhaps, that's temporary solution.
    public static final void copy(final TextKit textKit) {
        exportToClipboard(textKit, getSystemClipboard(), ActionNames.COPY);
    }

    public static final void cut(final TextKit textKit) {
        exportToClipboard(textKit, getSystemClipboard(), ActionNames.MOVE);
    }

    public static final void paste(final TextKit textKit) {
        TextUtils.importData(textKit, getSystemClipboard().getContents(null));
    }

    public static final void exportToClipboard(final TextKit textKit,
                                               final Clipboard clipboard,
                                               final int action) {
        if (textKit == null) {
            return;
        }
        int realAction = (action & (getSourceActions(textKit)));
        Transferable transferable = TextUtils.createTransferable(textKit);
        if (realAction > 0 && transferable != null) {
            clipboard.setContents(transferable, null);
        }
        exportDone(textKit, transferable, realAction);
    }

    public static final Transferable createTransferable(final TextKit textKit) {
        String text = textKit.getSelectedText();
        return text != null ? new StringSelection(text) : null;
    }

    public static final void exportDone(final TextKit textKit,
                                        final Transferable transferable,
                                        final int action) {
       if (textKit != null  && (action & ActionNames.MOVE) > 0) {
           textKit.replaceSelectedText(""); //$NON-NLS-1$
       }
    }

    public static final boolean importData(final TextKit textKit,
                                        final Transferable t) {

        if (t == null) {
            return false;
        }
        DataFlavor[] flavors = t.getTransferDataFlavors();
        DataFlavor flavor = null;
        for (DataFlavor element : flavors) {
            flavor = element;
            if (String.class.isAssignableFrom(flavor.getRepresentationClass())) {
                break;
            }
            flavor = null;
        }
        if (flavor != null) {
            try {
                String text = (String) t.getTransferData(flavor);
                textKit.replaceSelectedText(text);
                return true;
            } catch (UnsupportedFlavorException e) {
                return false;
            } catch (IOException e) {
                return false;
            }
        }
        return false;
    }

    public static final Clipboard getSystemClipboard() {
        return Toolkit.getDefaultToolkit().getSystemClipboard();
    }

    public static int getSourceActions(final TextKit textKit) {
        if (textKit != null
            && !"javax.swing.JPasswordField".equals(textKit.getClass())) { //$NON-NLS-1$
            return (textKit.isEditable()) ? ActionNames.COPY_OR_MOVE
                    : ActionNames.COPY;

        }
        return ActionNames.NONE;
    }

    public static Rectangle scrollRectToVisible(Rectangle viewRect, Rectangle r) {
        Rectangle retVal = (Rectangle)viewRect.clone();
        retVal.x = - retVal.x;
        retVal.y = - retVal.y;

        int dx;
        int dy;

        if (r.x > 0) {
            if (r.x + r.width > viewRect.width) {
                int dx2 = r.x + r.width - viewRect.width;
                dx = Math.min(r.x, dx2);
            } else {
                dx = 0;
            }
        } else if (r.x < 0) {
            if (r.x + r.width < viewRect.width) {
                int dx2 = r.x + r.width - viewRect.width;
                dx = Math.max(r.x, dx2);
            } else {
                dx = 0;
            }
        } else {
            dx = 0;
        }

        if (r.y > 0) {
            if (r.y + r.height > viewRect.height) {
                int dy2 = r.y + r.height - viewRect.height;
                dy = Math.min(r.y, dy2);
            } else {
                dy = 0;
            }
        } else if (r.y < 0) {
            if (r.y + r.height < viewRect.height) {
                int dy2 = r.y + r.height - viewRect.height;
                dy = Math.max(r.y, dy2);
            } else {
                dy = 0;
            }
        } else {
            dy = 0;
        }

        if (dx != 0 || dy != 0) {
            int x = retVal.x + dx;
            int y = retVal.y + dy;

            retVal.x = x;
            retVal.y = y;
        }

        return retVal;
    }

    public static Rectangle getEditorRect(final JComponent component) {
        if (component == null) {
            return null;
        }
        Insets insets = component.getInsets();
        int left = 0;
        int top = 0;
        if (insets != null) {
            left = insets.left;
            top = insets.top;
        }
        Dimension r = component.getSize();
        return r.width == 0 || r.height == 0 ? null
               : new Rectangle(left, top, r.width - getHrzInsets(insets),
                               r.height - getVrtInsets(insets));
    }

    public static int getHrzInsets(final Insets insets) {
        return (insets != null) ? insets.left + insets.right : 0;
    }

    public static int getVrtInsets(final Insets insets) {
        return (insets != null) ? insets.top + insets.bottom : 0;
    }

    public static void setCharacterAttributes(final AttributeSet attr,
                                              final boolean replace,
                                              final JEditorPane editorPane,
                                              final StyledDocument doc,
                                              final MutableAttributeSet
                                                  inputAttrs) {

        final int selectionStart = editorPane.getSelectionStart();
        final int selectionEnd = editorPane.getSelectionEnd();
        doc.setCharacterAttributes(selectionStart,
                                   selectionEnd - selectionStart,
                                   attr, replace);
        if (selectionStart == selectionEnd) {
            if (replace) {
                inputAttrs.removeAttributes(inputAttrs.getAttributeNames());
            }
            inputAttrs.addAttributes(attr);
        }
    }

    public static void setParagraphAttributes(final AttributeSet attr,
                                              final boolean replace,
                                              final JEditorPane editorPane,
                                              final StyledDocument doc) {
        final int selectStart = editorPane.getSelectionStart();
        int intervalLength = Math.max (editorPane.getSelectionEnd()
                                       - selectStart, 1);
        doc.setParagraphAttributes(selectStart, intervalLength, attr, replace);
    }

    public static int getCalendarField(final JFormattedTextField textField) {
        DateFormatter formatter = (DateFormatter)textField.getFormatter();
        Field[] fields = formatter.getFields(textField.getCaretPosition());

        for (int i = textField.getCaretPosition(); fields.length == 0 || i < 0; i--) {
            fields = formatter.getFields(i);
        }
        if (fields.length == 0) {
            int length = textField.getText().length();
            for (int i = textField.getCaretPosition(); fields.length == 0 || i > length; i++) {
                fields = formatter.getFields(i);
            }
        }
        return ((DateFormat.Field)fields[0]).getCalendarField();
    }

    public static void selectCalendarField(final JFormattedTextField textField,
                                           final int calendarField) {
        boolean selecting = false;
        int length = textField.getText().length();
        for (int i = 0; i <= length; i++) {
            if (!selecting) {
                textField.setCaretPosition(i);
            } else {
                textField.moveCaretPosition(i);
            }
            if(getCalendarField(textField) == calendarField) {
                selecting = true;
            } else {
                if (selecting) {
                    textField.moveCaretPosition(i - 1);
                    return;
                }
            }
        }
    }

    public static Object getNextValue(final Date value,
                                      final int calendarField,
                                      final Comparable<Date> end) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(value);
        calendar.add(calendarField, 1);
        Date result = calendar.getTime();
        return (end == null)? result
                : (end.compareTo(result) < 0) ? null : result;
    }

    public static Object getPreviousValue(final Date value,
                                          final int calendarField,
                                          final Comparable<Date> start) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(value);
        calendar.add(calendarField, -1);
        Date result = calendar.getTime();
        return (start == null)? result
                : (start.compareTo(result) > 0) ? null : result;
    }


    /**
     * Transforms position at the document model coordinate space to the
     * coordinate space of the corresponding icon or component view.
     */
    public static Shape modelToIconOrComponentView(final View view, final int pos,
                                    final Shape shape, final Bias bias)
        throws BadLocationException {

        TextUtils.isPositionValid(view, pos);

        final Rectangle bounds = shape.getBounds();
        final int x = (pos == view.getStartOffset() ? bounds.x
                                                    : bounds.x + bounds.width);

        return new Rectangle(x, bounds.y, 0, bounds.height);
    }

    /**
     * Throws BadLocationException if the position does not represent a
     * valid location in the associated document element.
     */
    public static void isPositionValid(final View view, final int pos)
        throws BadLocationException {

        if (pos < view.getStartOffset() || pos > view.getEndOffset()) {
            // awt.2E={0} not in range {1},{2}
            throw new BadLocationException(Messages.getString("awt.2E", //$NON-NLS-1$
                    new Object[] { pos, view.getStartOffset(),
                            view.getEndOffset() }), pos);
        }
    }
}
TOP

Related Classes of org.apache.harmony.awt.text.TextUtils

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.