Package limelight.ui.model.text

Source Code of limelight.ui.model.text.TextModel

//- Copyright © 2008-2011 8th Light, Inc. All Rights Reserved.
//- Limelight and all included source files are distributed under terms of the MIT License.

package limelight.ui.model.text;

import limelight.styles.abstrstyling.HorizontalAlignmentValue;
import limelight.styles.abstrstyling.VerticalAlignmentValue;
import limelight.ui.Fonts;
import limelight.ui.model.TextPanel;
import limelight.ui.model.text.masking.IdentityMask;
import limelight.ui.model.text.masking.TextMask;
import limelight.ui.model.text.offsetting.XOffsetStrategy;
import limelight.ui.model.text.offsetting.YOffsetStrategy;
import limelight.ui.text.TextLocation;
import limelight.ui.text.TextTypedLayoutFactory;
import limelight.ui.text.TypedLayout;
import limelight.ui.text.TypedLayoutFactory;
import limelight.util.Box;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

public abstract class TextModel implements ClipboardOwner
{
  private limelight.ui.model.text.TextContainer container;
  private StringBuffer text = new StringBuffer(); // TODO MDM Storing the text in both StringBuffer and List of TextLayouts leads to some major inefficiencies.  Should make an attempt to get rid of StringBuffer.
  private ArrayList<TypedLayout> lines;
  private Point offset = new Point(0, 0);
  private boolean caretOn;
  private TypedLayoutFactory typedLayoutFactory = TextTypedLayoutFactory.instance;
  private TextLocation caretLocation = TextLocation.at(0, 0);
  private boolean selectionActivated;
  private TextLocation selectionLocation = TextLocation.at(0, 0);
  private TextLocation verticalOrigin;
  private boolean changeFlag;
  private TextMask mask = IdentityMask.instance;

  public abstract Box getCaretShape();

  public abstract Dimension getTextDimensions();

  public abstract TextLocation getLocationAt(Point point);

  public abstract ArrayList<Box> getSelectionRegions();

  protected abstract void buildLines(ArrayList<TypedLayout> lines);

  protected abstract XOffsetStrategy getDefaultXOffsetStrategy();

  protected abstract YOffsetStrategy getDefaultYOffsetStrategy();

  public TextModel(limelight.ui.model.text.TextContainer container)
  {
    this.container = container;
  }

  public Font getFont()
  {
    // TODO MDM This is inefficient... should cache value
    return Fonts.fromStyle(container.getStyle());
  }


  public boolean isCaretOn()
  {
    return caretOn;
  }

  public void setCaretOn(boolean value)
  {
    caretOn = value;
  }

  public synchronized final ArrayList<TypedLayout> getLines()
  {
    if(lines == null)
    {
      lines = new ArrayList<TypedLayout>();
      buildLines(lines);
    }
    return lines;
  }

  public int getXOffset()
  {
    return offset.x;
  }

  public int getXOffset(TypedLayout line)
  {
    HorizontalAlignmentValue horizontalAlignment = getContainer().getStyle().getCompiledHorizontalAlignment();
    return horizontalAlignment.getX(line.getWidth(), getContainer().getConsumableBounds());
  }

  public int getYOffset()
  {
    return offset.y;
  }

  public int getX(int index)
  {
    TextLocation location = TextLocation.fromIndex(getLines(), index);
    return getX(location);
  }

  public int getX(TextLocation location)
  {
    return getAbsoluteX(location) + getXOffset();
  }

  public int getAbsoluteX(TextLocation location)
  {
    return getLines().get(location.line).getX(location.index);
  }

  public int getY(TextLocation location)
  {
    return getAbsoluteY(location) + getYOffset();
  }

  public int getAbsoluteY(TextLocation location)
  {
    int height = 0;
    for(int i = 0; i < location.line; i++)
    {
      TypedLayout layout = getLines().get(i);
      height += layout.getHeightWithLeading();
    }
    return height;
  }

  public void recalculateOffset(XOffsetStrategy xOffsetStrategy, YOffsetStrategy yOffsetStrategy)
  {
    Box boundingBox = getContainer().getConsumableBounds();
    Dimension textDimensions = getTextDimensions();

    int xOffset, yOffset;
    if(textDimensions.width < boundingBox.width)
      xOffset = getHorizontalAlignment().getX(textDimensions.width, boundingBox);
    else
      xOffset = xOffsetStrategy.calculateXOffset(this);

    if(textDimensions.height < boundingBox.height)
      yOffset = getVerticalAlignment().getY(textDimensions.height, boundingBox);
    else
      yOffset = yOffsetStrategy.calculateYOffset(this);

    setOffset(xOffset, yOffset);
  }

  public synchronized void clearCache()
  {
    changeFlag = true;
    lines = null;
  }

  public VerticalAlignmentValue getVerticalAlignment()
  {
    return container.getStyle().getCompiledVerticalAlignment();
  }

  public HorizontalAlignmentValue getHorizontalAlignment()
  {
    return container.getStyle().getCompiledHorizontalAlignment();
  }

  public boolean hasFocus()
  {
    return container.hasFocus();
  }

  public String getClipboardContents()
  {
    Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
    if(contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor))
    {
      try
      {
        return (String) contents.getTransferData(DataFlavor.stringFlavor);
      }
      catch(Exception e)
      {
        return "";
      }
    }
    return "";
  }

  public void copySelection()
  {
    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(getSelectedText()), this);
  }

  public void pasteClipboard()
  {
    String clipboard = getClipboardContents();
    if(clipboard != null && clipboard.length() > 0)
    {
      int caretIndex = caretLocation.toIndex(getLines());
      synchronized(this)
      {
        text.insert(caretIndex, clipboard);
        clearCache();
      }
      setCaretLocation(TextLocation.fromIndex(getLines(), caretIndex + clipboard.length()));
    }
  }

  public void cutSelection()
  {
    if(!selectionActivated)
      return;

    copySelection();
    deleteSelection();
  }

  public void deleteSelection()
  {
    if(!selectionActivated)
      return;

    deleteEnclosedText(getSelectionStart(), getSelectionEnd());
    deactivateSelection();
  }

  public void deleteEnclosedText(TextLocation start, TextLocation end)
  {
    ArrayList<TypedLayout> lines = getLines();
    int startIndex = start.toIndex(lines);
    int endIndex = end.toIndex(lines);
    synchronized(this)
    {
      text.delete(startIndex, endIndex);
      clearCache();
    }
    setCaretLocation(start);
    setSelectionLocation(start);
  }

  public TextLocation findWordsRightEdge(TextLocation location)
  {

    for(int i = location.toIndex(getLines()); i <= text.length() - 1; i++)
    {
      if(i == 0)
        i = 1;
      if(isAtEndOfWord(i))
        return TextLocation.fromIndex(getLines(), i);
    }
    return getEndLocation();
  }

  public TextLocation findWordsLeftEdge(TextLocation location)
  {
    for(int i = location.toIndex(getLines()); i > 1; i--)
    {
      if(isAtStartOfWord(i))
        return TextLocation.fromIndex(getLines(), i);
    }
    return TextLocation.origin;
  }

  public boolean isAtEndOfWord(int i)
  {
    return text.charAt(i - 1) != ' ' && text.charAt(i - 1) != '\n' && (text.charAt(i) == ' ' || text.charAt(i) == '\n');
  }

  public boolean isAtStartOfWord(int i)
  {
    if(i < 0 || i > getText().length())
      return true;
    return (text.charAt(i - 1) == ' ' || text.charAt(i - 1) == '\n') && (text.charAt(i) != ' ' && text.charAt(i) != '\n');
  }

  public TextLocation getCaretLocation()
  {
    return caretLocation;
  }

  public void setCaretLocation(TextLocation location)
  {
    setCaretLocation(location, getDefaultXOffsetStrategy(), getDefaultYOffsetStrategy());
  }

  public void setCaretLocation(TextLocation location, XOffsetStrategy xOffsetStrategy, YOffsetStrategy yOffsetStrategy)
  {
    caretLocation = location;
    verticalOrigin = null;
    recalculateOffset(xOffsetStrategy, yOffsetStrategy);
  }

  public TextLocation getSelectionLocation()
  {
    return selectionLocation;
  }

  public void setSelectionLocation(TextLocation location)
  {
    selectionLocation = location;
  }

  public synchronized void setText(String newText)
  {
    if(newText == null)
      newText = "";

    if(newText.length() == text.length() && newText.equals(getText()))
      return;

    text = new StringBuffer(newText);
    clearCache();
    setCaretLocation(getEndLocation());
  }

  public String getText()
  {
    return text.toString();
  }

  public String getDisplayableText()
  {
    return mask.mask(getText());
  }

  public boolean hasText()
  {
    return text != null && text.length() > 0;
  }

  public synchronized void insertChar(char c)
  {
    if(c == KeyEvent.CHAR_UNDEFINED)
      return;
    if(selectionActivated)
      deleteSelection();
    text.insert(getCaretLocation().toIndex(getLines()), c);
    clearCache();
    setCaretLocation(getCaretLocation().moved(getLines(), 1));
  }

  public TextLocation locateNearestWordToTheLeft()
  {
    return findWordsLeftEdge(getCaretLocation().moved(getLines(), -1));
  }

  public TextLocation locateNearestWordToTheRight()
  {
    return findNextWordSkippingSpacesOrNewLines(findWordsRightEdge(caretLocation));
  }

  protected TextLocation findNextWordSkippingSpacesOrNewLines(TextLocation startLocation)
  {
    for(int i = startLocation.toIndex(getLines()); i <= text.length() - 1; i++)
    {
      if(isAtStartOfWord(i))
        return TextLocation.fromIndex(getLines(), i);
    }
    return getEndLocation();
  }

  public TextLocation getEndLocation()
  {
    return TextLocation.fromIndex(getLines(), text.length());
  }

  public void selectAll()
  {
    startSelection(TextLocation.origin);
    setCaretLocation(getEndLocation());
  }

  public void moveCaret(int places)
  {
    setCaretLocation(getCaretLocation().moved(getLines(), places));
  }

  public void moveCaretUpALine()
  {
    moveCaretToNewLine(-1);
  }

  public void moveCaretDownALine()
  {
    moveCaretToNewLine(1);
  }

  public void moveCaretToNewLine(int lineDelta)
  {
    ArrayList<TypedLayout> lines = getLines();
    int newLineNumber = caretLocation.line + lineDelta;
    if(newLineNumber >= 0 && newLineNumber < lines.size())
    {
      TextLocation origin = verticalOrigin != null ? verticalOrigin : caretLocation;
      int desiredX = lines.get(origin.line).getX(origin.index);

      TypedLayout newLine = lines.get(newLineNumber);
      int newIndex = newLine.getIndexAt(desiredX);

      TextLocation newLocation = TextLocation.at(newLineNumber, newIndex);
      setCaretLocation(newLocation);

      verticalOrigin = origin;
    }
  }

  public void sendCaretToStartOfLine()
  {
    setCaretLocation(TextLocation.at(getCaretLocation().line, 0));
  }

  public void sendCaretToEndOfLine()
  {
    final TextLocation caret = getCaretLocation();
    TypedLayout caretLine = getLines().get(caret.line);
    setCaretLocation(TextLocation.at(caret.line, caretLine.visibleLength()));
  }

  public void startSelection(TextLocation location)
  {
    selectionLocation = location;
    selectionActivated = true;
  }

  public void deactivateSelection()
  {
    selectionActivated = false;
  }

  public boolean hasSelection()
  {
    return selectionActivated && !selectionLocation.equals(caretLocation);
  }

  public boolean isSelectionActivated()
  {
    return selectionActivated;
  }

  public String getSelectedText()
  {
    if(!hasSelection())
      return "";

    int startIndex = getSelectionStart().toIndex(getLines());
    int endIndex = getSelectionEnd().toIndex(getLines());

    return text.substring(startIndex, endIndex);
  }

  public TextLocation getSelectionStart()
  {
    return caretLocation.before(selectionLocation) ? caretLocation : selectionLocation;
  }

  public TextLocation getSelectionEnd()
  {
    return caretLocation.before(selectionLocation) ? selectionLocation : caretLocation;
  }

  public limelight.ui.model.text.TextContainer getContainer()
  {
    return container;
  }

  public Point getOffset()
  {
    return offset;
  }

  public void setOffset(int x, int y)
  {
    offset.setLocation(x, y);
  }

  public void lostOwnership(Clipboard clipboard, Transferable contents)
  {
    //this doesn't have to do anything...
  }

  public TypedLayout createLayout(String text)
  {
    return typedLayoutFactory.createLayout(text, getFont(), TextPanel.getRenderContext());
  }

  public void setTypedLayoutFactory(TypedLayoutFactory factory)
  {
    typedLayoutFactory = factory;
  }

  public int getCaretWidth()
  {
    return 1;
  }

  public void resetChangeFlag()
  {
    changeFlag = false;
  }

  public boolean hasChanged()
  {
    return changeFlag;
  }

  public boolean isSingleLine()
  {
    return false;
  }

  public TextMask getMask()
  {
    return mask;
  }

  public void setMask(TextMask mask)
  {
    this.mask = mask;
  }
}
TOP

Related Classes of limelight.ui.model.text.TextModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.