Package limn.print

Class Document

java.lang.Object
limn.print.Document

public final class Document extends Object
What a business application prints or saves as PDF: widgets the toolkit cuts into pages.

 Document order = Document.of(Paper.A4)
         .marginsMm(18, 15, 18, 15)
         .title("Order 4512")
         .header(page -> new Label("ACME Distribution"))
         .footer(page -> new Label(page.number() + " / " + page.count()))
         .add(customerCard)
         .add(itemsTable)                  // cut between rows, its header on every page
         .keepTogether(totalsBox)          // moved whole to the next page if it does not fit
         .pageBreak()
         .add(new DonutChart(byCategory));

 order.writePdf(file).onSuccess(saved -> window.launcher().openFile(saved)).start();
 order.print(window);
 

The widgets are the document's. An application builds them for the document, the same components it shows on screen, over the same data, and does not lend it widgets that are in a window: a widget belongs to one scene, and a document paints each block in a scene of its own that no window shows. In that scene nothing has focus, nothing is hovered, nothing scrolls, every animation is at its end, and the palette is the document's.

The page. A document unit is 1/96 inch, the convention a browser prints with: a body label of 13 units prints at 9.75 points. Every block takes the width of the content box (the paper less its margins) and as much height as it measures to; a block that does not fit in what is left of a page is cut where it can be cut (between the lines of a label, between the children of a column or the rows of a grid, between the rows of a list, a table or a tree), or moved whole to the next page, or, taller than a page and with nowhere to cut, sliced at the page's height. A list, a table or a tree is cut between rows only as a block of its own: every row is printed, a page's worth realized at a time, and a table's header is on every page. Inside another block it prints the box it measures to.

The smallest content box. What the margins, the header and the footer leave of a page is at least a quarter inch (24 units, 18 points) each way, room for a line of body text: a document that leaves less, a letterhead and a disclaimer filling a small label, or the default three-quarter-inch margins on paper less than an inch and three quarters across or down, is refused with an IllegalStateException that names the paper, the margins and the header's and the footer's heights, when its pages are recorded. The header and the footer are measured then, since they are made per page.

What a page holds that a PDF cannot. A soft shadow is a picture at the document's raster resolution (rasterDpi, 300 by default), as is an icon; a backdrop effect is its tint; a video or a 3D view is left out, with a warning.

UI thread only: a document holds widgets. Its pages are recorded on the UI thread when writePdf(java.nio.file.Path) or print(limn.backend.NativeWindow) is called or a PrintPreview asks for them, and again once a face the text asked for has loaded, or after ten seconds without it, with a warning; the PDF's bytes are written on a worker. A document can be written, printed and previewed any number of times; each records its pages afresh, so what the widgets show at that moment is what is printed.

  • Method Summary

    Modifier and Type
    Method
    Description
    add(Widget<?> widget)
    Adds a block: it takes the content box's width and the height it measures to, and is cut where it can be cut when it does not fit.
    footer(@Nullable Function<PageInfo,Widget<?>> footer)
    Sets what is drawn at the foot of every page, as header does at its top.
    header(@Nullable Function<PageInfo,Widget<?>> header)
    Sets what is drawn at the top of every page: a new widget for each page, made when the page is drawn, since a page's number is known only once the document is cut, and its count only once it is cut to the end.
    keepTogether(Widget<?> widget)
    Adds a block that is never cut: moved whole to the next page when it does not fit in what is left of a page, and sliced only when it is taller than a whole page.
    @Nullable Locale
     
    locale(@Nullable Locale locale)
    Sets the locale the pages are laid out in, which also sets their direction and the PDF's language; by default the process's.
    marginsMm(float top, float right, float bottom, float left)
    Sets the margins, in millimetres.
    marginsPt(float top, float right, float bottom, float left)
    Sets the margins, in points (1/72 inch).
    static Document
    of()
     
    static Document
    of(Paper paper)
     
    Ends the page: the next block begins a new one.
    int
    Cuts the document into pages now and says how many there are.
     
    Prints the document through the system's own print dialog, owned by window: the pages are recorded on the UI thread (again once a face the text asked for has loaded, or after ten seconds without it, with a warning), the PDF is written on a worker, and the window's Printer hands it to the system.
    int
     
    rasterDpi(int dpi)
    Sets the resolution of what is drawn as a picture: icons, soft shadows.
    theme(@Nullable Theme theme)
    Sets the palette the pages are painted with.
     
    title(String title)
    Sets the title: the PDF's title and the name of the print job.
    Writes the document as a PDF to a stream, which is not closed.
    writePdf(Path file)
    Writes the document as a PDF file.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Method Details

    • of

      public static Document of(Paper paper)
      Parameters:
      paper - the paper every page is laid out on
      Returns:
      an empty document, with margins of three quarters of an inch
    • of

      public static Document of()
      Returns:
      an empty document on the paper of the default locale's region (Paper.forLocale(java.util.Locale))
    • marginsMm

      public Document marginsMm(float top, float right, float bottom, float left)
      Sets the margins, in millimetres.
      Returns:
      this document
    • marginsPt

      public Document marginsPt(float top, float right, float bottom, float left)
      Sets the margins, in points (1/72 inch).
      Returns:
      this document
    • title

      public Document title(String title)
      Sets the title: the PDF's title and the name of the print job.
      Parameters:
      title - never blank
      Returns:
      this document
    • header

      public Document header(@Nullable Function<PageInfo,Widget<?>> header)
      Sets what is drawn at the top of every page: a new widget for each page, made when the page is drawn, since a page's number is known only once the document is cut, and its count only once it is cut to the end. The tallest of them is the room every page keeps for it: the document is cut again each time the count makes one taller, up to three times, and one taller still after that is drawn in the room the last cut kept, cut at its foot, with a warning; the content never runs under it.
      Parameters:
      header - makes a page's header, or null for none
      Returns:
      this document
    • footer

      public Document footer(@Nullable Function<PageInfo,Widget<?>> footer)
      Sets what is drawn at the foot of every page, as header does at its top.
      Parameters:
      footer - makes a page's footer, or null for none
      Returns:
      this document
    • theme

      public Document theme(@Nullable Theme theme)
      Sets the palette the pages are painted with. By default it is the light palette of the process's palette family (Theme.light() for Theme.dark(), Theme.limnLight() for Theme.limn(), and Theme.light() for any other dark palette): paper is white, and a dark page spends its toner on the background.
      Parameters:
      theme - the palette, or null for the default
      Returns:
      this document
    • locale

      public Document locale(@Nullable Locale locale)
      Sets the locale the pages are laid out in, which also sets their direction and the PDF's language; by default the process's.
      Parameters:
      locale - the locale, or null for the process's
      Returns:
      this document
    • rasterDpi

      public Document rasterDpi(int dpi)
      Sets the resolution of what is drawn as a picture: icons, soft shadows.
      Parameters:
      dpi - dots per inch, from 72 to 1200; 300 by default
      Returns:
      this document
    • add

      public Document add(Widget<?> widget)
      Adds a block: it takes the content box's width and the height it measures to, and is cut where it can be cut when it does not fit.
      Parameters:
      widget - a widget made for the document, in no window and in no other document
      Returns:
      this document
    • keepTogether

      public Document keepTogether(Widget<?> widget)
      Adds a block that is never cut: moved whole to the next page when it does not fit in what is left of a page, and sliced only when it is taller than a whole page.
      Parameters:
      widget - a widget made for the document
      Returns:
      this document
    • pageBreak

      public Document pageBreak()
      Ends the page: the next block begins a new one.
      Returns:
      this document
    • paper

      public Paper paper()
      Returns:
      the paper
    • title

      public String title()
      Returns:
      the title
    • locale

      public @Nullable Locale locale()
      Returns:
      the locale, or null for the process's
    • rasterDpi

      public int rasterDpi()
      Returns:
      the raster resolution, in dots per inch
    • pageCount

      public int pageCount()
      Cuts the document into pages now and says how many there are.
      Returns:
      the number of pages, at least 1
      Throws:
      IllegalStateException - if the margins, the header and the footer leave a content box smaller than a quarter inch either way (the class says why)
    • writePdf

      public Work<Path> writePdf(Path file)
      Writes the document as a PDF file. The pages are recorded now, on the UI thread, and recorded again once the work runs if a face the text asked for was still loading (a script's fallback face, loaded in the background on its first need), as soon as it has loaded or after ten seconds without it, with a warning; the file is written by the work on a worker, first to a temporary file beside file and then moved over it, so a failed or cancelled write leaves no half file.
      
       document.writePdf(file)
               .onProgress(fraction -> bar.setProgress((float) fraction))
               .onSuccess(saved -> window.launcher().showInFolder(saved))
               .onFailure(error -> status.setText(error.getMessage()))
               .start();
       
      Parameters:
      file - where to write it
      Returns:
      the work, not started; its value is file
      Throws:
      IllegalStateException - if the margins, the header and the footer leave a content box smaller than a quarter inch either way (the class says why); thrown here, as the pages are recorded, before any work exists
    • writePdf

      public Work<OutputStream> writePdf(OutputStream out)
      Writes the document as a PDF to a stream, which is not closed. The pages are recorded now, and again once the work runs if a face was still loading, as writePdf(Path) says; the bytes are written by the work on a worker.
      Parameters:
      out - where to write it
      Returns:
      the work, not started
      Throws:
      IllegalStateException - as writePdf(Path) does
    • print

      public CompletionStage<PrintResult> print(NativeWindow window)
      Prints the document through the system's own print dialog, owned by window: the pages are recorded on the UI thread (again once a face the text asked for has loaded, or after ten seconds without it, with a warning), the PDF is written on a worker, and the window's Printer hands it to the system. The dialog chooses the printer and may save the job as PDF where the system offers it; it scales a page to other paper, never re-flowing it.

      Pages that cannot be recorded, a content box smaller than a quarter inch among them (the class says why), show no dialog: the answer is PrintResult.FAILED, and the IllegalStateException is logged as a warning.

      Parameters:
      window - the window that owns the dialog
      Returns:
      what became of it, completed on the UI thread