20ef3c19f99ec9cae22b4f4f7e7bb98c6c4dd80f
[debian/openrocket] / core / src / net / sf / openrocket / gui / print / visitor / PageFitPrintStrategy.java
1 /*
2  * PageFitPrintStrategy.java
3  */
4 package net.sf.openrocket.gui.print.visitor;
5
6 import com.itextpdf.text.Document;
7 import com.itextpdf.text.pdf.PdfContentByte;
8 import com.itextpdf.text.pdf.PdfWriter;
9 import net.sf.openrocket.gui.print.PrintUnit;
10 import net.sf.openrocket.gui.print.PrintableComponent;
11 import net.sf.openrocket.logging.LogHelper;
12 import net.sf.openrocket.rocketcomponent.RocketComponent;
13 import net.sf.openrocket.startup.Application;
14
15 import java.awt.*;
16 import java.util.ArrayList;
17 import java.util.ListIterator;
18 import java.util.Set;
19
20 /**
21  * A strategy for drawing multiple rocket components onto as few pages as possible.
22  * 
23  * @author Jason Blood <dyster2000@gmail.com>
24  */
25 public class PageFitPrintStrategy {
26
27     /**
28      * The logger.
29      */
30     private static final LogHelper log = Application.getLogger();
31
32     /**
33      * The iText document.
34      */
35     protected Document document;
36
37     /**
38      * The direct iText writer.
39      */
40     protected PdfWriter writer;
41
42     /**
43      * The stages selected.
44      */
45     protected Set<Integer> stages;
46
47         protected ArrayList<PrintableComponent> componentToPrint;
48     
49     /**
50      * Constructor.
51      *
52      * @param doc              The iText document
53      * @param theWriter        The direct iText writer
54      * @param theStages        The stages to be printed by this strategy
55      */
56     public PageFitPrintStrategy(Document doc, PdfWriter theWriter) {
57         document = doc;
58         writer = theWriter;
59         componentToPrint = new ArrayList<PrintableComponent>();
60     }
61     
62     /**
63      * Add a component we want to print.
64      *
65      * @param component The component to add for printing
66      */
67     public void addComponent(PrintableComponent component) {
68                 componentToPrint.add(component);
69     }
70
71     /**
72      * Recurse through the given rocket component.
73      *
74      * @param root the root component; all children will be printed recursively
75      */
76     public void writeToDocument (final RocketComponent root) {
77         fitPrintComponents();
78     }
79
80     /**
81      * Iterate through the components to print fitting them onto pages as best possible.
82      */
83     private void fitPrintComponents() {
84         final Dimension pageSize = getPageSize();
85         double wPage = pageSize.getWidth();
86         double hPage = pageSize.getHeight();
87         int marginX = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
88         int marginY = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
89         PdfContentByte cb = writer.getDirectContent();
90         
91         while (componentToPrint.size() > 0) {
92                 int pageY = 0;
93                 Boolean anyAddedToRow;
94                 
95             Graphics2D g2 = cb.createGraphics(pageSize.width, pageSize.height);
96                 
97                 do {
98                         // Fill the row
99                         int rowX = 0;
100                         int rowY = pageY;
101                         ListIterator<PrintableComponent> entry = componentToPrint.listIterator();
102                         anyAddedToRow = false;
103
104                         while (entry.hasNext()) {
105                                 PrintableComponent component = entry.next();
106                                 java.awt.Dimension dim = component.getSize();
107                                 if ((rowX + dim.width < wPage) && (rowY + dim.height < hPage)) {
108                                         component.setPrintOffset(rowX, rowY);
109                                         rowX += dim.width + marginX;
110                                         if (rowY + dim.height + marginY > pageY)
111                                                 pageY = rowY + dim.height + marginY;
112                                         entry.remove();
113                                         component.print(g2);
114                                         anyAddedToRow = true;
115                                 }
116                         }
117                 } while (anyAddedToRow);
118                 
119                 g2.dispose();
120                 document.newPage();
121         }
122     }
123     
124     /**
125      * Get the dimensions of the paper page.
126      *
127      * @return an internal Dimension
128      */
129     protected Dimension getPageSize () {
130         return new Dimension(document.getPageSize().getWidth(),
131                              document.getPageSize().getHeight());
132     }
133
134     /**
135      * Convenience class to model a dimension.
136      */
137     class Dimension {
138         /** Width, in points. */
139         public float width;
140         /** Height, in points. */
141         public float height;
142
143         /**
144          * Constructor.
145          * @param w width
146          * @param h height
147          */
148         public Dimension (float w, float h) {
149             width = w;
150             height = h;
151         }
152
153         /**
154          * Get the width.
155          *
156          * @return  the width
157          */
158         public float getWidth () {
159             return width;
160         }
161
162         /**
163          * Get the height.
164          *
165          * @return the height
166          */
167         public float getHeight () {
168             return height;
169         }
170     }
171 }