0001: package ob.text;
0002:
0003: /*
0004: * Stingray Software Objective Blend
0005: * Copyright (C) 1997 Stingray Software, Inc.
0006: * All Rights Reserved
0007: *
0008: * This source code is only intended as a supplement to
0009: * the Stingray Objective Blend product. See the Objective
0010: * Blend html help documentation for detailed information regarding
0011: * using OB classes.
0012: *
0013: * Author : Jason W. Purdy
0014: * Description : Paragraph.java - implements the Text classes' data
0015: *
0016: */
0017:
0018: /**
0019: Paragraph
0020:
0021: implements a data control for the text classes to store state information
0022: such as text, cursor positions, and selection states. It is also responsible
0023: for rendering itself given a Graphics object and x,y coordinates.
0024:
0025: This class should never be directly instantiated, but left to the text classes
0026: to handle and work with.
0027: */
0028:
0029: import java.awt.*;
0030: import com.sun.portal.log.common.PortalLogger;
0031: import java.awt.event.*;
0032: import java.util.*;
0033: import java.io.*;
0034:
0035: public class Paragraph extends Object implements Serializable {
0036: public final static int LEFT = OBLabel.LEFT;
0037: public final static int CENTER = OBLabel.CENTER;
0038: public final static int RIGHT = OBLabel.RIGHT;
0039:
0040: protected final static int NONE = 0;
0041: protected final static int PARTIAL = 1;
0042: protected final static int COMPLETE = 2;
0043:
0044: // Scrolling variables
0045: private int x_offset = 0;
0046: private int prevXOffset = 0;
0047:
0048: private boolean m_bAllowScroll = false;
0049: private boolean m_bAutoWrap = false;
0050:
0051: StringBuffer buffer;
0052: Vector lines;
0053: FontMetrics fontMetrics;
0054: Font m_fFont;
0055: Color m_cHighlight = SystemColor.textHighlight;
0056: Color m_cTextHighlight = SystemColor.textHighlightText;
0057: Color m_cBackground = Color.white;
0058: Color m_cForeground = Color.black;
0059: Insets m_inInsets;
0060:
0061: boolean m_bVisible;
0062: boolean m_bMarkVisible = true;
0063:
0064: int cursorPos, currentLine;
0065: int m_nYSpan, m_nFirstLine;
0066: int m_nHAlign = LEFT;
0067: int leftOffset = 10;
0068: int m_nWidth = 0;
0069: int selectionStart, selectionEnd;
0070: int selected = NONE;
0071:
0072: //OBLabel target;
0073: IScrollable target;
0074:
0075: /**
0076: * Null constructor that just forwards to the constructor w/ the String argument
0077: */
0078: public Paragraph() {
0079: this ("");
0080: }
0081:
0082: /**
0083: * Constructor that sets up the preliminary data.
0084: * @param s - initial text of the Paragraph
0085: */
0086: public Paragraph(String s) {
0087: cursorPos = 0;
0088: currentLine = 0;
0089: m_nFirstLine = 0;
0090: m_bVisible = true;
0091: m_fFont = null;
0092: lines = new Vector();
0093: buffer = new StringBuffer(s);
0094: lines.addElement(buffer.toString());
0095: m_inInsets = new Insets(3, 3, 3, 3);
0096: }
0097:
0098: /**
0099: * Constructor that takes the text control as an argument.
0100: * @param text control that interfaces IScrollable
0101: */
0102: public Paragraph(IScrollable target) {
0103: this (target, "");
0104: }
0105:
0106: /**
0107: * This constructor takes the text control as well as the initial
0108: * string.
0109: * @param target - text control that interfaces w/ IScrollable
0110: * @param s - initial string
0111: */
0112: public Paragraph(IScrollable target, String s) {
0113: this (s);
0114: this .target = target;
0115: }
0116:
0117: /**
0118: * This is overridden to call onTextModified
0119: */
0120: public void addNotify() {
0121: onTextModified();
0122: }
0123:
0124: /**
0125: * This returns the color of the background
0126: * @return background color
0127: */
0128: public Color getBackground() {
0129: return m_cBackground;
0130: }
0131:
0132: /**
0133: * This returns the cursor's x/y location in Point format.
0134: * @return cursor's location
0135: */
0136: protected Point getCursorPoint() {
0137: Point p = new Point(0, 0);
0138: int base = 0;
0139: for (int i = 0; i < lines.size(); i++) {
0140: String s = (String) lines.elementAt(i);
0141: int upper = s.length();
0142: if (upper > 0 && i < (lines.size() - 1)
0143: && s.charAt(upper - 1) == ' ')
0144: upper--;
0145: upper += base;
0146: if (cursorPos >= base && cursorPos <= upper) {
0147: String str = s.substring(0, (cursorPos - base));
0148: p.x = fontMetrics.stringWidth(str) + m_inInsets.left;
0149: if (x_offset <= 0 && m_nHAlign != LEFT) {
0150: if (m_nHAlign == CENTER) {
0151: p.x = ((m_nWidth / 2) - (fontMetrics
0152: .stringWidth(s) / 2))
0153: + fontMetrics.stringWidth(str) - 4;
0154: } else if (m_nHAlign == RIGHT) {
0155: if (fontMetrics.stringWidth(str) > m_nWidth)
0156: p.x = m_inInsets.left
0157: + fontMetrics.stringWidth(str) + 2;
0158: else
0159: p.x = m_nWidth - 2 - m_inInsets.right
0160: - fontMetrics.stringWidth(s)
0161: + fontMetrics.stringWidth(str);
0162: }
0163: }
0164: p.x -= x_offset;
0165: break;
0166: } else {
0167: base += s.length();
0168: p.y += fontMetrics.getHeight();
0169: }
0170: }
0171: return p;
0172: }
0173:
0174: /**
0175: * This returns the cursor's position
0176: * @return cursor's position
0177: */
0178: protected int getCursorPos() {
0179: return cursorPos;
0180: }
0181:
0182: /**
0183: * This returns the cursor's position from a Point.
0184: * @param p - Point (x, y coordinates)
0185: * @return cursor's position at that Point
0186: */
0187: public int getCursorPosFromPoint(Point p) {
0188: if (p.y > getYSpan())
0189: return buffer.length();
0190: int line = -1;
0191: int base = 0;
0192: for (int i = 0; i < lines.size(); i++) {
0193: if (((i + 1) * fontMetrics.getHeight()) > p.y) {
0194: line = i;
0195: break;
0196: }
0197: base += ((String) lines.elementAt(i)).length();
0198: }
0199: if (line == -1)
0200: line = (lines.size() - 1);
0201: String s = (String) lines.elementAt(line);
0202: return (base + getPositionAt(s, p.x));
0203: }
0204:
0205: /**
0206: * This returns the first line of the Paragraph shown
0207: * @return the index of the first line shown
0208: */
0209: protected int getFirstLine() {
0210: return m_nFirstLine;
0211: }
0212:
0213: /**
0214: * This returns the font of the Paragraph.
0215: * @return the font of the Paragraph
0216: */
0217: public Font getFont() {
0218: return m_fFont;
0219: }
0220:
0221: /**
0222: * This returns the FontMetrics of the Paragraph.
0223: * @return FontMetrics of the Paragraph
0224: */
0225: public FontMetrics getFontMetrics() {
0226: return fontMetrics;
0227: }
0228:
0229: /**
0230: * This returns the foreground of the Paragraph.
0231: * @return foreground color
0232: */
0233: public Color getForeground() {
0234: return m_cForeground;
0235: }
0236:
0237: /**
0238: * This returns the color of the highlight.
0239: * @return highlight color
0240: */
0241: protected Color getHighlight() {
0242: return m_cHighlight;
0243: }
0244:
0245: /**
0246: * This returns the color of the highlighted text.
0247: * @return highlighted text color
0248: */
0249: protected Color getHighlightedText() {
0250: return m_cTextHighlight;
0251: }
0252:
0253: /**
0254: * This returns the insets of the Paragraph.
0255: * @return insets of the Paragraph
0256: */
0257: public Insets getInsets() {
0258: return m_inInsets;
0259: }
0260:
0261: /**
0262: * This returns the lines of the Paragraph.
0263: * @return the lines of the Paragraph
0264: */
0265: protected Vector getLines() {
0266: return lines;
0267: }
0268:
0269: /**
0270: * This returns whether or not the mark (selection) is visible.
0271: * @return mark visibility
0272: */
0273: protected boolean getMarkVisible() {
0274: return m_bMarkVisible;
0275: }
0276:
0277: /**
0278: * This takes the string and returns the cursor position given the length
0279: * in pixels.
0280: * @param s - string to measure on
0281: * @param len - length to span in pixels
0282: * @return cursor position
0283: */
0284: protected int getPositionAt(String s, int len) {
0285: if (x_offset <= 0 && m_nHAlign != LEFT) {
0286: int w1 = m_nWidth;
0287: int w2 = fontMetrics.stringWidth(s);
0288: if (m_nHAlign == CENTER)
0289: len -= (w1 - w2) / 2;
0290: else if (m_nHAlign == RIGHT)
0291: len -= (w1 - w2);
0292: }
0293: len += x_offset;
0294: if (len == 0)
0295: return len;
0296: if (fontMetrics.stringWidth(s) <= len) {
0297: int result = s.length();
0298: if (lines.indexOf(s) < (lines.size() - 1)
0299: && s.charAt(result - 1) == ' ')
0300: result--;
0301: return result;
0302: } else {
0303: int i;
0304: for (i = 0; i < s.length() - 1; i++) {
0305: if (fontMetrics.stringWidth(s.substring(0, i + 1)) > len)
0306: break;
0307: }
0308: return i;
0309: }
0310: }
0311:
0312: /**
0313: * This returns the previous x offset.
0314: * @return previous x offset
0315: */
0316: protected int getPrevXOffset() {
0317: return prevXOffset;
0318: }
0319:
0320: /**
0321: * This returns the end of the selection.
0322: * @return end of the selection
0323: */
0324: protected int getSelectionEnd() {
0325: return selectionEnd;
0326: }
0327:
0328: /**
0329: * This returns the start of the selection.
0330: * @return start of the selection
0331: */
0332: protected int getSelectionStart() {
0333: return selectionStart;
0334: }
0335:
0336: /**
0337: * This returns the selection state.
0338: * @return selection state
0339: */
0340: protected int getSelectionState() {
0341: return selected;
0342: }
0343:
0344: /**
0345: * This returns the text control.
0346: * @return text control
0347: */
0348: public IScrollable getTarget() {
0349: return target;
0350: }
0351:
0352: /**
0353: * This returns the text of the Paragraph.
0354: * @return text
0355: */
0356: protected String getText() {
0357: return buffer.toString();
0358: }
0359:
0360: /**
0361: * This returns the width of the Paragraph in pixels.
0362: * @return width of Paragraph
0363: */
0364: public int getWidth() {
0365: return m_nWidth;
0366: }
0367:
0368: /**
0369: * This returns the cursor position.
0370: * @return cursor position
0371: * @see #getCursorPos
0372: */
0373: protected int getXCoord() {
0374: return cursorPos;
0375: }
0376:
0377: /**
0378: * This returns the x offset.
0379: * @return x offset
0380: */
0381: protected int getXOffset() {
0382: return x_offset;
0383: }
0384:
0385: /**
0386: * This returns the height of the Paragraph.
0387: * @return height of Paragraph
0388: */
0389: protected int getYSpan() {
0390: return (fontMetrics.getHeight() * lines.size());
0391: }
0392:
0393: /**
0394: * This inserts a character into the Paragraph.
0395: * @param c - character to insert
0396: * @param watchWidth - whether to check to see if it fits first
0397: * @return whether or not the insertion was successful
0398: */
0399: protected boolean insertChar(char c, boolean watchWidth) {
0400: if (watchWidth) {
0401: StringBuffer b2 = new StringBuffer(buffer.toString());
0402: b2.insert(cursorPos, c);
0403: if (fontMetrics.stringWidth(b2.toString()) <= (m_nWidth - 4/*(2*leftOffset)*/)) {
0404: buffer.insert(cursorPos++, c);
0405: onTextModified();
0406: return true;
0407: }
0408: return false;
0409: }
0410:
0411: buffer.insert(cursorPos++, c);
0412: onTextModified();
0413: return true;
0414: }
0415:
0416: /**
0417: * This returns whether or not the Paragraph class allows scrolling.
0418: * @return scrolling behavior flag
0419: */
0420: protected boolean isAllowScroll() {
0421: return m_bAllowScroll;
0422: }
0423:
0424: /**
0425: * This returns whether or not the Paragraph class allows
0426: * auto-wrapping behavior.
0427: * @return auto-wrapping behavior flag
0428: */
0429: public boolean isAutoWrap() {
0430: return m_bAutoWrap;
0431: }
0432:
0433: /**
0434: * This returns whether or not the cursor position is at the end.
0435: * @return if the cursor is at the end
0436: */
0437: protected boolean isCursorAtEnd() {
0438: return (cursorPos == (buffer.length()));
0439: }
0440:
0441: /**
0442: * This returns whether or not the cursor is on the first line of the text
0443: * control.
0444: * @return whether or not the cursor is one the first line
0445: */
0446: protected boolean isCursorOnFirstLine() {
0447: String s = (String) lines.firstElement();
0448: int upper = s.length();
0449: if (upper > 0 && lines.size() > 1 && s.charAt(upper - 1) == ' ')
0450: upper--;
0451: return (cursorPos <= upper); // lwang
0452: }
0453:
0454: /**
0455: * This returns whether or not the cursor is on the last line
0456: * of the text control.
0457: * @return whether or not the cursor is on the last line
0458: */
0459: protected boolean isCursorOnLastLine() {
0460: if (lines.size() == 1)
0461: return true;
0462:
0463: int base = 0;
0464: for (int i = 0; i < lines.size() - 1; i++)
0465: base += ((String) lines.elementAt(i)).length();
0466: return (cursorPos > base);
0467: }
0468:
0469: /**
0470: * This returns whether or not the Paragraph class is
0471: * visible.
0472: * @return Paragraph's visibility
0473: */
0474: protected boolean isVisible() {
0475: return m_bVisible;
0476: }
0477:
0478: /**
0479: * This moves the cursor within the text control. Called from up/down
0480: * arrow keys.
0481: * @param b - if true, go to the last line
0482: * @param w - width (in pixels) to move to
0483: * @param key - which key was pressed.
0484: */
0485: protected void moveSpecial(boolean b, int w, int key) {
0486: String s = (b) ? (String) lines.lastElement() : (String) lines
0487: .firstElement();
0488: int base = 0;
0489: if (b) {
0490: for (int i = 0; i < (lines.size() - 1); i++) {
0491: base += ((String) lines.elementAt(i)).length();
0492: }
0493: }
0494:
0495: if (isAllowScroll()) {
0496: int sW = fontMetrics.stringWidth(s);
0497: if (b
0498: && (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_END)) {
0499: if (sW + m_inInsets.right + m_inInsets.left > w
0500: && getTarget() != null) {
0501: int nOffset = Math.max(0, sW - w + m_inInsets.right
0502: + m_inInsets.left + 6);
0503: getTarget().setXOffset(nOffset);
0504: }
0505: } else if (!b
0506: && (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_HOME)) {
0507: if (x_offset > 0 && getTarget() != null)
0508: getTarget().setXOffset(0);
0509: } else {
0510: if (x_offset > sW && getTarget() != null) {
0511: int nOffset = Math.max(0, sW - w + m_inInsets.right
0512: + m_inInsets.left + 6);
0513: getTarget().setXOffset(nOffset);
0514: }
0515: }
0516: }
0517:
0518: cursorPos = base + getPositionAt(s, w);
0519: }
0520:
0521: /**
0522: * This is called whenever the user hits the 'Backspace' key.
0523: */
0524: protected void onBackspaceKey() {
0525: String s = buffer.toString();
0526: String newS = s.substring(0, cursorPos - 1);
0527: if (cursorPos < s.length())
0528: newS += s.substring(cursorPos);
0529: buffer = new StringBuffer(newS);
0530: cursorPos--;
0531: onTextModified();
0532:
0533: if (isAllowScroll()) {
0534: int sW = fontMetrics.stringWidth(newS);
0535: if (getCursorPoint().x <= m_inInsets.left
0536: && getTarget() != null) {
0537: int nOffset = Math.max(0, sW - 3 * m_nWidth / 2
0538: + m_inInsets.left + m_inInsets.right);
0539: setXOffset(nOffset);
0540: getTarget().setXOffset(nOffset);
0541: }
0542: }
0543: }
0544:
0545: /**
0546: * This is called whenever the user hits the 'Delete' key.
0547: */
0548: protected void onDeleteKey() {
0549: String s = buffer.toString();
0550: if (cursorPos < s.length()) {
0551: String newS = s.substring(0, cursorPos);
0552: newS += s.substring(cursorPos + 1);
0553: buffer = new StringBuffer(newS);
0554: onTextModified();
0555: }
0556: }
0557:
0558: /**
0559: * This is called whenever the user hits the down arrow key in a MultiText
0560: * control and the new cursor position has to be figured.
0561: */
0562: protected void onDownKey() {
0563: int base = 0;
0564: int lineNum = 0;
0565: for (int i = 0; i < lines.size(); i++) {
0566: String s = (String) lines.elementAt(i);
0567: int upper = s.length();
0568: if (upper > 0 && i < (lines.size() - 1)
0569: && s.charAt(upper - 1) == ' ')
0570: upper--;
0571: upper += base;
0572: base += s.length();
0573: if (cursorPos <= upper) {
0574: lineNum = i + 1;
0575: break;
0576: }
0577: }
0578: if (lineNum >= lines.size())
0579: return;
0580: else {
0581: cursorPos = base
0582: + getPositionAt((String) lines.elementAt(lineNum),
0583: getCursorPoint().x);
0584: }
0585: }
0586:
0587: /**
0588: * This is called from the MultiText class when the 'End' key was pressed
0589: * and the new cursor position has to be figured out.
0590: */
0591: protected void onEndKey() {
0592: // lwang
0593: if (isAllowScroll())
0594: moveSpecial(true, m_nWidth + m_inInsets.right
0595: + m_inInsets.left, KeyEvent.VK_END);
0596:
0597: int base = 0;
0598: for (int i = 0; i < lines.size(); i++) {
0599: String s = (String) lines.elementAt(i);
0600: int upper = s.length();
0601: if (upper > 0 && i < (lines.size() - 1)
0602: && s.charAt(upper - 1) == ' ')
0603: upper--;
0604: upper += base;
0605: if (cursorPos >= base && cursorPos <= upper) {
0606: cursorPos = upper;
0607: break;
0608: }
0609: base += s.length();
0610: }
0611: }
0612:
0613: /**
0614: * This is called from the MultiText class to determine
0615: * whether the 'Enter' key was pressed in the middle of
0616: * a Paragraph.
0617: * @return string after the cursor position (null if none)
0618: */
0619: protected String onEnterKey() {
0620: if (cursorPos == buffer.length())
0621: return null;
0622: String s = buffer.toString();
0623: buffer = new StringBuffer(s.substring(0, cursorPos));
0624: onTextModified();
0625: return (s.substring(cursorPos));
0626: }
0627:
0628: /**
0629: * This is called from the MultiText class whenever the 'Home' key is
0630: * pressed and the new cursor position has to be figured out.
0631: */
0632: protected void onHomeKey() {
0633: // lwang
0634: if (isAllowScroll())
0635: moveSpecial(false, m_nWidth, KeyEvent.VK_HOME);
0636:
0637: int base = 0;
0638: for (int i = 0; i < lines.size(); i++) {
0639: String s = (String) lines.elementAt(i);
0640: int upper = s.length();
0641: if (upper > 0 && i < (lines.size() - 1)
0642: && s.charAt(upper - 1) == ' ')
0643: upper--;
0644: upper += base;
0645: if (cursorPos <= upper) {
0646: cursorPos = base;
0647: break;
0648: } else
0649: base += s.length();
0650: }
0651: }
0652:
0653: /**
0654: * This is called whenever horizontal scrolling has to be figured out.
0655: */
0656: protected void onScrollAction() {
0657: if (!m_bAllowScroll)
0658: return;
0659:
0660: if (m_nWidth > 0) {
0661: int x = getCursorPoint().x + 2;
0662: if (x > (m_nWidth)) {
0663: x_offset += (x - (m_nWidth));
0664: } else if (x < 2) {
0665: x_offset -= 2 - x;
0666: }
0667: if (isCursorAtEnd() && m_nHAlign == RIGHT && x_offset > 0
0668: && x < m_nWidth - 2) {
0669: x_offset -= (m_nWidth - 2) - x;
0670: if (x_offset < 0)
0671: x_offset = 0;
0672: }
0673:
0674: IScrollable label = getTarget();
0675: if (label != null)
0676: label.setXOffset(x_offset);
0677: }
0678: }
0679:
0680: /**
0681: * This is called whenever there's a text modification.
0682: */
0683: protected void onTextModified() {
0684: if (isAutoWrap() && m_nWidth > 0)
0685: lines = wrapText(buffer.toString());
0686: else {
0687: lines.setElementAt(buffer.toString(), 0);
0688: onScrollAction();
0689: }
0690: }
0691:
0692: /**
0693: * This is called from the MultiText class whenever the user hits
0694: * the up arrow key and the new cursor position has to be figured
0695: * out.
0696: */
0697: protected void onUpKey() {
0698: int base = 0;
0699: int prevBase = 0;
0700: int lineNum = 0;
0701: for (int i = 0; i < lines.size(); i++) {
0702: String s = (String) lines.elementAt(i);
0703: int upper = s.length();
0704: if (upper > 0 && i < (lines.size() - 1)
0705: && s.charAt(upper - 1) == ' ')
0706: upper--;
0707: upper += base;
0708: if (cursorPos >= base && cursorPos <= upper) {
0709: lineNum = i - 1;
0710: break;
0711: }
0712: prevBase = base;
0713: base += s.length();
0714: }
0715: if (lineNum < 0)
0716: return;
0717: else {
0718: cursorPos = prevBase
0719: + getPositionAt((String) lines.elementAt(lineNum),
0720: getCursorPoint().x);
0721: }
0722: }
0723:
0724: /**
0725: * This draws the Paragraph class given the arguments.
0726: * @param g - the Graphics class to draw upon
0727: * @param x - the x coordinate
0728: * @param y - the y coordinate
0729: * @param underline - whether to draw an underline or not
0730: * @param xo - whether to draw the strikeout or not
0731: */
0732: protected void render(Graphics g, int x, int y, boolean underline,
0733: boolean xo) {
0734:
0735: int base = 0;
0736: g.setFont(m_fFont);
0737: g.setColor(m_cForeground);
0738: boolean paintAll = false;
0739:
0740: if (m_nHAlign == LEFT)
0741: x += 2;
0742: for (int i = 0; i < lines.size(); i++) {
0743: String str = (String) lines.elementAt(i);
0744: if (x_offset == 0 && m_nHAlign != LEFT) {
0745: if (m_nHAlign == CENTER) {
0746: x = ((m_nWidth / 2) - (fontMetrics.stringWidth(str) / 2)); // - 2;
0747: } else if (m_nHAlign == RIGHT) {
0748: x = m_nWidth /*- 2*/- fontMetrics.stringWidth(str)
0749: - m_inInsets.right;
0750: }
0751: }
0752:
0753: if (x < m_inInsets.left)
0754: x = m_inInsets.left;
0755: int upper = str.length();
0756: if (upper > 0 && i < (lines.size() - 1)
0757: && str.charAt(upper - 1) == ' ')
0758: upper--;
0759: upper += base;
0760:
0761: int y2 = y + fontMetrics.getHeight();
0762: y2 -= (fontMetrics.getHeight() / 4);
0763: x -= x_offset;
0764: if (!m_bMarkVisible || selected == NONE) {
0765: g.drawString(str, x, y2);
0766: if (underline) {
0767: int yDraw = y + fontMetrics.getHeight();
0768: g.drawLine(x, yDraw, x
0769: + (fontMetrics.stringWidth(str)), yDraw);
0770: }
0771: if (xo) {
0772: int yDraw = y + (fontMetrics.getHeight() / 2);
0773: g.drawLine(x, yDraw, x
0774: + (fontMetrics.stringWidth(str)), yDraw);
0775: }
0776: } else if (selected == COMPLETE) {
0777: g.setColor(m_cHighlight);
0778: g.fillRect(x, y, fontMetrics
0779: .stringWidth(str/*.substring(0, upper)*/),
0780: fontMetrics.getHeight());
0781: g.setColor(m_cTextHighlight);
0782: g.drawString(str, x, y2);
0783: if (underline) {
0784: int yDraw = y + fontMetrics.getHeight();
0785: g.drawLine(x, yDraw, x
0786: + (fontMetrics.stringWidth(str)), yDraw);
0787: }
0788: if (xo) {
0789: int yDraw = y + (fontMetrics.getHeight() / 2);
0790: g.drawLine(x, yDraw, x
0791: + (fontMetrics.stringWidth(str)), yDraw);
0792: }
0793: } else {
0794: int start = selectionStart;
0795: int end = selectionEnd;
0796: if (selectionStart > selectionEnd) {
0797: end = selectionStart;
0798: start = selectionEnd;
0799: }
0800: boolean paintAfter, paintBefore, paintPart;
0801: paintAfter = paintBefore = paintPart = false;
0802: // setup boolean vars
0803: if ((start >= base && start <= upper)
0804: && (end >= base && end <= upper))
0805: paintPart = true;
0806: else if (start >= base && start < (base + str.length()))
0807: paintAfter = true;
0808: else if (end >= base && end < (base + str.length()))
0809: paintBefore = true;
0810: if (paintAfter) {
0811: int pos = start - base;
0812: String s1 = str.substring(0, pos);
0813: String s2 = str.substring(pos);
0814: g.drawString(s1, x, y2);
0815: int x2 = x + fontMetrics.stringWidth(s1);
0816: g.setColor(m_cHighlight);
0817: g.fillRect(x2, y, fontMetrics.stringWidth(s2),
0818: fontMetrics.getHeight());
0819: g.setColor(m_cTextHighlight);
0820: g.drawString(s2, x2, y2);
0821: if (underline) {
0822: int yDraw = y + fontMetrics.getHeight();
0823: g
0824: .drawLine(
0825: x,
0826: yDraw,
0827: x
0828: + (fontMetrics
0829: .stringWidth(str)),
0830: yDraw);
0831: }
0832: if (xo) {
0833: int yDraw = y + (fontMetrics.getHeight() / 2);
0834: g
0835: .drawLine(
0836: x,
0837: yDraw,
0838: x
0839: + (fontMetrics
0840: .stringWidth(str)),
0841: yDraw);
0842: }
0843: paintAll = true;
0844: } else if (paintBefore) {
0845: int pos = end - base;
0846: String s1 = str.substring(0, pos);
0847: String s2 = str.substring(pos);
0848: int x2 = x + fontMetrics.stringWidth(s1);
0849: g.setColor(m_cHighlight);
0850: g.fillRect(x, y, fontMetrics.stringWidth(s1),
0851: fontMetrics.getHeight());
0852: g.setColor(m_cTextHighlight);
0853: g.drawString(s1, x, y2);
0854: g.setColor(m_cForeground);
0855: g.drawString(s2, x2, y2);
0856: if (underline) {
0857: int yDraw = y + fontMetrics.getHeight();
0858: g
0859: .drawLine(
0860: x,
0861: yDraw,
0862: x
0863: + (fontMetrics
0864: .stringWidth(str)),
0865: yDraw);
0866: }
0867: if (xo) {
0868: int yDraw = y + (fontMetrics.getHeight() / 2);
0869: g
0870: .drawLine(
0871: x,
0872: yDraw,
0873: x
0874: + (fontMetrics
0875: .stringWidth(str)),
0876: yDraw);
0877: }
0878: paintAll = false;
0879: } else if (paintAll) {
0880: g.setColor(m_cHighlight);
0881: g
0882: .fillRect(
0883: x,
0884: y,
0885: fontMetrics.stringWidth(str),
0886: /*(m_nWidth-m_inInsets.left-m_inInsets.right),*/fontMetrics
0887: .getHeight());
0888: g.setColor(m_cTextHighlight);
0889: g.drawString(str, x, y2);
0890: if (underline) {
0891: int yDraw = y + fontMetrics.getHeight();
0892: g
0893: .drawLine(
0894: x,
0895: yDraw,
0896: x
0897: + (fontMetrics
0898: .stringWidth(str)),
0899: yDraw);
0900: }
0901: if (xo) {
0902: int yDraw = y + (fontMetrics.getHeight() / 2);
0903: g
0904: .drawLine(
0905: x,
0906: yDraw,
0907: x
0908: + (fontMetrics
0909: .stringWidth(str)),
0910: yDraw);
0911: }
0912: } else if (paintPart) {
0913: String s1, s2, s3;
0914: int x2, x3;
0915: int pos1 = start - base;
0916: int pos2 = end - base;
0917: s1 = str.substring(0, pos1);
0918: x2 = x + fontMetrics.stringWidth(s1);
0919: s2 = str.substring(pos1, pos2);
0920: x3 = x2 + fontMetrics.stringWidth(s2);
0921: s3 = str.substring(pos2);
0922: g.drawString(s1, x, y2);
0923: g.setColor(m_cHighlight);
0924: g.fillRect(x2, y, fontMetrics.stringWidth(s2),
0925: fontMetrics.getHeight());
0926: g.setColor(m_cTextHighlight);
0927: g.drawString(s2, x2, y2);
0928: g.setColor(getForeground());
0929: g.drawString(s3, x3, y2);
0930: if (underline) {
0931: int yDraw = y + fontMetrics.getHeight();
0932: g
0933: .drawLine(
0934: x,
0935: yDraw,
0936: x
0937: + (fontMetrics
0938: .stringWidth(str)),
0939: yDraw);
0940: }
0941: if (xo) {
0942: int yDraw = y + (fontMetrics.getHeight() / 2);
0943: g
0944: .drawLine(
0945: x,
0946: yDraw,
0947: x
0948: + (fontMetrics
0949: .stringWidth(str)),
0950: yDraw);
0951: }
0952: } else {
0953: g.drawString(str, x, y2);
0954: if (underline) {
0955: int yDraw = y + fontMetrics.getHeight();
0956: g
0957: .drawLine(
0958: x,
0959: yDraw,
0960: x
0961: + (fontMetrics
0962: .stringWidth(str)),
0963: yDraw);
0964: }
0965: if (xo) {
0966: int yDraw = y + (fontMetrics.getHeight() / 2);
0967: g
0968: .drawLine(
0969: x,
0970: yDraw,
0971: x
0972: + (fontMetrics
0973: .stringWidth(str)),
0974: yDraw);
0975: }
0976: }
0977: }
0978: y += fontMetrics.getHeight();
0979: base += str.length();
0980: }
0981: }
0982:
0983: /**
0984: * This sets the scrolling behavior of the Paragraph class.
0985: * @param b - scrolling behavior flag
0986: */
0987: protected void setAllowScroll(boolean b) {
0988: m_bAllowScroll = b;
0989: }
0990:
0991: /**
0992: * This sets whether or not the Paragraph class will autowrap.
0993: * @param bWrap - autowrap boolean flag
0994: */
0995: public void setAutoWrap(boolean bWrap) {
0996: if (m_bAutoWrap != bWrap) {
0997: m_bAutoWrap = bWrap;
0998: onTextModified();
0999: }
1000: }
1001:
1002: /**
1003: * This sets the background of the Paragraph.
1004: * @param c - background color
1005: */
1006: public void setBackground(Color c) {
1007: m_cBackground = c;
1008: }
1009:
1010: /**
1011: * This sets the cursor position of the Paragraph.
1012: * @param p - cursor position
1013: */
1014: protected void setCursorPos(int p) {
1015: cursorPos = p;
1016: onScrollAction();
1017: }
1018:
1019: /**
1020: * This sets the font of the Paragraph.
1021: * @param f - the new Font
1022: */
1023: public void setFont(Font f) {
1024: m_fFont = f;
1025: }
1026:
1027: /**
1028: * This sets the FontMetrics of the Paragraph.
1029: * @param fm - the new FontMetrics
1030: */
1031: public void setFontMetrics(FontMetrics fm) {
1032: fontMetrics = fm;
1033: }
1034:
1035: /**
1036: * This sets the foreground color of the Paragraph.
1037: * @param c - the new Foreground
1038: */
1039: public void setForeground(Color c) {
1040: m_cForeground = c;
1041: }
1042:
1043: /**
1044: * This sets the horizontal alignment of the Paragraph.
1045: * @param align - horizontal alignment
1046: */
1047: protected void setHAlign(int align) {
1048: m_nHAlign = align;
1049: }
1050:
1051: /**
1052: * This sets the highlighting color.
1053: * @param c - highlighting color
1054: */
1055: protected void setHighlight(Color c) {
1056: m_cHighlight = c;
1057: }
1058:
1059: /**
1060: * This sets the color of the highlighted text.
1061: * @param c - highlighted text color
1062: */
1063: protected void setHighlightedText(Color c) {
1064: m_cTextHighlight = c;
1065: }
1066:
1067: /**
1068: * This sets the insets of the text control.
1069: * @param i - insets
1070: */
1071: public void setInsets(Insets i) {
1072: m_inInsets = i;
1073: }
1074:
1075: /**
1076: * This sets whether or not the selection mark is visible.
1077: * @param b - mark visibility flag
1078: */
1079: protected void setMarkVisible(boolean b) {
1080: m_bMarkVisible = b;
1081: }
1082:
1083: /**
1084: * This sets the previous x offset.
1085: * @param x - previous x offset
1086: */
1087: protected void setPrevXOffset(int x) {
1088: prevXOffset = x;
1089: }
1090:
1091: /**
1092: * This sets the selection end of the Paragraph.
1093: * @param pos - position of the selection end
1094: */
1095: protected void setSelectionEnd(int pos) {
1096: selectionEnd = pos;
1097: }
1098:
1099: /**
1100: * This sets the start of the Paragraph's selection.
1101: * @param pos - position of the start of the selection
1102: */
1103: protected void setSelectionStart(int pos) {
1104: selectionStart = pos;
1105: }
1106:
1107: /**
1108: * This sets the selection state of the Paragraph.
1109: * @param s - one of these: (Paragraph.NONE||Paragraph.PARTIAL||Paragraph.COMPLETE)
1110: */
1111: protected void setSelectionState(int s) {
1112: selected = s;
1113: }
1114:
1115: /**
1116: * This sets the text control as the target.
1117: * @param target - the text control that implements IScrollable
1118: */
1119: public void setTarget(IScrollable target) {
1120: this .target = target;
1121: }
1122:
1123: /**
1124: * This sets the text of the Paragraph.
1125: * @param s - text
1126: */
1127: protected void setText(String s) {
1128: buffer = new StringBuffer(s);
1129: onTextModified();
1130: }
1131:
1132: /**
1133: * This sets the width of the Paragraph in pixels.
1134: * @param w - new width of the Paragraph
1135: */
1136: public void setWidth(int w) {
1137: m_nWidth = w;
1138: onTextModified();
1139: }
1140:
1141: /**
1142: * This sets the x offset of the Paragraph.
1143: * @param x - x offset
1144: */
1145: protected void setXOffset(int x) {
1146: x_offset = x;
1147: }
1148:
1149: /**
1150: * This overrides Object's toString() to represent the Paragraph
1151: * in String format.
1152: * @return a string representation of the Paragraph
1153: */
1154: public String toString() {
1155: String s = new String();
1156: s = "Paragraph: [text=" + buffer.toString()
1157: + "||selection state=";
1158: if (selected == NONE)
1159: s += "NONE";
1160: else if (selected == PARTIAL)
1161: s += "PARTIAL";
1162: else
1163: s += "COMPLETE";
1164: s += "||selectionStart=" + selectionStart + "||selectionEnd="
1165: + selectionEnd;
1166: return s;
1167: }
1168:
1169: private Vector wrapText(String str) {
1170:
1171: Vector v = new Vector();
1172: int first = 0;
1173: if (str.length() > 0) {
1174: for (int i = 0; i < str.length(); i++) {
1175: String s = str.substring(first, i + 1);
1176: if (fontMetrics.stringWidth(s) > m_nWidth - 4) {
1177: // word wrap
1178: int nWord = i;
1179: while (nWord > first && str.charAt(nWord) != ' ')
1180: nWord--;
1181: if (nWord == first)
1182: nWord = i;
1183:
1184: if (first != nWord) {
1185: if (nWord != i || str.charAt(nWord) == ' ')
1186: nWord++;
1187: v.addElement(str.substring(first, nWord));
1188: }
1189: first = nWord;
1190: }
1191: }
1192: }
1193: if (first < str.length() || str.length() == 0)
1194: v.addElement(str.substring(first));
1195: return v;
1196: }
1197: }
|