views:

630

answers:

2

Within my ListField, I want to be able to take any given long String, and just be able to wrap the first line within the width of the screen, and just take the remaining string and display it below and ellipsis the rest. Right now, this is what I'm using to detect wrapping within my draw paint call:

int totalWidth = 0;
int charWidth = 0;
int lastIndex = 0;
int spaceIndex = 0;
int lineIndex = 0;
String firstLine = "";
String secondLine = "";
boolean isSecondLine = false;

for (int i = 0; i < longString.length(); i++){
  charWidth = Font.getDefault().getAdvance(String.valueOf(longString.charAt(i)));
  //System.out.println("char width: " + charWidth);
  if(longString.charAt(i) == ' ')
  spaceIndex = i;
  if((charWidth + totalWidth) > (this.getWidth()-32)){
            //g.drawText(longString.substring(lastIndex, spaceIndex), xpos, y +_padding, DrawStyle.LEFT, w - xpos);  
            lineIndex++;
    System.out.println("current lines to draw: " + lineIndex);
    /*if (lineIndex = 2){
    int idx =  i;
    System.out.println("first line " + longString.substring(lastIndex, spaceIndex));
    System.out.println("second line " + longString.substring(spaceIndex+1, longString.length()));
  }*/
  //firstLine = longString.substring(lastIndex, spaceIndex);
  firstLine = longString.substring(0, spaceIndex);
  //System.out.println("first new line: " +firstLine);
  //isSecondLine=true;
  //xpos = 0;
  //y += Font.getDefault().getHeight();
  i = spaceIndex + 1;
  lastIndex = i;
  System.out.println("Rest of string: " + longString.substring(lastIndex, longString.length()));

  charWidth = 0;
  totalWidth = 0;
  }
  totalWidth += charWidth;
  System.out.println("total width: " + totalWidth);
  //g.drawText(longString.substring(lastIndex, i+1), xpos, y + (_padding*3)+4, DrawStyle.ELLIPSIS, w - xpos);

  //secondLine = longString.substring(lastIndex, i+1);
  secondLine = longString.substring(lastIndex, longString.length());
  //isSecondLine = true;
}

Now this does a great job of actually wrapping any given string (assuming the y values were properly offsetted and it only drew the text after the string width exceeded the screen width, as well as the remaining string afterwards), however, every time I try to get the first two lines, it always ends up returning the last two lines of the string if it goes beyond two lines. Is there a better way to do this sort of thing, since I am fresh out of ideas?

+1  A: 

I'm not entirely sure I understand you're question but it sounds to me like you need a word wrapping algorithm that gives up after two lines. If that is the case then this should hopefully get you pointed in the right direction.

void wrapString(String inputString, int width, Font font){
    String line1;
    String line2;

    if (font.getAdvance(inputString) <= width){
        line1 = inputString;
        line2 = "";
    }
    else{
        int charsInLine1 = countCharsInLine(inputString, 0, inputString.length()-1, width, font);
        int lineBreak = inputString.lastIndexOf(' ', charsInLine1);
        if (lineBreak == -1)
            lineBreak = charsInLine1;
        line1 = inputString.substring(0, lineBreak);

        line2 = inputString.substring(lineBreak+1, inputString.length());
        if (font.getAdvance(line2) > width){
            int charsInLine2 = countCharsInLine(line2, 0, inputString.length()-1, width - font.getAdvance("..."), font);
            line2 = line2.substring(0, charsInLine2) + "...";
        }
    }

    System.out.println("line1: " + line1);
    System.out.println("line2: " + line2);
}

int countCharsInLine(String str, int min, int max, int width, Font font) {

    if (min >= max)
        return max;

    int guess = min + (max - min) / 2;
    int advance = font.getAdvance(str, 0, guess);

    if (advance < width)
        return countCharsInLine(str, guess+1, max, width, font);
    else if (advance > width)
        return countCharsInLine(str, min, guess-1, width, font);
    else
        return guess;
}
Jeff
Thanks for the help, so far it actually works when it doesn't have to do the second line font advance check, since after trying to compensate for the ellipsis width, it breaks in trying to guess the char length. However, I was able to adapt that same algorithm with drawText calls in a separate function and let the second line ellipsis from the paint call. So far, thanks for the help, although I would like to know if you can revisit the guess calculation just for kicks.
Diego Tori
A: 

I have done something similar but it will return all the warped lines. You can then use the first element of the returned vector and combine the rest elements to get the two lines you want:

private Vector wrap (String text, int width) 
{
    Vector result = new Vector ();

    String remaining = text;


    while (remaining.length()>=0)
    {
        int index = getSplitIndex(remaining, width);

        if (index == -1)
            break;

        result.addElement(remaining.substring(0,index));

        remaining = remaining.substring(index);

        if (index == 0)
            break;
    }

    return result;
}


private int getSplitIndex(String bigString, int width)
{
    int index = -1;
    int lastSpace = -1;
    String smallString="";
    boolean spaceEncountered = false;
    boolean maxWidthFound = false;

    for (int i=0; i<bigString.length(); i++)
    {
        char current = bigString.charAt(i);
        smallString += current;


        if (current == ' ')
        {
            lastSpace = i;
            spaceEncountered = true;
        }

        int linewidth = this.getFont().getAdvance(smallString,0,  smallString.length());

        if(linewidth>width)
        {
            if (spaceEncountered)
                index = lastSpace+1;
            else
                index = i;

            maxWidthFound = true;

            break;


        }


    }

    if (!maxWidthFound)
        index = bigString.length();


    return index;
}

Am still testing and working fine until now.

Afzal