/* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing.text; import java.lang.reflect.Method; import java.awt.Component;import java.awt.Rectangle;import java.awt.Graphics;import java.awt.FontMetrics;import java.awt.Shape;import java.awt.Toolkit;import java.awt.Graphics2D;import java.awt.font.FontRenderContext;import java.awt.font.TextLayout;import java.awt.font.TextAttribute; import java.text.*;import javax.swing.JComponent;import javax.swing.SwingConstants;import javax.swing.text.ParagraphView.Row;import sun.swing.SwingUtilities2; /** * A collection of methods to deal with various text * related activities. * * @author Timothy Prinzing */public class Utilities { /** * If <code>view</code>'s container is a <code>JComponent</code> it * is returned, after casting. */ static JComponent getJComponent(View view) { if (view != null) { Component component = view.getContainer(); if (component instanceof JComponent) { return (JComponent)component; } } return null; } /** * Draws the given text, expanding any tabs that are contained * using the given tab expansion technique. This particular * implementation renders in a 1.1 style coordinate system * where ints are used and 72dpi is assumed. * * @param s the source of the text * @param x the X origin >= 0 * @param y the Y origin >= 0 * @param g the graphics context * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the X location at the end of the rendered text */ public static final int drawTabbedText(Segment s, int x, int y, Graphics g, TabExpander e, int startOffset) { return drawTabbedText(null, s, x, y, g, e, startOffset); } /** * Draws the given text, expanding any tabs that are contained * using the given tab expansion technique. This particular * implementation renders in a 1.1 style coordinate system * where ints are used and 72dpi is assumed. * * @param view View requesting rendering, may be null. * @param s the source of the text * @param x the X origin >= 0 * @param y the Y origin >= 0 * @param g the graphics context * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the X location at the end of the rendered text */ static final int drawTabbedText(View view, Segment s, int x, int y, Graphics g, TabExpander e, int startOffset) { return drawTabbedText(view, s, x, y, g, e, startOffset, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int drawTabbedText(View view, Segment s, int x, int y, Graphics g, TabExpander e, int startOffset, int [] justificationData) { JComponent component = getJComponent(view); FontMetrics metrics = SwingUtilities2.getFontMetrics(component, g); int nextX = x; char[] txt = s.array; int txtOffset = s.offset; int flushLen = 0; int flushIndex = s.offset; int spaceAddon = 0; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } int n = s.offset + s.count; for (int i = txtOffset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )) { if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g, txt, flushIndex, flushLen, x, y); flushLen = 0; } flushIndex = i + 1; if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } x = nextX; } else if ((txt[i] == '\n') || (txt[i] == '\r')) { if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g, txt, flushIndex, flushLen, x, y); flushLen = 0; } flushIndex = i + 1; x = nextX; } else { flushLen += 1; } } if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g,txt, flushIndex, flushLen, x, y); } return nextX; } /** * Determines the width of the given segment of text taking tabs * into consideration. This is implemented in a 1.1 style coordinate * system where ints are used and 72dpi is assumed. * * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x the X origin >= 0 * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the width of the text */ public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, int x, TabExpander e, int startOffset) { return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int getTabbedTextWidth(View view, Segment s, FontMetrics metrics, int x, TabExpander e, int startOffset, int[] justificationData) { int nextX = x; char[] txt = s.array; int txtOffset = s.offset; int n = s.offset + s.count; int charCount = 0; int spaceAddon = 0; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } for (int i = txtOffset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )) { nextX += metrics.charsWidth(txt, i-charCount, charCount); charCount = 0; if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } } else if(txt[i] == '\n') { // Ignore newlines, they take up space and we shouldn't be // counting them. nextX += metrics.charsWidth(txt, i - charCount, charCount); charCount = 0; } else { charCount++; } } nextX += metrics.charsWidth(txt, n - charCount, charCount); return nextX - x; } /** * Determines the relative offset into the given text that * best represents the given span in the view coordinate * system. This is implemented in a 1.1 style coordinate * system where ints are used and 72dpi is assumed. * * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x0 the starting view location representing the start * of the given text >= 0. * @param x the target view location to translate to an * offset into the text >= 0. * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the offset into the text >= 0 */ public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { return getTabbedTextOffset(s, metrics, x0, x, e, startOffset, true); } static final int getTabbedTextOffset(View view, Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, int[] justificationData) { return getTabbedTextOffset(view, s, metrics, x0, x, e, startOffset, true, justificationData); } public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, boolean round) { return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, round, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int getTabbedTextOffset(View view, Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, boolean round, int[] justificationData) { if (x0 >= x) { // x before x0, return. return 0; } int nextX = x0; // s may be a shared segment, so it is copied prior to calling // the tab expander char[] txt = s.array; int txtOffset = s.offset; int txtCount = s.count; int spaceAddon = 0 ; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0 ; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } int n = s.offset + s.count; for (int i = s.offset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )){ if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } } else { nextX += metrics.charWidth(txt[i]); } if (x < nextX) { // found the hit position... return the appropriate side int offset; // the length of the string measured as a whole may differ from // the sum of individual character lengths, for example if // fractional metrics are enabled; and we must guard from this. if (round) { offset = i + 1 - txtOffset; int width = metrics.charsWidth(txt, txtOffset, offset); int span = x - x0; if (span < width) { while (offset > 0) { int nextWidth = offset > 1 ? metrics.charsWidth(txt, txtOffset, offset - 1) : 0; if (span >= nextWidth) { if (span - nextWidth < width - span) { offset--; } break; } width = nextWidth; offset--; } } } else { offset = i - txtOffset; while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) { offset--; } } return offset; } } // didn't find, return end offset return txtCount; } /** * Determine where to break the given text to fit * within the given span. This tries to find a word boundary. * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x0 the starting view location representing the start * of the given text. * @param x the target view location to translate to an * offset into the text. * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset in the document of the text * @return the offset into the given text */ public static final int getBreakLocation(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { char[] txt = s.array; int txtOffset = s.offset; int txtCount = s.count; int index = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset, false); if (index >= txtCount - 1) { return txtCount; } for (int i = txtOffset + index; i >= txtOffset; i--) { char ch = txt[i]; if (ch < 256) { // break on whitespace if (Character.isWhitespace(ch)) { index = i - txtOffset + 1; break; } } else { // a multibyte char found; use BreakIterator to find line break BreakIterator bit = BreakIterator.getLineInstance(); bit.setText(s); int breakPos = bit.preceding(i + 1); if (breakPos > txtOffset) { index = breakPos - txtOffset; } break; } } return index; } /** * Determines the starting row model position of the row that contains * the specified model position. The component given must have a * size to compute the result. If the component doesn't have a size * a value of -1 will be returned. * * @param c the editor * @param offs the offset in the document >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range */ public static final int getRowStart(JTextComponent c, int offs) throws BadLocationException { Rectangle r = c.modelToView(offs); if (r == null) { return -1; }Lines 1–500 of 1078. Load more
/* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing.text; import java.lang.reflect.Method; import java.awt.Component; import java.awt.Rectangle; import java.awt.Graphics; import java.awt.FontMetrics; import java.awt.Shape; import java.awt.Toolkit; import java.awt.Graphics2D; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.font.TextAttribute; import java.text.*; import javax.swing.JComponent; import javax.swing.SwingConstants; import javax.swing.text.ParagraphView.Row; import sun.swing.SwingUtilities2; /** * A collection of methods to deal with various text * related activities. * * @author Timothy Prinzing */ public class Utilities { /** * If <code>view</code>'s container is a <code>JComponent</code> it * is returned, after casting. */ static JComponent getJComponent(View view) { if (view != null) { Component component = view.getContainer(); if (component instanceof JComponent) { return (JComponent)component; } } return null; } /** * Draws the given text, expanding any tabs that are contained * using the given tab expansion technique. This particular * implementation renders in a 1.1 style coordinate system * where ints are used and 72dpi is assumed. * * @param s the source of the text * @param x the X origin >= 0 * @param y the Y origin >= 0 * @param g the graphics context * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the X location at the end of the rendered text */ public static final int drawTabbedText(Segment s, int x, int y, Graphics g, TabExpander e, int startOffset) { return drawTabbedText(null, s, x, y, g, e, startOffset); } /** * Draws the given text, expanding any tabs that are contained * using the given tab expansion technique. This particular * implementation renders in a 1.1 style coordinate system * where ints are used and 72dpi is assumed. * * @param view View requesting rendering, may be null. * @param s the source of the text * @param x the X origin >= 0 * @param y the Y origin >= 0 * @param g the graphics context * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the X location at the end of the rendered text */ static final int drawTabbedText(View view, Segment s, int x, int y, Graphics g, TabExpander e, int startOffset) { return drawTabbedText(view, s, x, y, g, e, startOffset, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int drawTabbedText(View view, Segment s, int x, int y, Graphics g, TabExpander e, int startOffset, int [] justificationData) { JComponent component = getJComponent(view); FontMetrics metrics = SwingUtilities2.getFontMetrics(component, g); int nextX = x; char[] txt = s.array; int txtOffset = s.offset; int flushLen = 0; int flushIndex = s.offset; int spaceAddon = 0; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } int n = s.offset + s.count; for (int i = txtOffset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )) { if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g, txt, flushIndex, flushLen, x, y); flushLen = 0; } flushIndex = i + 1; if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } x = nextX; } else if ((txt[i] == '\n') || (txt[i] == '\r')) { if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g, txt, flushIndex, flushLen, x, y); flushLen = 0; } flushIndex = i + 1; x = nextX; } else { flushLen += 1; } } if (flushLen > 0) { nextX = SwingUtilities2.drawChars(component, g,txt, flushIndex, flushLen, x, y); } return nextX; } /** * Determines the width of the given segment of text taking tabs * into consideration. This is implemented in a 1.1 style coordinate * system where ints are used and 72dpi is assumed. * * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x the X origin >= 0 * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the width of the text */ public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, int x, TabExpander e, int startOffset) { return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int getTabbedTextWidth(View view, Segment s, FontMetrics metrics, int x, TabExpander e, int startOffset, int[] justificationData) { int nextX = x; char[] txt = s.array; int txtOffset = s.offset; int n = s.offset + s.count; int charCount = 0; int spaceAddon = 0; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } for (int i = txtOffset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )) { nextX += metrics.charsWidth(txt, i-charCount, charCount); charCount = 0; if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } } else if(txt[i] == '\n') { // Ignore newlines, they take up space and we shouldn't be // counting them. nextX += metrics.charsWidth(txt, i - charCount, charCount); charCount = 0; } else { charCount++; } } nextX += metrics.charsWidth(txt, n - charCount, charCount); return nextX - x; } /** * Determines the relative offset into the given text that * best represents the given span in the view coordinate * system. This is implemented in a 1.1 style coordinate * system where ints are used and 72dpi is assumed. * * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x0 the starting view location representing the start * of the given text >= 0. * @param x the target view location to translate to an * offset into the text >= 0. * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset of the text in the document >= 0 * @return the offset into the text >= 0 */ public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { return getTabbedTextOffset(s, metrics, x0, x, e, startOffset, true); } static final int getTabbedTextOffset(View view, Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, int[] justificationData) { return getTabbedTextOffset(view, s, metrics, x0, x, e, startOffset, true, justificationData); } public static final int getTabbedTextOffset(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, boolean round) { return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, round, null); } // In addition to the previous method it can extend spaces for // justification. // // all params are the same as in the preious method except the last // one: // @param justificationData justificationData for the row. // if null not justification is needed static final int getTabbedTextOffset(View view, Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset, boolean round, int[] justificationData) { if (x0 >= x) { // x before x0, return. return 0; } int nextX = x0; // s may be a shared segment, so it is copied prior to calling // the tab expander char[] txt = s.array; int txtOffset = s.offset; int txtCount = s.count; int spaceAddon = 0 ; int spaceAddonLeftoverEnd = -1; int startJustifiableContent = 0 ; int endJustifiableContent = 0; if (justificationData != null) { int offset = - startOffset + txtOffset; View parent = null; if (view != null && (parent = view.getParent()) != null) { offset += parent.getStartOffset(); } spaceAddon = justificationData[Row.SPACE_ADDON]; spaceAddonLeftoverEnd = justificationData[Row.SPACE_ADDON_LEFTOVER_END] + offset; startJustifiableContent = justificationData[Row.START_JUSTIFIABLE] + offset; endJustifiableContent = justificationData[Row.END_JUSTIFIABLE] + offset; } int n = s.offset + s.count; for (int i = s.offset; i < n; i++) { if (txt[i] == '\t' || ((spaceAddon != 0 || i <= spaceAddonLeftoverEnd) && (txt[i] == ' ') && startJustifiableContent <= i && i <= endJustifiableContent )){ if (txt[i] == '\t') { if (e != null) { nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset); } else { nextX += metrics.charWidth(' '); } } else if (txt[i] == ' ') { nextX += metrics.charWidth(' ') + spaceAddon; if (i <= spaceAddonLeftoverEnd) { nextX++; } } } else { nextX += metrics.charWidth(txt[i]); } if (x < nextX) { // found the hit position... return the appropriate side int offset; // the length of the string measured as a whole may differ from // the sum of individual character lengths, for example if // fractional metrics are enabled; and we must guard from this. if (round) { offset = i + 1 - txtOffset; int width = metrics.charsWidth(txt, txtOffset, offset); int span = x - x0; if (span < width) { while (offset > 0) { int nextWidth = offset > 1 ? metrics.charsWidth(txt, txtOffset, offset - 1) : 0; if (span >= nextWidth) { if (span - nextWidth < width - span) { offset--; } break; } width = nextWidth; offset--; } } } else { offset = i - txtOffset; while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) { offset--; } } return offset; } } // didn't find, return end offset return txtCount; } /** * Determine where to break the given text to fit * within the given span. This tries to find a word boundary. * @param s the source of the text * @param metrics the font metrics to use for the calculation * @param x0 the starting view location representing the start * of the given text. * @param x the target view location to translate to an * offset into the text. * @param e how to expand the tabs. If this value is null, * tabs will be expanded as a space character. * @param startOffset starting offset in the document of the text * @return the offset into the given text */ public static final int getBreakLocation(Segment s, FontMetrics metrics, int x0, int x, TabExpander e, int startOffset) { char[] txt = s.array; int txtOffset = s.offset; int txtCount = s.count; int index = Utilities.getTabbedTextOffset(s, metrics, x0, x, e, startOffset, false); if (index >= txtCount - 1) { return txtCount; } for (int i = txtOffset + index; i >= txtOffset; i--) { char ch = txt[i]; if (ch < 256) { // break on whitespace if (Character.isWhitespace(ch)) { index = i - txtOffset + 1; break; } } else { // a multibyte char found; use BreakIterator to find line break BreakIterator bit = BreakIterator.getLineInstance(); bit.setText(s); int breakPos = bit.preceding(i + 1); if (breakPos > txtOffset) { index = breakPos - txtOffset; } break; } } return index; } /** * Determines the starting row model position of the row that contains * the specified model position. The component given must have a * size to compute the result. If the component doesn't have a size * a value of -1 will be returned. * * @param c the editor * @param offs the offset in the document >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. * @exception BadLocationException if the offset is out of range */ public static final int getRowStart(JTextComponent c, int offs) throws BadLocationException { Rectangle r = c.modelToView(offs); if (r == null) { return -1; }