vandeseer / easytable

Small table drawing library built upon Apache PDFBox

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Disable line-break hyphenation

opened this issue · comments

Hi, I am currently working on a table that contains information about IT projects.
As I use Japanese for some parts, words can get quite long, such that line breaks become necessary.
Now I was wondering if it is possible to disable hyphens at the end of the line where words get too long.
Thank you very much in advance.
image

Hi @gabu99,

there is no easy switch to turn this off as of now. But I think it should not be too hard to implement a custom cell type that just breaks without adding hyphens.

I will have a look.

Best,
Stefan

Hey @vandeseer

Thank you very much, I appreciate.

I hacked around a bit found a solution using a custom cell type and the very nice library https://github.com/davidmoten/word-wrap. You would need to include that library in your pom.xml:

    <dependency>
        <groupId>com.github.davidmoten</groupId>
        <artifactId>word-wrap</artifactId>
        <version>0.1.8</version>
    </dependency>

The full example now looks like this:

import lombok.experimental.SuperBuilder;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.davidmoten.text.utils.WordWrap;
import org.vandeseer.easytable.TableDrawer;
import org.vandeseer.easytable.drawing.Drawer;
import org.vandeseer.easytable.drawing.cell.TextCellDrawer;
import org.vandeseer.easytable.structure.Row;
import org.vandeseer.easytable.structure.Table;
import org.vandeseer.easytable.structure.cell.TextCell;
import org.vandeseer.easytable.util.PdfUtil;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class EasytableCustomMain {

    @SuperBuilder
    private static class MyCustomCell extends TextCell {

        private List<String> lines;

        public List<String> getLines() {
            if (lines != null) {
                return lines;
            }

            return Arrays.stream(
                    WordWrap
                            .from(getText()).maxWidth(getMaxWidthOfText() - getHorizontalPadding())
                            .stringWidth(charSequence -> PdfUtil.getStringWidth(charSequence.toString(), getFont(), getFontSize()))
                            .breakWords(true)
                            .insertHyphens(false)
                            .wrap().split("\n")
            )
                    .collect(Collectors.toList());
        }

        @Override
        public float getWidthOfText() {
            return lines.stream()
                    .map(line -> PdfUtil.getStringWidth(line, getFont(), getFontSize()))
                    .max(Comparator.naturalOrder())
                    .orElse(PdfUtil.getStringWidth(getText(), getFont(), getFontSize()));
        }

        @Override
        public float getTextHeight() {
            if (this.textHeight != null) {
                return this.textHeight;
            }

            this.textHeight = PdfUtil.getFontHeight(getFont(), getFontSize());

            final float heightOfTextLines = getLines().size() * this.textHeight;
            final float heightOfLineSpacing = (getLines().size() - 1) * this.textHeight * getLineSpacing();

            this.textHeight = heightOfTextLines + heightOfLineSpacing;
            return this.textHeight;
        }

        @Override
        public Drawer getDrawer() {
            return new TextCellDrawer<MyCustomCell>(this) {
                @Override
                protected List<String> calculateAndGetLines(PDFont currentFont, int currentFontSize, float maxWidth) {
                    return ((MyCustomCell) cell).getLines();
                }
            };
        }

    }

    public static void main(String[] args) throws Exception {
        try (PDDocument document = new PDDocument()) {
            final PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {

                // Build the table
                Table myTable = Table.builder()
                        .addColumnsOfWidth(200, 200)
                        .padding(2)
                        .addRow(Row.builder()
                                .add(MyCustomCell.builder().text("This is a very long text that should be split").build())
                                .add(MyCustomCell.builder().text("Fubarfubarfubarfubarfubarfubarfubarfubarfubarbazzz").build())
                                .build())
                        .addRow(Row.builder()
                                .add(MyCustomCell.builder().text("Two One").build())
                                .add(MyCustomCell.builder().text("Two Two").build())
                                .build())
                        .build();

                // Set up the drawer
                TableDrawer tableDrawer = TableDrawer.builder()
                        .contentStream(contentStream)
                        .startX(20f)
                        .startY(page.getMediaBox().getUpperRightY() - 20f)
                        .table(myTable)
                        .build();

                // And go for it!
                tableDrawer.draw();
            }

            document.save("example.pdf");
        }
    }

}

Please also note that you will need Lombok for that, too:

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>

Let me know if that works for you.

Best,
Stefan

Thank you for your quick support.
Unfortunately, when I try to use the code there seem to be problems with extending the TextCell class.
The first error says Implicit super constructor TextCell() is undefined for default constructor. Must define an explicit constructor.
And getMaxWidthOfText seems to be a private method, such that I can't call it in this class.
Do you have any ideas how to solve the problem?
Thank you again!

image

Hey @gabu99,

sorry, my fault: You need to get version 0.8.0 of easytable (which I just published with the changes necessary).
Regarding the Implicit super constructor issue: It may stem from not using any Lombok support in Eclipse. I don't use Eclipse myself but maybe this link is of use.

Also you can try to run the code from the command line. It should compile correctly then, because the Lombok stuff is done automatically (it's just your IDE not "understanding" it as of now).

Best,
Stefan

@vandeseer
Unfortunately, the code still did not work after updating the version of easytable (same errors).
Thank you for your efforts though.
If I find a solution, I'll post it.

Hey @gabu99,

I am pretty confident we get this running. So please don't give up! 😉

Did it work running from the command line?
Were you able to get the Lombok plugin installed?

Can you share an example of your code which has the problem?

Hi @vandeseer
I had the same problem too.
I was able to hide the line-break hyphen by modifying this issue as a reference. thank you!
easytable version: 0.8.5
IDE: Eclipse+Java8
I post the code in case it helps someone.

@SuperBuilder
private static class MyCustomCell extends TextCell {

      private List<String> lines;

      public List<String> getLines() {
          if (lines != null) {
              return lines;
          }

          return Arrays.stream(
                  WordWrap
                          .from(getText()).maxWidth(getMaxWidth())
                          .stringWidth(charSequence -> PdfUtil.getStringWidth(charSequence.toString(), getFont(), getFontSize()))
                          .breakWords(true)
                          .insertHyphens(false)
                          .wrap().split("\n")
          )
                  .collect(Collectors.toList());
      }

      @Override
      public float getWidthOfText() {
          return lines.stream()
                  .map(line -> PdfUtil.getStringWidth(line, getFont(), getFontSize()))
                  .max(Comparator.naturalOrder())
                  .orElse(PdfUtil.getStringWidth(getText(), getFont(), getFontSize()));
      }

      @Override
      public float getTextHeight() {
          /*if (this.textHeight != null) {
              return this.textHeight;
          }*/

       Float textHeight = PdfUtil.getFontHeight(getFont(), getFontSize());

          final float heightOfTextLines = getLines().size() * textHeight;
          final float heightOfLineSpacing = (getLines().size() - 1) * textHeight * getLineSpacing();

          textHeight = heightOfTextLines + heightOfLineSpacing;
          return textHeight;
      }

      @Override
      public Drawer getDrawer() {
          return new TextCellDrawer<MyCustomCell>(this) {
              @Override
              protected List<String> calculateAndGetLines(PDFont currentFont, int currentFontSize, float maxWidth) {
                  return ((MyCustomCell) cell).getLines();
              }
          };
      }
}