/** Clear any styles applied to the selected text. */
  public void clearSelectionStyle() {
    if (!hasSelection()) return;
    TextLayoutHitInfo startSelTLHI;
    TextLayoutHitInfo endSelTLHI;
    if (endTLHI.compareTo(startTLHI) == -1) {
      startSelTLHI = endTLHI;
      endSelTLHI = startTLHI;
    } else {
      startSelTLHI = startTLHI;
      endSelTLHI = endTLHI;
    }
    int ss = startSelTLHI.tli.startCharIndex + startSelTLHI.thi.getInsertionIndex();
    int ee = endSelTLHI.tli.startCharIndex + endSelTLHI.thi.getInsertionIndex();
    stext.clearAttributes(ss, ee);

    // We have modified the text style so the end of the selection may have
    // moved, so it needs to be recalculated. The start will be unaffected.
    stext.getLines(buffer.g2);
    endSelTLHI.tli = stext.getTLIforCharNo(ee);
    int cn = ee - endSelTLHI.tli.startCharIndex;
    if (cn == 0) // start of line
    endSelTLHI.thi = endSelTLHI.tli.layout.getNextLeftHit(1);
    else endSelTLHI.thi = endSelTLHI.tli.layout.getNextRightHit(cn - 1);
    bufferInvalid = true;
  }
 /**
  * Move caret right by one character.
  *
  * @param currPos the current position of the caret
  * @return true if caret moved else false
  */
 protected boolean moveCaretRight(TextLayoutHitInfo currPos) {
   TextHitInfo nthi = currPos.tli.layout.getNextRightHit(currPos.thi);
   if (nthi == null) {
     return false;
   } else {
     currPos.thi = nthi;
   }
   return true;
 }
  // Only executed if text has changed
  protected boolean changeText() {
    TextLayoutInfo tli;
    TextHitInfo thi = null, thiRight = null;

    pos += adjust;
    // Force layouts to be updated
    stext.getLines(buffer.g2);

    // Try to get text layout info for the current position
    tli = stext.getTLIforCharNo(pos);
    if (tli == null) {
      // If unable to get a layout for pos then reset everything
      endTLHI = null;
      startTLHI = null;
      ptx = pty = 0;
      caretX = caretY = 0;
      return false;
    }
    // We have a text layout so we can do something
    // First find the position in line
    int posInLine = pos - tli.startCharIndex;

    // Get some hit info so we can see what is happening
    try {
      thiRight = tli.layout.getNextRightHit(posInLine);
    } catch (Exception excp) {
      thiRight = null;
    }

    if (posInLine <= 0) { // At start of line
      thi = tli.layout.getNextLeftHit(thiRight);
    } else if (posInLine >= tli.nbrChars) { // End of line
      thi = tli.layout.getNextRightHit(tli.nbrChars - 1);
    } else { // Character in line;
      thi = tli.layout.getNextLeftHit(thiRight);
    }

    endTLHI.setInfo(tli, thi);
    // Cursor at end of paragraph graphic
    calculateCaretPos(endTLHI);

    //			// Is do we have to move cursor to start of next line
    //			if(newline) {
    //				if(pos >= stext.length()){
    //					stext.insertCharacters(pos, " ");
    //					stext.getLines(buffer.g2);
    //				}
    //				moveCaretRight(endTLHI);
    //				calculateCaretPos(endTLHI);
    //			}
    //			// Finish off by ensuring no selection, invalidate buffer etc.
    //			startTLHI.copyFrom(endTLHI);
    //		}
    bufferInvalid = true;
    return true;
  }
 /**
  * Move caret left by one character.
  *
  * @param currPos the current position of the caret
  * @return true if caret moved else false
  */
 protected boolean moveCaretLeft(TextLayoutHitInfo currPos) {
   TextHitInfo nthi = currPos.tli.layout.getNextLeftHit(currPos.thi);
   if (nthi == null) {
     return false;
   } else {
     // Move the caret to the left of current position
     currPos.thi = nthi;
   }
   return true;
 }
  /**
   * Determines whether this component is to have focus or not. <br>
   * Fire focus events for the GTextField and GTextArea controls
   *
   * @param focus
   */
  public void setFocus(boolean focus) {
    if (!focus) {
      loseFocus(null);
      return;
    }
    // Make sure we have some text
    if (focusIsWith != this) {
      dragging = false;
      if (stext == null || stext.length() == 0) stext = new StyledString(" ", wrapWidth);
      //			text = stext.getPlainText();
      LinkedList<TextLayoutInfo> lines = stext.getLines(buffer.g2);
      startTLHI = new TextLayoutHitInfo(lines.getFirst(), null);
      startTLHI.thi = startTLHI.tli.layout.getNextLeftHit(1);

      endTLHI = new TextLayoutHitInfo(lines.getLast(), null);
      int lastChar = endTLHI.tli.layout.getCharacterCount();
      endTLHI.thi = startTLHI.tli.layout.getNextRightHit(lastChar - 1);

      calculateCaretPos(endTLHI);
      bufferInvalid = true;
    }
    keepCursorInView = true;
    takeFocus();
  }
 /**
  * Get the text that has been selected (highlighted) by the user. <br>
  *
  * @return the selected text without styling
  */
 public String getSelectedText() {
   if (!hasSelection()) return "";
   TextLayoutHitInfo startSelTLHI;
   TextLayoutHitInfo endSelTLHI;
   if (endTLHI.compareTo(startTLHI) == -1) {
     startSelTLHI = endTLHI;
     endSelTLHI = startTLHI;
   } else {
     startSelTLHI = startTLHI;
     endSelTLHI = endTLHI;
   }
   int ss = startSelTLHI.tli.startCharIndex + startSelTLHI.thi.getInsertionIndex();
   int ee = endSelTLHI.tli.startCharIndex + endSelTLHI.thi.getInsertionIndex();
   String s = stext.getPlainText().substring(ss, ee);
   return s;
 }
  /**
   * Load the styled string to be used by this control. <br>
   * It will also restore any text selection saved with the text.
   *
   * @param fname the name of the file to use
   * @return true if loaded successfully else false
   */
  public boolean loadText(String fname) {
    StyledString ss = StyledString.load(winApp, fname);
    if (ss == null) return false;
    setStyledText(ss);
    // Now restore any text selection
    if (stext.startIdx >= 0) { // we have a selection
      // Selection starts at ...
      startTLHI = new TextLayoutHitInfo();
      startTLHI.tli = stext.getTLIforCharNo(stext.startIdx);
      int pInLayout = stext.startIdx - startTLHI.tli.startCharIndex;
      if (pInLayout == 0) startTLHI.thi = startTLHI.tli.layout.getNextLeftHit(1);
      else startTLHI.thi = startTLHI.tli.layout.getNextRightHit(pInLayout - 1);
      // Selection ends at ...
      endTLHI = new TextLayoutHitInfo();
      endTLHI.tli = stext.getTLIforCharNo(stext.endIdx);
      pInLayout = stext.endIdx - endTLHI.tli.startCharIndex;

      if (pInLayout == 0) endTLHI.thi = endTLHI.tli.layout.getNextLeftHit(1);
      else endTLHI.thi = endTLHI.tli.layout.getNextRightHit(pInLayout - 1);
      calculateCaretPos(endTLHI);
    }
    bufferInvalid = true;
    return true;
  }
 /**
  * Find out if some text is selected (highlighted)
  *
  * @return true if some text is selected else false
  */
 public boolean hasSelection() {
   return (startTLHI.tli != null && endTLHI.tli != null && startTLHI.compareTo(endTLHI) != 0);
 }
 /**
  * Move caret to the end of the line that has the current caret position
  *
  * @param currPos the current position of the caret
  * @return true if caret moved else false
  */
 protected boolean moveCaretEndOfLine(TextLayoutHitInfo currPos) {
   if (currPos.thi.getCharIndex() == currPos.tli.nbrChars - 1)
     return false; // already at end of line
   currPos.thi = currPos.tli.layout.getNextRightHit(currPos.tli.nbrChars - 1);
   return true;
 }
 /**
  * Move caret to home position
  *
  * @param currPos the current position of the caret
  * @return true if caret moved else false
  */
 protected boolean moveCaretStartOfLine(TextLayoutHitInfo currPos) {
   if (currPos.thi.getCharIndex() == 0) return false; // already at start of line
   currPos.thi = currPos.tli.layout.getNextLeftHit(1);
   return true;
 }