Another TextUtilities wrap wrong

A discussion forum for the JCommon class library.
Post Reply
fischerw
Posts: 3
Joined: Wed Aug 25, 2010 6:16 pm
antibot: No, of course not.

Another TextUtilities wrap wrong

Post by fischerw » Tue Dec 13, 2011 4:49 am

I am using a pie chart to display data. The labels for the pie sections are sometimes very long, with few, if any, line break characters. I was setting the label width maximum, but getting bizarre results when the label was drawn.

For example, the label "JmsMessaging.someFunction()", was being drawn as
JmsM
essagi
ng.someFunction()
which caused some of the last line to be drawn out of the plot area.

I tracked the problem down to the private function nextLineBreak() in TextUtilities. It would call the BreakIterator next() method to get the next token, then shorten it until it would fit in the allotted maximum width. The first call to next() would return the index of the '.' in the label, the next would return the index of the ')', and the third would return -1 to indicate it was done.

Here is the original code.

Code: Select all

    private static int nextLineBreak(final String text, final int start,
            final float width, final BreakIterator iterator,
            final TextMeasurer measurer) {

        // this method is (loosely) based on code in JFreeReport's
        // TextParagraph class
        int current = start;
        int end;
        float x = 0.0f;
        boolean firstWord = true;
        int newline = text.indexOf('\n', start);
        if (newline < 0) {
            newline = Integer.MAX_VALUE;
        }
        while (((end = iterator.next()) != BreakIterator.DONE)) {
            if (end > newline) {
                return newline;
            }
            x += measurer.getStringWidth(text, current, end);
            if (x > width) {
                if (firstWord) {
                    while (measurer.getStringWidth(text, start, end) > width) {
                        end--;
                        if (end <= start) {
                            return end;
                        }
                    }
                    return end;
                }
                else {
                    end = iterator.previous();
                    return end;
                }
            }
            // we found at least one word that fits ...
            firstWord = false;
            current = end;
        }
        return BreakIterator.DONE;
    }
The problem is that when end is decremented, the iterator knows nothing about it, so the call to next() looks beyond the last returned index.

Here is the modified code.

Code: Select all

  private static int nextLineBreak(final String text, final int start,
          final float width, final BreakIterator iterator,
          final TextMeasurer measurer) {

      // this method is (loosely) based on code in JFreeReport's
      // TextParagraph class
      int current = start;
      int end;
      float x = 0.0f;
      boolean firstWord = true;
      int newline = text.indexOf('\n', start);
      if (newline < 0) {
          newline = Integer.MAX_VALUE;
      }
/***************************************************************************************/
/*  HERE IS THE CHANGE                                                                        */
      while (((end = iterator.following(current)) != BreakIterator.DONE)) {
/***************************************************************************************/
          if (end > newline) {
              return newline;
          }
          // This gives us the next line, we need to process all of the 
          // string returned before asking for the next line.
          x += measurer.getStringWidth(text, current, end);
          if (x > width) {
              if (firstWord) {
                  while (measurer.getStringWidth(text, start, end) > width) {
                      end--;
                      if (end <= start) {
                          return end;
                      }
                  }
                  return end;
              }
              else {
                  end = iterator.previous();
                  return end;
              }
          }
          // we found at least one word that fits ...
          firstWord = false;
          current = end;
      }
      return BreakIterator.DONE;
  }
Just wanted to let you know for possible inclusion in a later release.

david.gilbert
JFreeChart Project Leader
Posts: 11679
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Another TextUtilities wrap wrong

Post by david.gilbert » Wed Dec 14, 2011 9:28 pm

Thanks for the analysis. I committed the fix for inclusion in JCommon 1.0.18.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Ask your company to buy the JFreeChart Developer Guide
:idea: Check out other products sold by my company Object Refinery Limited

venus6
Posts: 1
Joined: Wed Jun 13, 2012 7:35 am
antibot: No, of course not.
Contact:

Re: Another TextUtilities wrap wrong

Post by venus6 » Wed Jun 13, 2012 7:45 am

Thanks for the analysis.

lyzahundley
Posts: 1
Joined: Tue Dec 11, 2012 4:32 am
antibot: No, of course not.

Re: Another TextUtilities wrap wrong

Post by lyzahundley » Tue Dec 11, 2012 4:34 am

appreciate this one.

abxbe
Posts: 2
Joined: Fri Apr 10, 2015 2:07 pm
antibot: No, of course not.

Re: Another TextUtilities wrap wrong

Post by abxbe » Fri Apr 10, 2015 2:13 pm

fischerw wrote:I am using a pie chart to display data. The labels for the pie sections are sometimes very long, with few, if any, line break characters. I was setting the label width maximum, but getting bizarre results when the label was drawn.

For example, the label "JmsMessaging.someFunction()", was being drawn as
JmsM
essagi
ng.someFunction()
which caused some of the last line to be drawn out of the plot area.

I tracked the problem down to the private function nextLineBreak() in TextUtilities. It would call the BreakIterator next() method to get the next token, then shorten it until Paris airport transportation it would fit in the allotted maximum width. The first call to next() would return the index of the '.' in the label, the next would return the index of the ')', and the third would return -1 to indicate it was done.

Here is the original code.

Code: Select all

    private static int nextLineBreak(final String text, final int start,
            final float width, final BreakIterator iterator,
            final TextMeasurer measurer) {

        // this method is (loosely) based on code in JFreeReport's
        // TextParagraph class
        int current = start;
        int end;
        float x = 0.0f;
        boolean firstWord = true;
        int newline = text.indexOf('\n', start);
        if (newline < 0) {
            newline = Integer.MAX_VALUE;
        }
        while (((end = iterator.next()) != BreakIterator.DONE)) {
            if (end > newline) {
                return newline;
            }
            x += measurer.getStringWidth(text, current, end);
            if (x > width) {
                if (firstWord) {
                    while (measurer.getStringWidth(text, start, end) > width) {
                        end--;
                        if (end <= start) {
                            return end;
                        }
                    }
                    return end;
                }
                else {
                    end = iterator.previous();
                    return end;
                }
            }
            // we found at least one word that fits ...
            firstWord = false;
            current = end;
        }
        return BreakIterator.DONE;
    }
The problem is that when end is decremented, the iterator knows nothing about it, so the call to next() looks beyond the last returned index.

Here is the modified code.

Code: Select all

  private static int nextLineBreak(final String text, final int start,
          final float width, final BreakIterator iterator,
          final TextMeasurer measurer) {

      // this method is (loosely) based on code in JFreeReport's
      // TextParagraph class
      int current = start;
      int end;
      float x = 0.0f;
      boolean firstWord = true;
      int newline = text.indexOf('\n', start);
      if (newline < 0) {
          newline = Integer.MAX_VALUE;
      }
/***************************************************************************************/
/*  HERE IS THE CHANGE                                                                        */
      while (((end = iterator.following(current)) != BreakIterator.DONE)) {
/***************************************************************************************/
          if (end > newline) {
              return newline;
          }
          // This gives us the next line, we need to process all of the 
          // string returned before asking for the next line.
          x += measurer.getStringWidth(text, current, end);
          if (x > width) {
              if (firstWord) {
                  while (measurer.getStringWidth(text, start, end) > width) {
                      end--;
                      if (end <= start) {
                          return end;
                      }
                  }
                  return end;
              }
              else {
                  end = iterator.previous();
                  return end;
              }
          }
          // we found at least one word that fits ...
          firstWord = false;
          current = end;
      }
      return BreakIterator.DONE;
  }
Just wanted to let you know for possible inclusion in a later release.
Thanks for great job. your analysis is more helpfull. Now am able to fix my JCommom problem.

midupe
Posts: 1
Joined: Sun Aug 05, 2018 7:51 pm
antibot: No, of course not.
Location: Tunisia
Contact:

rsllpzqfbxlc

Post by midupe » Sun Aug 05, 2018 8:18 pm

buy viagra soft 10 pills http://canadian-pharmacie.com

soarve
Posts: 1
Joined: Mon Aug 06, 2018 6:18 pm
antibot: No, of course not.
Location: Tajikistan
Contact:

qpardlfznppv

Post by soarve » Mon Aug 06, 2018 6:36 pm

<a href=http://canadian-pharman.com>buy viagra cheaply</a>
generico viagra italia http://canadian-pharman.com

Post Reply