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 : Text.java - implements the Text class
0015: *
0016: */
0017:
0018: /**
0019: Text
0020:
0021: implements the text control. Text is the second of three in a
0022: heirarchy and serves as a one-line edit control. It also supports
0023: horizontal scrolling.
0024: */
0025:
0026: import java.awt.*;
0027: import com.sun.portal.log.common.PortalLogger;
0028: import java.awt.event.*;
0029: import java.awt.datatransfer.*;
0030: import java.util.*;
0031:
0032: public class Text extends OBLabel implements Runnable, ClipboardOwner {
0033:
0034: protected Point cursorPoint;
0035: protected ActionListener actionListener;
0036: protected TextListener textListener;
0037: protected TextEvent textEvent = new TextEvent(this ,
0038: TextEvent.TEXT_VALUE_CHANGED);
0039: protected TextEvent textEventEnter = new TextEvent(this ,
0040: TextEvent.TEXT_LAST);
0041: protected ActionEvent actionEventEnter = new ActionEvent(this ,
0042: ActionEvent.ACTION_PERFORMED, endEditing);
0043:
0044: Point selectionStart, selectionEnd;
0045:
0046: Thread m_tCursor;
0047: Color m_cCursorColor;
0048: Point cursor;
0049: boolean m_bAllowHScroll = true;
0050: boolean m_bEditable = true;
0051: boolean m_bModified = false;
0052: transient Clipboard clipboard = new Clipboard(
0053: "BlendTextComponentClipboard");
0054:
0055: int m_nCursorWidth = 2;
0056:
0057: // Backwards Compatible variables
0058: boolean AllowEnter = false;
0059: public String textModified = "textModified";
0060: public String cursorMovedOutOfBound = "cursorMovedOutOfBound";
0061: public static String endEditing = "End_Editing";
0062:
0063: /**
0064: * Null constructor that routes to another constructor with a blank
0065: * string.
0066: */
0067: public Text() {
0068: this ("");
0069: }
0070:
0071: /**
0072: * Preferred constructor for Text that takes the String argument as the
0073: * initial text.
0074: * @param s - initial text
0075: */
0076: public Text(String s) {
0077: super (s);
0078:
0079: setBorderStyle(INSET);
0080:
0081: m_inTextInsets.top = 3;
0082: m_inTextInsets.left = 3;
0083: cursorPoint = new Point(0, 0);
0084: cursor = new Point(0, 0);
0085: m_cCursorColor = Color.black;
0086: selectionStart = new Point(0, 0);
0087: selectionEnd = new Point(0, 0);
0088: setAutoWrap(false);
0089: setInsets(m_inTextInsets);
0090: setAllowHScroll(true);
0091:
0092: enableEvents(AWTEvent.MOUSE_EVENT_MASK);
0093: enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
0094: enableEvents(AWTEvent.FOCUS_EVENT_MASK);
0095: enableEvents(AWTEvent.KEY_EVENT_MASK);
0096: }
0097:
0098: /**
0099: * Add an ActionListener to the Text control.
0100: * @param l - the listener
0101: */
0102: public void addActionListener(ActionListener l) {
0103: actionListener = AWTEventMulticaster.add(actionListener, l);
0104: }
0105:
0106: /**
0107: * This adds a TextListener.
0108: * @param l - the text listener
0109: */
0110: public void addTextListener(TextListener l) {
0111: textListener = AWTEventMulticaster.add(textListener, l);
0112: }
0113:
0114: /**
0115: * This takes the selected text and copies it to the clipboard.
0116: */
0117: protected void copy() {
0118: if (!isSelected())
0119: return;
0120: String str = getSelectedText();
0121: setClipboardText(str);
0122: }
0123:
0124: /**
0125: * This cuts the selected text. If copy is true, then the selected text
0126: * is copied to the clipboard.
0127: * @param copy - whether or not to copy the selected text to the clipboard
0128: */
0129: protected void cut(boolean copy) {
0130: if (!isSelected())
0131: return;
0132: if (copy) {
0133: String clipText = getSelectedText();
0134: setClipboardText(clipText);
0135: }
0136: Point start = selectionStart;
0137: Point end = selectionEnd;
0138:
0139: if (end.y < start.y || (start.y == end.y && start.x > end.x)) {
0140: Point temp = start;
0141: start = end;
0142: end = temp;
0143: }
0144: String str = new String();
0145: for (int i = start.y; i <= end.y; i++) {
0146: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
0147: if (i == start.y) {
0148: String s = p.getText();
0149: str += s.substring(0, start.x);
0150: }
0151: if (i == end.y) {
0152: String s = p.getText();
0153: str += s.substring(end.x);
0154: }
0155: }
0156: ((Paragraph) m_vParagraphs.elementAt(start.y)).setText(str);
0157: for (int i = (start.y + 1); i <= end.y; i++)
0158: m_vParagraphs.removeElement((Paragraph) m_vParagraphs
0159: .elementAt(start.y + 1));
0160: unselectAll();
0161: start();
0162: cursorPoint.y = start.y;
0163: Paragraph p = (Paragraph) m_vParagraphs.elementAt(start.y);
0164: p
0165: .moveSpecial(true, p.getCursorPoint().x,
0166: KeyEvent.VK_UNDEFINED);
0167: p.setCursorPos(start.x);
0168:
0169: y_offset = prevYOffset;
0170: repaint();
0171: }
0172:
0173: /**
0174: * this function finds the paragraph, given the y coordinate
0175: * if the boolean is true, then if we didn't find the paragraph
0176: * it will return the last paragraph, otherwise, null
0177: * @param y - y coordinate
0178: * @param b - whether or not to return the last element if nothing's found
0179: */
0180: protected Paragraph findParagraph(int y, boolean b) {
0181: int marker = 0;
0182: y += y_offset;
0183: for (int i = 0; i < m_vParagraphs.size(); i++) {
0184: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
0185: marker += p.getYSpan();
0186: if (y < marker)
0187: return p;
0188: }
0189: return (b) ? (Paragraph) m_vParagraphs.lastElement() : null;
0190: }
0191:
0192: /**
0193: * This finds the y coordinate of Paragraph
0194: * @param p - Paragraph
0195: */
0196: protected int findYCoord(Paragraph p) {
0197: int y = m_inTextInsets.top;
0198: for (int i = 0; i < m_vParagraphs.size(); i++) {
0199: Paragraph pg = (Paragraph) m_vParagraphs.elementAt(i);
0200: if (pg == p)
0201: break;
0202: y += pg.getYSpan();
0203: }
0204: return y;
0205: }
0206:
0207: /**
0208: * This returns whether or not horizontal scrolling is allowed.
0209: * @return horizontal scrolling behavior
0210: */
0211: public boolean getAllowHScroll() {
0212: return m_bAllowHScroll && getHAlign() == LEFT && !isAutoWrap();
0213: }
0214:
0215: /**
0216: * This returns the clipboard used by the text control with
0217: * copy and cut commands.
0218: */
0219: public Clipboard getClipboard() {
0220: return clipboard;
0221: }
0222:
0223: /**
0224: * This returns the cursor position (0 - length of string) of the
0225: * text control.
0226: * @return the cursor's position
0227: */
0228: public int getCursorPos() {
0229: return ((Paragraph) m_vParagraphs.elementAt(cursorPoint.y))
0230: .getCursorPos();
0231: }
0232:
0233: /**
0234: * This returns the width of the cursor.
0235: * @return width of the cursor
0236: */
0237: public int getCursorWidth() {
0238: return m_nCursorWidth;
0239: }
0240:
0241: /**
0242: * This returns whether or not the text control has been
0243: * modified.
0244: * @return whether or not the text control has been modified
0245: */
0246: public boolean getModified() {
0247: return m_bModified;
0248: }
0249:
0250: /**
0251: * This returns the selected text.
0252: * @return the selected text
0253: */
0254: public String getSelectedText() {
0255: String str = new String();
0256: if (!isSelected())
0257: return str;
0258: Point start = selectionStart;
0259: Point end = selectionEnd;
0260: if (end.y < start.y || (start.y == end.y && start.x > end.x)) {
0261: Point temp = start;
0262: start = end;
0263: end = temp;
0264: }
0265: for (int i = start.y; i <= end.y; i++) {
0266: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
0267: if (i == start.y && start.y == end.y) {
0268: String s = p.getText();
0269: str += s.substring(start.x, end.x);
0270: } else {
0271: if (i == start.y) {
0272: String s = p.getText();
0273: str += s.substring(start.x);
0274: }
0275: if (i == end.y) {
0276: String s = p.getText();
0277: str += s.substring(0, end.x);
0278: }
0279: if ((i != start.y && i != end.y)
0280: && (i > start.y && i < end.y))
0281: str += p.getText();
0282: }
0283: str += "\n";
0284: }
0285: str = str.substring(0, (str.length() - 1));
0286: return str;
0287: }
0288:
0289: /**
0290: * This returns the position of the end of the selected text
0291: * @return selection's end
0292: */
0293: public int getSelectionEnd() {
0294: return Math.max(selectionStart.x, selectionEnd.x);
0295: }
0296:
0297: /**
0298: * This returns the position of the start of the selected text
0299: * @return position of the start of the selected text
0300: */
0301: public int getSelectionStart() {
0302: return Math.min(selectionStart.x, selectionEnd.x);
0303: }
0304:
0305: /**
0306: * This is called whenever the Text control receives focus
0307: */
0308: protected void gotFocus() {
0309: if (m_bEditable) {
0310: start();
0311:
0312: for (int i = 0; i < m_vParagraphs.size(); i++) {
0313: ((Paragraph) m_vParagraphs.elementAt(i))
0314: .setMarkVisible(true);
0315: }
0316: repaint();
0317: }
0318: }
0319:
0320: /**
0321: * This is called from processKeyEvent whenever the user enters a character.
0322: * @param c - the character entered
0323: */
0324: protected boolean insertChar(char c) {
0325: if (c == KeyEvent.CHAR_UNDEFINED)
0326: return false;
0327: if (m_vParagraphs == null || cursorPoint.y < 0
0328: || cursorPoint.y > m_vParagraphs.size() - 1)
0329: return false;
0330:
0331: if (isSelected()) {
0332: cut(false);
0333: if (textListener != null)
0334: textListener.textValueChanged(textEvent);
0335: start();
0336: }
0337: Paragraph p = (Paragraph) m_vParagraphs
0338: .elementAt(cursorPoint.y);
0339: if (p.insertChar(c, !m_bAllowHScroll && !isAutoWrap())) {
0340: if (textListener != null)
0341: textListener.textValueChanged(textEvent);
0342: update();
0343: return true;
0344: } else
0345: return false;
0346: }
0347:
0348: /**
0349: * This returns whether or not the text control allows the enter key.
0350: * @return false
0351: */
0352: public boolean isAllowEnter() {
0353: return false;
0354: }
0355:
0356: /**
0357: * This returns whether or not the text control is editable.
0358: * @return editable boolean flag
0359: */
0360: public boolean isEditable() {
0361: return m_bEditable;
0362: }
0363:
0364: /**
0365: * This returns whether or not the text control can receive focus.
0366: * Same thing as being editable.
0367: * @return focus traversable boolean flag
0368: */
0369: public boolean isFocusTraversable() {
0370: return m_bEditable;
0371: }
0372:
0373: /**
0374: * This returns whether or not the text class has been modified.
0375: * @return modified boolean flag
0376: */
0377: public boolean isModified() {
0378: return m_bModified;
0379: }
0380:
0381: private boolean isNotBreakChar(char c) {
0382: boolean res = true;
0383: switch (c) {
0384: case ' ':
0385: case ';':
0386: case ',':
0387: case '.':
0388: case '?':
0389: case '!':
0390: case ':':
0391: res = false;
0392: break;
0393: }
0394: return res;
0395: }
0396:
0397: /**
0398: * This returns whether or not the text control has a selection.
0399: * @return text selection boolean flag
0400: */
0401: public boolean isSelected() {
0402: for (int i = 0; i < m_vParagraphs.size(); i++)
0403: if (((Paragraph) m_vParagraphs.elementAt(i))
0404: .getSelectionState() != Paragraph.NONE)
0405: return true;
0406: return false;
0407: }
0408:
0409: /**
0410: * This is called whenever the text class loses focus.
0411: */
0412: protected void lostFocus() {
0413: if (m_bEditable) {
0414: stop();
0415:
0416: for (int i = 0; i < m_vParagraphs.size(); i++) {
0417: ((Paragraph) m_vParagraphs.elementAt(i))
0418: .setMarkVisible(false);
0419: }
0420:
0421: if (actionListener != null)
0422: actionListener.actionPerformed(actionEventEnter);
0423: repaint();
0424: }
0425: }
0426:
0427: /**
0428: * This is called whenever the clipboard's contents have been replaced.
0429: * @param clipboard - the clipboard
0430: * @param contents - the contents
0431: */
0432: public void lostOwnership(Clipboard clipboard, Transferable contents) {
0433: //System.out.println("Clipboard contents replaced");
0434: }
0435:
0436: /**
0437: * This is called whenever the user hits the backspace key.
0438: */
0439: protected void onBackspaceKey() {
0440: if (isSelected()) {
0441: cut(false);
0442: if (textListener != null)
0443: textListener.textValueChanged(textEvent);
0444: start();
0445: } else {
0446: Paragraph p = (Paragraph) m_vParagraphs
0447: .elementAt(cursorPoint.y);
0448: //if (p.getCursorPos()==0) return;
0449: //stop();
0450: if (getAllowHScroll() && p.getCursorPos() == 0) {
0451: if (p.getXOffset() > 0) {
0452: p.setXOffset(0);
0453: repaint();
0454: }
0455: return;
0456: } else {
0457: if (p.getCursorPos() == 0)
0458: return;
0459: }
0460:
0461: p.onBackspaceKey();
0462: if (textListener != null)
0463: textListener.textValueChanged(textEvent);
0464: //start();
0465: }
0466: repaint();
0467: }
0468:
0469: /**
0470: * This is called whenever the user hits the delete key.
0471: */
0472: protected void onDeleteKey() {
0473: if (isSelected()) {
0474: cut(false);
0475: if (textListener != null)
0476: textListener.textValueChanged(textEvent);
0477: start();
0478: } else {
0479: Paragraph p = (Paragraph) m_vParagraphs
0480: .elementAt(cursorPoint.y);
0481: if (p.isCursorAtEnd())
0482: return;
0483: p.onDeleteKey();
0484: if (textListener != null)
0485: textListener.textValueChanged(textEvent);
0486: }
0487: repaint();
0488: }
0489:
0490: /**
0491: * This is called whenever the user double-clicks on the text control.
0492: * (it selects a word)
0493: */
0494: protected void onDoubleClicked() {
0495: // select word
0496: selectWord();
0497: }
0498:
0499: /**
0500: * This is called whenever the user hits the down arrow key.
0501: * This has no effect in the Text class.
0502: * @param mod - any modifiers (SHIFT, CONTROL, etc)
0503: */
0504: protected void onDownKey(int mod) {
0505: return;
0506: }
0507:
0508: /**
0509: * This is called whenever the user hits the 'End' key.
0510: * @param mod - modifiers used when hitting the key
0511: */
0512: protected void onEndKey(int mod) {
0513: Paragraph p = (Paragraph) m_vParagraphs
0514: .elementAt(cursorPoint.y);
0515: int pos = p.getCursorPos();
0516: stop();
0517: String s = p.getText();
0518: p.setCursorPos(s.length());
0519: if ((p.getFontMetrics()).stringWidth(s) > (getSize().width)) {
0520: int n = (p.getFontMetrics()).stringWidth(s)
0521: - getSize().width + 15;
0522: p.setXOffset(n);
0523: }
0524: if (mod == Event.SHIFT_MASK) {
0525: if (p.getSelectionState() == Paragraph.NONE) {
0526: p.setSelectionState(Paragraph.PARTIAL);
0527: p.setSelectionStart(pos);
0528: selectionStart.x = pos;
0529: }
0530: selectionEnd.x = (p.getText()).length();
0531: p.setSelectionEnd((p.getText()).length());
0532: } else {
0533: if (p.getSelectionState() != Paragraph.NONE)
0534: p.setSelectionState(Paragraph.NONE);
0535: start();
0536: }
0537: repaint();
0538: }
0539:
0540: /**
0541: * This is called whenever the user hits the 'Enter' key. This fires off
0542: * two events, a TextEvent and an ActionEvent.
0543: */
0544: protected void onEnterKey() {
0545: if (textListener != null)
0546: textListener.textValueChanged(textEventEnter);
0547: if (actionListener != null)
0548: actionListener.actionPerformed(actionEventEnter);
0549: return;
0550: }
0551:
0552: /**
0553: * This is called whenever the user hits the 'Home' key.
0554: * @param mod - modifiers used when hitting the key
0555: */
0556: protected void onHomeKey(int mod) {
0557: Paragraph p = (Paragraph) m_vParagraphs
0558: .elementAt(cursorPoint.y);
0559: int pos = p.getCursorPos();
0560: stop();
0561: p.setCursorPos(0);
0562: p.setXOffset(0);
0563: if (mod == Event.SHIFT_MASK) {
0564: if (p.getSelectionState() == Paragraph.NONE) {
0565: p.setSelectionState(Paragraph.PARTIAL);
0566: p.setSelectionStart(pos);
0567: selectionStart.x = pos;
0568: }
0569: selectionEnd.x = 0;
0570: p.setSelectionEnd(0);
0571: } else {
0572: if (p.getSelectionState() != Paragraph.NONE)
0573: p.setSelectionState(Paragraph.NONE);
0574: start();
0575: }
0576: repaint();
0577: }
0578:
0579: /**
0580: * This is called whenever the user hits the left arrow key.
0581: * @param mod - modifiers used when hitting the key
0582: */
0583: protected void onLeftKey(int mod) {
0584: Paragraph p = (Paragraph) m_vParagraphs
0585: .elementAt(cursorPoint.y);
0586: int pos = p.getCursorPos();
0587: if (pos == 0) {
0588: if (p.getXOffset() > 0) {
0589: setXOffset(0);
0590: repaint();
0591: }
0592: return;
0593: }
0594: //stop();
0595: p.setCursorPos(--pos);
0596: /*if (m_bAllowHScroll) {
0597: p.onScrollAction();
0598: p.setPrevXOffset(p.getXOffset());
0599: }*/
0600: if (mod == Event.SHIFT_MASK) {
0601: if (p.getSelectionState() == Paragraph.NONE) {
0602: p.setSelectionState(Paragraph.PARTIAL);
0603: p.setSelectionStart(pos + 1);
0604: selectionStart.x = pos + 1;
0605: }
0606: selectionEnd.x = pos;
0607: p.setSelectionEnd(pos);
0608: } else {
0609: if (isSelected()) {
0610: p.setSelectionState(Paragraph.NONE);
0611: p.setCursorPos(Math.min(selectionStart.x,
0612: selectionEnd.x));
0613: }
0614: //start();
0615: }
0616:
0617: if (m_bAllowHScroll && getHAlign() == LEFT) {
0618: if (!isAutoWrap()
0619: && p.getCursorPoint().x < m_inTextInsets.left + 2) {
0620: int offset = p.getXOffset() - getSize().width / 2;
0621: if (offset < 0)
0622: offset = 0;
0623: p.setXOffset(offset);
0624: }
0625: }
0626:
0627: repaint();
0628: }
0629:
0630: public void setXOffset(int n) {
0631: Paragraph p = (Paragraph) m_vParagraphs
0632: .elementAt(cursorPoint.y);
0633: p.setXOffset(n);
0634: }
0635:
0636: /**
0637: * This is called whenever the cursor has been moved.
0638: */
0639: protected void onMovement() {
0640: repaint();
0641: }
0642:
0643: /**
0644: * This is called whenever the user hits the right arrow key.
0645: * @param mod - modifiers used when hitting the key
0646: */
0647: protected void onRightKey(int mod) {
0648: Paragraph p = (Paragraph) m_vParagraphs
0649: .elementAt(cursorPoint.y);
0650: int pos = p.getCursorPos();
0651: if (pos == (p.getText()).length())
0652: return;
0653: stop();
0654: p.setCursorPos(++pos);
0655: if (m_bAllowHScroll)
0656: p.onScrollAction();
0657: if (mod == Event.SHIFT_MASK) {
0658: if (p.getSelectionState() == Paragraph.NONE) {
0659: p.setSelectionState(Paragraph.PARTIAL);
0660: p.setSelectionStart(pos - 1);
0661: selectionStart.x = pos - 1;
0662: if (m_bAllowHScroll)
0663: p.setPrevXOffset(p.getXOffset());
0664: }
0665: selectionEnd.x = pos;
0666: p.setSelectionEnd(pos);
0667: } else {
0668: if (p.getSelectionState() != Paragraph.NONE) {
0669: p.setSelectionState(Paragraph.NONE);
0670: p.setCursorPos(Math.max(selectionStart.x,
0671: selectionEnd.x));
0672: }
0673: start();
0674: }
0675: repaint();
0676: }
0677:
0678: /**
0679: * This is called whenever the user clicks three times on the
0680: * text control, selecting all of the text.
0681: */
0682: protected void onTripleClicked() {
0683: selectAll();
0684: }
0685:
0686: /**
0687: * This is called whenever the user hits the up arrow key.
0688: * This has no effect on the Text class.
0689: * @param mod - modifiers used when hitting the key
0690: */
0691: protected void onUpKey(int mod) {
0692: return;
0693: }
0694:
0695: /**
0696: * This method is called by the Thread (in an editable and focused text control) to blink
0697: * the cursor.
0698: * @param b - whether to paint in the background or foreground (DEPRECATED)
0699: */
0700: protected void paintCursor(boolean b) {
0701: if (m_vParagraphs == null || cursorPoint.y < 0
0702: || cursorPoint.y > m_vParagraphs.size() - 1)
0703: return;
0704: Graphics g = getGraphics();
0705: if (g == null)
0706: return;
0707:
0708: Paragraph p = (Paragraph) m_vParagraphs
0709: .elementAt(cursorPoint.y);
0710: Point pt = p.getCursorPoint();
0711: if (y_offset == 0 && m_nVAlign != TOP) {
0712: int h1 = getSize().height;
0713: int h2 = 0;
0714: for (int i = 0; i < m_vParagraphs.size(); i++)
0715: h2 += ((Paragraph) m_vParagraphs.elementAt(i))
0716: .getYSpan();
0717: if (m_nVAlign == CENTER) {
0718: pt.y += ((h1 / 2) - (h2 / 2));
0719: } else if (m_nVAlign == BOTTOM) {
0720: pt.y += (h1 - h2) - m_inTextInsets.bottom;
0721: }
0722: }
0723: if (m_nVAlign == TOP)
0724: pt.y += m_inTextInsets.top;
0725: pt.y -= y_offset;
0726: Dimension d = getSize();
0727: for (int i = 0; i < cursorPoint.y; i++) {
0728: Paragraph pg = (Paragraph) m_vParagraphs.elementAt(i);
0729: if (!pg.isVisible())
0730: continue;
0731: pt.y += pg.getYSpan();
0732: }
0733: pt.x += 2;
0734: pt.y += 2;
0735:
0736: g.setXORMode(getBackground());
0737: Font f = p.getFont();
0738: if (f == null)
0739: f = getFont();
0740: FontMetrics fm = getFontMetrics(f);
0741: g.setColor(m_cCursorColor);
0742: int h = fm.getHeight() - 3;
0743: g.fillRect(pt.x, pt.y, m_nCursorWidth, h);
0744: g.setPaintMode();
0745: }
0746:
0747: /**
0748: * This is called to paste the clipboard's contents into the text control.
0749: */
0750: protected void paste() {
0751: Transferable content = clipboard.getContents(this );
0752:
0753: if (isSelected()) {
0754: cut(false);
0755: unselectAll();
0756: start();
0757: }
0758:
0759: if (content != null) {
0760: try {
0761: String data = (String) content
0762: .getTransferData(DataFlavor.stringFlavor);
0763: StringTokenizer st = new StringTokenizer(data, "\n",
0764: false);
0765: data = st.nextToken();
0766: Paragraph p = (Paragraph) m_vParagraphs
0767: .elementAt(cursorPoint.y);
0768: int pos = p.getCursorPos();
0769: String text = p.getText();
0770: String partb4 = text.substring(0, pos);
0771: String after = text.substring(pos);
0772: p.setText(partb4 + data);
0773: p.setCursorPos(pos + (data.length()));
0774: while (st.hasMoreTokens()) {
0775: String s = st.nextToken();
0776: p = new Paragraph(this , s);
0777: p.setFont(getFont());
0778: p.setFontMetrics(getFontMetrics(getFont()));
0779: p.setWidth(getSize().width - m_nWidthOffset);
0780: p.setForeground(getForeground());
0781: p.setBackground(getBackground());
0782: p.setInsets(m_inTextInsets);
0783: m_vParagraphs.insertElementAt(p, cursorPoint.y + 1);
0784: cursorPoint.y++;
0785: }
0786: p.setText(p.getText() + after);
0787: p
0788: .setCursorPos(((p.getText()).length() - after
0789: .length()));
0790: repaint();
0791: } catch (Exception e) {
0792: System.out.println("Couldn't get contents in format: "
0793: + DataFlavor.stringFlavor
0794: .getHumanPresentableName());
0795: }
0796: }
0797: }
0798:
0799: /**
0800: * This is called whenever an ActionEvent has been fired.
0801: * @param e - the ActionEvent fired
0802: */
0803: protected void processActionEvent(ActionEvent e) {
0804: if (actionListener != null) {
0805: actionListener.actionPerformed(e);
0806: }
0807: }
0808:
0809: /**
0810: * This is called whenever a FocusEvent has been fired.
0811: * @param e - the FocusEvent
0812: */
0813: protected void processFocusEvent(FocusEvent e) {
0814: super .processFocusEvent(e);
0815: if (e.getID() == Event.GOT_FOCUS) {
0816: gotFocus();
0817: } else if (e.getID() == Event.LOST_FOCUS) {
0818: lostFocus();
0819: }
0820: }
0821:
0822: /**
0823: * This is called whenever a KeyEvent is fired.
0824: * @param e - the KeyEvent
0825: */
0826: protected void processKeyEvent(KeyEvent e) {
0827: super .processKeyEvent(e);
0828: if (!m_bEditable)
0829: return;
0830: if (e.getID() == Event.KEY_PRESS) {
0831: int key = e.getKeyCode();
0832: // if it's escape
0833: if (key == KeyEvent.VK_ESCAPE) {
0834: }
0835: // else if it's tab
0836: else if (key == KeyEvent.VK_TAB) {
0837: transferFocus();
0838: }
0839: // else if it's left
0840: else if (key == KeyEvent.VK_LEFT) {
0841: onLeftKey(e.getModifiers());
0842: }
0843: // else if it's right
0844: else if (key == KeyEvent.VK_RIGHT) {
0845: onRightKey(e.getModifiers());
0846: }
0847: // else if it's up
0848: else if (key == KeyEvent.VK_UP) {
0849: onUpKey(e.getModifiers());
0850: }
0851: // else if it's down
0852: else if (key == KeyEvent.VK_DOWN) {
0853: onDownKey(e.getModifiers());
0854: }
0855: // else if it's home
0856: else if (key == KeyEvent.VK_HOME) {
0857: onHomeKey(e.getModifiers());
0858: }
0859: // else if it's end
0860: else if (key == KeyEvent.VK_END) {
0861: onEndKey(e.getModifiers());
0862: }
0863: // else if it's backspace
0864: else if (key == KeyEvent.VK_BACK_SPACE) {
0865: onBackspaceKey();
0866: }
0867: // else if it's delete
0868: else if (key == KeyEvent.VK_DELETE) {
0869: onDeleteKey();
0870: }
0871: // else if it's enter
0872: else if (key == KeyEvent.VK_ENTER) {
0873: onEnterKey();
0874: }
0875: // else if it's page up
0876: else if (key == KeyEvent.VK_PAGE_UP) {
0877: }
0878: // else if it's page down
0879: else if (key == KeyEvent.VK_PAGE_DOWN) {
0880: }
0881: // else if it's ctrl-c
0882: else if (e.getModifiers() == Event.CTRL_MASK
0883: && key == KeyEvent.VK_C) {
0884: copy();
0885: }
0886: // else if it's ctrl-x
0887: else if (e.getModifiers() == Event.CTRL_MASK
0888: && key == KeyEvent.VK_X) {
0889: cut(true);
0890: }
0891: // else if it's ctrl-v
0892: else if (e.getModifiers() == Event.CTRL_MASK
0893: && key == KeyEvent.VK_V) {
0894: paste();
0895: }
0896: // else post it to the paragraph
0897: else {
0898: insertChar((char) e.getKeyChar());
0899: }
0900: }
0901: }
0902:
0903: /**
0904: * This is called whenever a MouseEvent has been fired.
0905: * @param e - the MouseEvent
0906: */
0907: protected void processMouseEvent(MouseEvent e) {
0908: super .processMouseEvent(e);
0909: if (!m_bEditable)
0910: return;
0911: Point p = e.getPoint();
0912: if (e.getID() == Event.MOUSE_DOWN) {
0913: this .requestFocus();
0914: setCursorPosition(p.x, p.y);
0915: unselectAll();
0916: repaint();
0917: try {
0918: start();
0919: } catch (Exception ex) {
0920: ;
0921: }
0922: if (e.getClickCount() == 2) {
0923: onDoubleClicked();
0924: } else if (e.getClickCount() == 3) {
0925: onTripleClicked();
0926: }
0927: }
0928: }
0929:
0930: /**
0931: * This method is called whenever a MouseEvent has been fired with
0932: * motion involved.
0933: * @param e - the MouseEvent
0934: */
0935: protected void processMouseMotionEvent(MouseEvent e) {
0936: super .processMouseMotionEvent(e);
0937: if (!m_bEditable)
0938: return;
0939: Point pt = e.getPoint();
0940: if (e.getID() == Event.MOUSE_DRAG) {
0941: stop();
0942: Paragraph pg = findParagraph(pt.y, true);
0943: pt.x -= m_inTextInsets.left;
0944: selectionEnd.y = m_vParagraphs.indexOf(pg);
0945:
0946: // have to adjust p's 'y'
0947: pt.y += y_offset;
0948: for (int i = 0; i < selectionEnd.y; i++)
0949: pt.y -= ((Paragraph) m_vParagraphs.elementAt(i))
0950: .getYSpan();
0951: if (y_offset == 0 && m_nVAlign != TOP) {
0952: int h1 = getSize().height;
0953: int h2 = 0;
0954: for (int i = 0; i < m_vParagraphs.size(); i++)
0955: h2 += ((Paragraph) m_vParagraphs.elementAt(i))
0956: .getYSpan();
0957: if (m_nVAlign == CENTER) {
0958: pt.y -= (h1 - h2) / 2;
0959: } else if (m_nVAlign == BOTTOM) {
0960: pt.y -= (h1 - h2);
0961: }
0962: }
0963: selectionEnd.x = pg.getCursorPosFromPoint(pt);
0964: pg.setCursorPos(selectionEnd.x);
0965: cursorPoint.y = selectionEnd.y;
0966: cursorPoint.x = selectionEnd.x;
0967: if (m_bAllowHScroll)
0968: pg.onScrollAction();
0969: // now set the states of selection
0970: Point start, end;
0971: start = new Point(selectionStart);
0972: end = new Point(selectionEnd);
0973: if (end.y < start.y
0974: || (end.y == start.y && end.x < start.x)) {
0975: Point temp = new Point(start);
0976: start = end;
0977: end = temp;
0978: }
0979: for (int i = 0; i < m_vParagraphs.size(); i++) {
0980: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
0981: if (i < start.y || i > end.y)
0982: p.setSelectionState(Paragraph.NONE);
0983: else {
0984: if (start.y == end.y) {
0985: p.setSelectionState(Paragraph.PARTIAL);
0986: p.setSelectionStart(start.x);
0987: p.setSelectionEnd(end.x);
0988: } else {
0989: for (int j = start.y; j <= end.y; j++) {
0990: Paragraph pp = (Paragraph) m_vParagraphs
0991: .elementAt(j);
0992: if (j == start.y) {
0993: pp.setSelectionState(Paragraph.PARTIAL);
0994: pp.setSelectionStart(start.x);
0995: pp.setSelectionEnd((pp.getText())
0996: .length());
0997: } else if (j == end.y) {
0998: pp.setSelectionState(Paragraph.PARTIAL);
0999: pp.setSelectionStart(0);
1000: pp.setSelectionEnd(end.x);
1001: } else {
1002: pp
1003: .setSelectionState(Paragraph.COMPLETE);
1004: }
1005: }
1006: i = end.y;
1007: }
1008: }
1009: }
1010: repaint();
1011: }
1012: }
1013:
1014: /**
1015: * This method removes the ActionListener from Text's list.
1016: * @param l - the listener to remove
1017: */
1018: public void removeActionListener(ActionListener l) {
1019: actionListener = AWTEventMulticaster.remove(actionListener, l);
1020: }
1021:
1022: /**
1023: * This removes the TextListener from Text's list.
1024: * @param l - the listener to remove
1025: */
1026: public void removeTextListener(TextListener l) {
1027: textListener = AWTEventMulticaster.remove(textListener, l);
1028: }
1029:
1030: /**
1031: * This is the Thread's runtime, which calls paintCursor in a loop.
1032: * @see #paintCursor
1033: */
1034: public void run() {
1035: boolean blink = true;
1036: while (true) {
1037: paintCursor(blink);
1038: blink = !blink;
1039: try {
1040: Thread.sleep(500);
1041: } catch (InterruptedException e) {
1042: ;
1043: }
1044: }
1045: }
1046:
1047: /**
1048: * This method selects text from the first position to the second.
1049: * @param from - the first position
1050: * @param to - the second position
1051: */
1052: public void select(int from, int to) {
1053: if (m_vParagraphs == null || m_vParagraphs.size() == 0)
1054: return;
1055: stop();
1056: selectionStart = new Point(from, 0);
1057: selectionEnd = new Point(to, 0);
1058: Paragraph p = (Paragraph) m_vParagraphs.firstElement();
1059: p.setSelectionStart(from);
1060: p.setSelectionEnd(to);
1061: p.setCursorPos(to);
1062: if (from == to) {
1063: p.setSelectionState(Paragraph.NONE);
1064: start();
1065: } else
1066: p.setSelectionState(Paragraph.PARTIAL);
1067: repaint();
1068: }
1069:
1070: /**
1071: * This method selects all the text within the Text control
1072: */
1073: public void selectAll() {
1074: stop();
1075: selectionStart = new Point(0, 0);
1076: selectionEnd = new Point((((Paragraph) m_vParagraphs
1077: .lastElement()).getText().length()), (m_vParagraphs
1078: .size() - 1));
1079: for (int i = 0; i < m_vParagraphs.size(); i++) {
1080: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
1081: p.setSelectionState(Paragraph.COMPLETE);
1082: p.setMarkVisible(true);
1083: }
1084: repaint();
1085: }
1086:
1087: /**
1088: * This method selects the word closest to where the cursor is
1089: * currently located.
1090: */
1091: public void selectWord() {
1092: Paragraph p = (Paragraph) m_vParagraphs
1093: .elementAt(cursorPoint.y);
1094: String s = p.getText();
1095: if (s.length() == 0)
1096: return;
1097: stop();
1098: // now figure out the start/end of selection
1099: int start = cursorPoint.x;
1100: int end = cursorPoint.x;
1101: if (end == 0)
1102: end = 1;
1103: while (start > 0 && isNotBreakChar(s.charAt(start - 1)))
1104: start--;
1105: while (end < s.length() && isNotBreakChar(s.charAt(end)))
1106: end++;
1107: selectionStart = new Point(start, cursorPoint.y);
1108: selectionEnd = new Point(end, cursorPoint.y);
1109: p.setSelectionState(Paragraph.PARTIAL);
1110: p.setSelectionStart(start);
1111: p.setSelectionEnd(end);
1112: repaint();
1113: }
1114:
1115: /**
1116: * This sets whether or not the 'Enter' key is allowed in the Text
1117: * control.
1118: * This method has no effect in the Text class.
1119: * @param b - allow enter boolean flag
1120: */
1121: public void setAllowEnter(boolean b) {
1122: return;
1123: }
1124:
1125: /**
1126: * This sets whether or not to allow horizontal scrolling within the text
1127: * control.
1128: * @param b - horizontal scrolling behavior
1129: */
1130: public void setAllowHScroll(boolean b) {
1131: //if (m_bAllowHScroll==b) return;
1132: m_bAllowHScroll = b && getHAlign() == LEFT && !isAutoWrap();
1133:
1134: for (int i = 0; i < m_vParagraphs.size(); i++) {
1135: Paragraph p = (Paragraph) m_vParagraphs.elementAt(i);
1136: p.setAllowScroll(m_bAllowHScroll);
1137: }
1138: }
1139:
1140: /**
1141: * This sets the clipboard of the Text class, used for cut, copy, and
1142: * paste functionality. This is good to set from an app, since the
1143: * text control cannot get the system clipboard w/o raising security
1144: * precautions. This way, a common clipboard can be used between
1145: * different text controls.
1146: * @param bd - the clipboard
1147: */
1148: public void setClipboard(Clipboard bd) {
1149: clipboard = bd;
1150: }
1151:
1152: /**
1153: * This sets the text contents of the clipboard.
1154: * @param text - the contents of the clipboard
1155: */
1156: protected void setClipboardText(String text) {
1157: if (text != null) {
1158: StringSelection contents = new StringSelection(text);
1159: clipboard.setContents(contents, this );
1160: }
1161: }
1162:
1163: /**
1164: * This sets the position of the cursor.
1165: * @param x - the position of the cursor
1166: */
1167: public void setCursorPos(int x) {
1168: ((Paragraph) m_vParagraphs.elementAt(cursorPoint.y))
1169: .setCursorPos(x);
1170: cursorPoint.x = x;
1171: }
1172:
1173: /**
1174: * This sets the cursor position, given an x,y coordinate set.
1175: * This method is used from mouse events.
1176: * @param x - x coordinate
1177: * @param y - y coordinate
1178: */
1179: protected void setCursorPosition(int x, int y) {
1180: y -= m_inTextInsets.top;
1181: if (y_offset == 0 && m_nVAlign != TOP) {
1182: int h1 = getSize().height;
1183: int h2 = 0;
1184: for (int i = 0; i < m_vParagraphs.size(); i++)
1185: h2 += ((Paragraph) m_vParagraphs.elementAt(i))
1186: .getYSpan();
1187: if (m_nVAlign == CENTER) {
1188: y -= (h1 - h2) / 2;
1189: } else if (m_nVAlign == BOTTOM) {
1190: y -= (h1 - h2);
1191: }
1192: }
1193: Point p = new Point(x, y);
1194: Paragraph pg = findParagraph(p.y, true);
1195: cursorPoint.y = m_vParagraphs.indexOf(pg);
1196: p.y -= m_inTextInsets.top;
1197: // have to adjust p's 'y'
1198: p.y += y_offset;
1199: for (int i = 0; i < cursorPoint.y; i++)
1200: p.y -= ((Paragraph) m_vParagraphs.elementAt(i)).getYSpan();
1201: cursorPoint.x = pg.getCursorPosFromPoint(p);
1202: pg.setCursorPos(cursorPoint.x);
1203: selectionStart.x = cursorPoint.x;
1204: selectionStart.y = cursorPoint.y;
1205:
1206: // lwang
1207: selectionEnd.x = cursorPoint.x;
1208: selectionEnd.y = cursorPoint.y;
1209: }
1210:
1211: /**
1212: * This sets the width of the cursor.
1213: * @param w - width of the cursor
1214: */
1215: public void setCursorWidth(int w) {
1216: if (w < 0)
1217: return;
1218: m_nCursorWidth = w;
1219: }
1220:
1221: /**
1222: * This sets whether or not the text control is editable.
1223: * @param b - editable boolean flag
1224: */
1225: public void setEditable(boolean b) {
1226: m_bEditable = b;
1227: }
1228:
1229: /**
1230: * This sets the horizontal alignment of the text control
1231: * @param align - horizontal alignment
1232: * @see ob.text.OBLabel#setHAlign
1233: */
1234: public void setHAlign(int align) {
1235: if (align != LEFT) {
1236: setAllowHScroll(false);
1237: }
1238:
1239: super .setHAlign(align);
1240: }
1241:
1242: /**
1243: * This sets the modified flag of the text control.
1244: * @param b - modification flag
1245: */
1246: public void setModified(boolean b) {
1247: m_bModified = b;
1248: }
1249:
1250: /**
1251: * This sets the text of the text control. This is overridden to ensure
1252: * newlines don't break this control into a multiline control.
1253: * @param t - text to set in the control
1254: * @param repaint - whether or not to repaint the control afterwards
1255: * @see ob.text.OBLabel#setText
1256: */
1257: public void setText(String t, boolean repaint) {
1258: if (t == null)
1259: t = "";
1260: if (m_vParagraphs.size() > 0)
1261: m_vParagraphs.removeAllElements();
1262: Paragraph p = new Paragraph(this , t);
1263: p.setFont(getFont());
1264: p.setFontMetrics(getFontMetrics(getFont()));
1265: p.setBackground(getBackground());
1266: p.setForeground(getForeground());
1267: p.setWidth(getSize().width - m_nWidthOffset);
1268: p.setInsets(m_inTextInsets);
1269: p.setHAlign(getHAlign());
1270: p.setAutoWrap(isAutoWrap());
1271: p.setAllowScroll(getAllowHScroll());
1272: m_vParagraphs.addElement(p);
1273:
1274: if (repaint)
1275: repaint();
1276: }
1277:
1278: /**
1279: * This is called whenever the Thread that runs the cursor is started.
1280: */
1281: public void start() {
1282: if (this == null)
1283: return;
1284: if (m_tCursor == null) {
1285: m_tCursor = new Thread(this );
1286: m_tCursor.start();
1287: }
1288: }
1289:
1290: /**
1291: * This is called whenever the Thread that runs the cursor is stopped.
1292: */
1293: public void stop() {
1294: if (m_tCursor != null) {
1295: m_tCursor.stop();
1296: m_tCursor = null;
1297: }
1298: }
1299:
1300: /**
1301: * This method unselects the text control.
1302: */
1303: protected void unselectAll() {
1304: for (int i = 0; i < m_vParagraphs.size(); i++)
1305: ((Paragraph) m_vParagraphs.elementAt(i))
1306: .setSelectionState(Paragraph.NONE);
1307: }
1308:
1309: /**
1310: * This is a backwards compatible method to update/repaint the
1311: * text control.
1312: */
1313: public void update() {
1314: repaint();
1315: }
1316:
1317: /**
1318: * This method is used by other classes to break up the string
1319: * into a Vector of wrapped lines.
1320: * @param string - string to be broken up
1321: * @param width - the width (in pixels) to allow a string to be carried to
1322: * @param bAutoWrap - whether or not to break a line on the width or newline or just a newline
1323: * @param fm - the FontMetrics of the string
1324: */
1325: public static Vector wrapText(String string, int width,
1326: boolean bAutoWrap, FontMetrics fm) {
1327:
1328: // store the wraped text.
1329: Vector v = new Vector();
1330:
1331: int first = 0;
1332: int nStringLength = 0;
1333:
1334: if (bAutoWrap) {
1335: for (int i = 0; i < string.length(); i++) {
1336:
1337: // if the control is in autowrap state, we get a new line of text whenever we
1338: // reach a new line character or reach the right edge of the control.
1339: //if (string.charAt(i)=='\n'||fm.stringWidth(string.substring(first,i+1))>width) {
1340: nStringLength += fm.charWidth(string.charAt(i));
1341:
1342: if (string.charAt(i) == '\n' || nStringLength > width) {
1343:
1344: // word wrap
1345: int nWord = i;
1346: while (nWord > first
1347: && string.charAt(nWord) != '\n'
1348: && string.charAt(nWord) != ' ')
1349: nWord--;
1350: if (nWord == first)
1351: nWord = i;
1352:
1353: if (nWord != first)
1354: v.addElement(string.substring(first, nWord));
1355: first = (string.charAt(nWord) == '\n' || string
1356: .charAt(nWord) == ' ') ? nWord + 1 : nWord; // skip the new line character.
1357:
1358: // prepare for next line
1359: if (first < i) {
1360: nStringLength = fm.stringWidth(string
1361: .substring(first, i + 1));
1362: } else {
1363: nStringLength = fm.charWidth(string.charAt(i));
1364: }
1365: }
1366: }
1367: } else {
1368: for (int i = 0; i < string.length(); i++) {
1369:
1370: // if the control is not in autowrap state, we get a new line of text only when we
1371: // reach a new line character.
1372: if (string.charAt(i) == '\n') {
1373: v.addElement(string.substring(first, i));
1374: first = i + 1;
1375: }
1376: }
1377: }
1378:
1379: if (first < string.length()) {
1380: v.addElement(string.substring(first));
1381: } else {
1382: v.addElement(new String());
1383: }
1384:
1385: return v;
1386: }
1387: }
|