Added ruler graphic to printed output; improvements to layout and margins in printing...
[debian/openrocket] / core / src / net / sf / openrocket / gui / print / visitor / CenteringRingStrategy.java
1 package net.sf.openrocket.gui.print.visitor;
2
3 import com.itextpdf.text.Document;
4 import com.itextpdf.text.DocumentException;
5 import com.itextpdf.text.Rectangle;
6 import com.itextpdf.text.pdf.PdfWriter;
7 import net.sf.openrocket.gui.print.AbstractPrintable;
8 import net.sf.openrocket.gui.print.ITextHelper;
9 import net.sf.openrocket.gui.print.PrintUnit;
10 import net.sf.openrocket.gui.print.PrintableCenteringRing;
11 import net.sf.openrocket.logging.LogHelper;
12 import net.sf.openrocket.rocketcomponent.CenteringRing;
13 import net.sf.openrocket.rocketcomponent.RocketComponent;
14 import net.sf.openrocket.startup.Application;
15
16 import java.awt.image.BufferedImage;
17 import java.util.List;
18 import java.util.Set;
19
20 /**
21  * A strategy for printing a centering ring to iText.
22  */
23 public class CenteringRingStrategy {
24
25     /**
26      * The logger.
27      */
28     private static final LogHelper log = Application.getLogger();
29
30     /**
31      * The iText document.
32      */
33     protected Document document;
34
35     /**
36      * The direct iText writer.
37      */
38     protected PdfWriter writer;
39
40     /**
41      * The stages selected.
42      */
43     protected Set<Integer> stages;
44
45     /**
46      * Strategy for fitting multiple components onto a page.
47      */
48     protected PageFitPrintStrategy pageFitPrint;
49
50     /**
51      * Constructor.
52      *
53      * @param doc              The iText document
54      * @param theWriter        The direct iText writer
55      * @param theStagesToVisit The stages to be visited by this strategy
56      */
57     public CenteringRingStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit, PageFitPrintStrategy pageFit) {
58         document = doc;
59         writer = theWriter;
60         stages = theStagesToVisit;
61         pageFitPrint = pageFit;
62     }
63
64     /**
65      * Recurse through the given rocket component.
66      *
67      * @param root the root component; all children will be visited recursively
68      */
69     public void writeToDocument(final RocketComponent root) {
70         List<RocketComponent> rc = root.getChildren();
71         goDeep(rc);
72     }
73
74
75     /**
76      * Recurse through the given rocket component.
77      *
78      * @param theRc an array of rocket components; all children will be visited recursively
79      */
80     protected void goDeep(final List<RocketComponent> theRc) {
81         for (RocketComponent rocketComponent : theRc) {
82             if (rocketComponent instanceof CenteringRing) {
83                 render((CenteringRing) rocketComponent);
84             }
85             else if (rocketComponent.getChildCount() > 0) {
86                 goDeep(rocketComponent.getChildren());
87             }
88         }
89     }
90
91     /**
92      * The core behavior of this visitor.
93      *
94      * @param component the object to extract info about; a graphical image of the centering ring shape is drawn to the
95      *                  document
96      */
97     private void render(final CenteringRing component) {
98         try {
99             AbstractPrintable pfs;
100             pfs = new PrintableCenteringRing(component);
101
102             java.awt.Dimension size = pfs.getSize();
103             final Dimension pageSize = getPageSize();
104             if (fitsOnOnePage(pageSize, size.getWidth(), size.getHeight())) {
105                 pageFitPrint.addComponent(pfs);
106             }
107             else {
108                 int off = (int) (PrintUnit.POINTS_PER_INCH * 0.3f);
109                 pfs.setPrintOffset(off, off);
110                 BufferedImage image = (BufferedImage) pfs.createImage();
111                 ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
112                         document, writer, image);
113                 document.newPage();
114             }
115         }
116         catch (DocumentException e) {
117             log.error("Could not render the centering ring.", e);
118         }
119     }
120
121     /**
122      * Determine if the image will fit on the given page.
123      *
124      * @param pageSize the page size
125      * @param wImage   the width of the thing to be printed
126      * @param hImage   the height of the thing to be printed
127      *
128      * @return true if the thing to be printed will fit on a single page
129      */
130     private boolean fitsOnOnePage(Dimension pageSize, double wImage, double hImage) {
131         double wPage = pageSize.getWidth();
132         double hPage = pageSize.getHeight();
133
134         int wRatio = (int) Math.ceil(wImage / wPage);
135         int hRatio = (int) Math.ceil(hImage / hPage);
136
137         return wRatio <= 1.0d && hRatio <= 1.0d;
138     }
139
140     /**
141      * Get the dimensions of the paper page.
142      *
143      * @return an internal Dimension
144      */
145     protected Dimension getPageSize() {
146         return new Dimension(document.getPageSize().getWidth(),
147                 document.getPageSize().getHeight());
148     }
149
150     /**
151      * Convenience class to model a dimension.
152      */
153     class Dimension {
154         /**
155          * Width, in points.
156          */
157         public float width;
158         /**
159          * Height, in points.
160          */
161         public float height;
162
163         /**
164          * Constructor.
165          *
166          * @param w width
167          * @param h height
168          */
169         public Dimension(float w, float h) {
170             width = w;
171             height = h;
172         }
173
174         /**
175          * Get the width.
176          *
177          * @return the width
178          */
179         public float getWidth() {
180             return width;
181         }
182
183         /**
184          * Get the height.
185          *
186          * @return the height
187          */
188         public float getHeight() {
189             return height;
190         }
191     }
192 }