Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/virtuosotechnologies/asaph/standardgui/PrintRenderHelper.java


1   /*
2   ================================================================================
3   
4     FILE:  PrintRenderHelper.java
5     
6     PROJECT:
7     
8       Asaph
9     
10    CONTENTS:
11    
12      Helper that does layout and rendering of the song for printing
13    
14    PROGRAMMERS:
15    
16      Daniel Azuma (DA)  <dazuma@kagi.com>
17    
18    COPYRIGHT:
19    
20      Copyright (C) 2003  Daniel Azuma  (dazuma@kagi.com)
21      
22      This program is free software; you can redistribute it and/or
23      modify it under the terms of the GNU General Public License as
24      published by the Free Software Foundation; either version 2
25      of the License, or (at your option) any later version.
26      
27      This program is distributed in the hope that it will be useful,
28      but WITHOUT ANY WARRANTY; without even the implied warranty of
29      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30      GNU General Public License for more details.
31      
32      You should have received a copy of the GNU General Public
33      License along with this program; if not, write to
34        Free Software Foundation, Inc.
35        59 Temple Place, Suite 330
36        Boston, MA 02111-1307 USA
37  
38  ================================================================================
39  */
40  
41  
42  package com.virtuosotechnologies.asaph.standardgui;
43  
44  
45  import java.util.List;
46  import java.util.ArrayList;
47  import java.util.Iterator;
48  import java.awt.Graphics2D;
49  import java.awt.Color;
50  
51  import virtuoso.asaph.util.render.BodyLayout;
52  
53  
54  /**
55   * Helper that does layout and rendering of the song for printing
56   */
57  /*package*/ class PrintRenderHelper
58  {
59    private static final float EPSILON = 1;
60    
61    
62    private float imageableWidth_;
63    private float imageableHeight_;
64    private int numColumns_;
65    private float unscaledGutterWidth_;
66    private float gutterWidth_;
67    private float columnWidth_;
68    private RenderHelper fullRender_;
69    private float scale_;
70    private List pages_;
71    private List columnPopulations_;
72    
73    
74    private static class BlockLayout
75    {
76      private int column;
77      private float yPosition;
78      private BodyLayout layout;
79      
80      private BlockLayout(
81        int c,
82        float y,
83        BodyLayout lo)
84      {
85        column = c;
86        yPosition = y;
87        layout = lo;
88      }
89    }
90    
91    
92    private static class PageLayout
93    {
94      private List blocks = new ArrayList();
95      private float height = 0;
96      private float footerPos = 0;
97    }
98    
99    
100   /*package*/ PrintRenderHelper(
101     RenderHelper renderHelper,
102     float imageableWidth,
103     float imageableHeight,
104     int columns,
105     float gutter)
106   {
107     this(renderHelper, imageableWidth, imageableHeight, columns, gutter, null);
108   }
109   
110   
111   private PrintRenderHelper(
112     RenderHelper renderHelper,
113     float imageableWidth,
114     float imageableHeight,
115     int columns,
116     float gutter,
117     List columnPopulations)
118   {
119     imageableWidth_ = imageableWidth;
120     imageableHeight_ = imageableHeight;
121     numColumns_ = columns;
122     gutterWidth_ = gutter;
123     unscaledGutterWidth_ = gutter;
124     columnWidth_ = (imageableWidth-(numColumns_-1)*gutterWidth_)/columns;
125     fullRender_ = renderHelper;
126     if (columnPopulations != null)
127     {
128       columnPopulations_ = columnPopulations;
129     }
130     else
131     {
132       columnPopulations_ = new ArrayList();
133     }
134     
135     // Make sure song fits into column horizontally
136     scale_ = 1;
137     if (columnWidth_ < fullRender_.getWidth())
138     {
139       if (columnWidth_ < fullRender_.getMinWidth())
140       {
141         float width = fullRender_.getMinWidth();
142         scale_ = columnWidth_/width;
143         columnWidth_ = width;
144       }
145       fullRender_ = fullRender_.createUsingWidth(columnWidth_);
146     }
147     else
148     {
149       columnWidth_ = fullRender_.getWidth();
150     }
151     BodyLayout fullBody = fullRender_.getBodyLayout();
152     int numBlocks = fullBody.getBlockCount();
153     
154     // Make sure blocks fit vertically
155     for (int i=0; i<numBlocks; ++i)
156     {
157       BodyLayout block = fullBody.getNthBlockLayout(i);
158       float h = block.getHeight();
159       if (h+EPSILON > imageableHeight/scale_)
160       {
161         scale_ = imageableHeight/(h+EPSILON);
162       }
163     }
164     
165     // Now we know the scale
166     float scaledImageableWidth = imageableWidth/scale_;
167     float scaledImageableHeight = imageableHeight/scale_;
168     
169     // Start arranging pages
170     pages_ = new ArrayList();
171     PageLayout curPage = new PageLayout();
172     float curY = fullRender_.getHeaderHeight();
173     pages_.add(curPage);
174     int curBlocksOnColumn = 0;
175     int curColumn = 0;
176     int pageColumn = 0;
177     
178     // Arrange each block, plus footer
179     int imax = fullRender_.hasFooter() ? numBlocks+1 : numBlocks;
180     for (int i=0; i<imax; ++i)
181     {
182       // Calc blockHeight, and initial guess at y position and new column height,
183       // assuming the block shows up on the current column
184       float y;
185       if (i == numBlocks)
186       {
187         y = curY + fullRender_.getFooterSeparation();
188       }
189       else if (i == 0)
190       {
191         y = curY + fullRender_.getHeaderSeparation();
192       }
193       else
194       {
195         y = curY + fullRender_.getBlockSpacing();
196       }
197       float blockHeight;
198       if (i == numBlocks)
199       {
200         blockHeight = fullRender_.getFooterHeight();
201       }
202       else
203       {
204         blockHeight = fullBody.getNthBlockLayout(i).getHeight();
205       }
206       float nh = y + blockHeight;
207       
208       // Determine if the block should go on the next column.
209       boolean needsNewColumn;
210       if (columnPopulations != null)
211       {
212         needsNewColumn = (curBlocksOnColumn ==
213           ((Integer)columnPopulations.get(curColumn)).intValue());
214       }
215       else
216       {
217         needsNewColumn = nh > scaledImageableHeight;
218       }
219       
220       // Create new column if necessary
221       if (needsNewColumn)
222       {
223         if (pages_.size() == 1 && pageColumn > 0)
224         {
225           // On the first page, if the column is not the first column, attempt
226           // to move it down to start after the header, if there's room.
227           float delta = Math.min(scaledImageableHeight-curY,
228             fullRender_.getHeaderHeight()+fullRender_.getHeaderSeparation());
229           for (Iterator iter = curPage.blocks.iterator(); iter.hasNext(); )
230           {
231             BlockLayout block = (BlockLayout)iter.next();
232             if (block.column == pageColumn)
233             {
234               block.yPosition += delta;
235             }
236           }
237           curY += delta;
238           if (curY > curPage.height)
239           {
240             curPage.height = curY;
241           }
242         }
243         ++pageColumn;
244         if (pageColumn == numColumns_)
245         {
246           curPage = new PageLayout();
247           pages_.add(curPage);
248           pageColumn = 0;
249         }
250         y = 0;
251         nh = blockHeight;
252         if (columnPopulations == null)
253         {
254           columnPopulations_.add(new Integer(curBlocksOnColumn));
255         }
256         curBlocksOnColumn = 0;
257         ++curColumn;
258       }
259       
260       // Add block
261       if (i == numBlocks)
262       {
263         curPage.footerPos = y;
264       }
265       else
266       {
267         curPage.blocks.add(new BlockLayout(pageColumn, y,
268           fullBody.getNthBlockLayout(i)));
269       }
270       curY = nh;
271       if (curY > curPage.height)
272       {
273         curPage.height = curY;
274       }
275       ++curBlocksOnColumn;
276     }
277     if (pages_.size() == 1 && pageColumn > 0)
278     {
279       // On the first page, if the column is not the first column, attempt
280       // to move it down to start after the header, if there's room.
281       float delta = Math.min(scaledImageableHeight-curY,
282         fullRender_.getHeaderHeight()+fullRender_.getHeaderSeparation());
283       for (Iterator iter = curPage.blocks.iterator(); iter.hasNext(); )
284       {
285         BlockLayout block = (BlockLayout)iter.next();
286         if (block.column == pageColumn)
287         {
288           block.yPosition += delta;
289         }
290       }
291       curY += delta;
292       if (curY > curPage.height)
293       {
294         curPage.height = curY;
295       }
296     }
297     
298     // Finish
299     if (columnPopulations == null)
300     {
301       // Record population of last column
302       columnPopulations_.add(new Integer(curBlocksOnColumn));
303     }
304     else
305     {
306       // adjust the scale if necessary
307       float maxHeight = 0;
308       for (Iterator iter = pages_.iterator(); iter.hasNext(); )
309       {
310         curPage = (PageLayout)iter.next();
311         if (curPage.height > maxHeight)
312         {
313           maxHeight = curPage.height;
314         }
315       }
316       if (maxHeight > scaledImageableHeight)
317       {
318         scale_ = imageableHeight/maxHeight;
319       }
320     }
321   }
322   
323   
324   /*package*/ PrintRenderHelper createUsingGraphics(
325     Graphics2D g2d)
326   {
327     RenderHelper newFullRender = fullRender_.createUsingGraphics(g2d);
328     return new PrintRenderHelper(newFullRender, imageableWidth_, imageableHeight_,
329       numColumns_, unscaledGutterWidth_, columnPopulations_);
330   }
331   
332   
333   /*package*/ int getNumPages()
334   {
335     return pages_.size();
336   }
337   
338   
339   /*package*/ float getRequiredScale()
340   {
341     return scale_;
342   }
343   
344   
345   /*package*/ int getNumColumns()
346   {
347     return numColumns_;
348   }
349   
350   
351   /*package*/ float getColumnWidth()
352   {
353     return columnWidth_;
354   }
355   
356   
357   /*package*/ float getGutterWidth()
358   {
359     return gutterWidth_;
360   }
361   
362   
363   /*package*/ float getWidth()
364   {
365     return (columnWidth_+gutterWidth_)*numColumns_-gutterWidth_;
366   }
367   
368   
369   /*package*/ float getHeightForPage(
370     int pageNum)
371   {
372     return ((PageLayout)pages_.get(pageNum)).height;
373   }
374   
375   
376   /*package*/ void paintPage(
377     int pageNum,
378     Graphics2D g2d,
379     float x,
380     float y)
381   {
382     RenderHelper.mungeGraphics2D(g2d);
383     g2d.setColor(Color.black);
384     PageLayout pageLayout = (PageLayout)pages_.get(pageNum);
385     if (pageNum == 0)
386     {
387       fullRender_.paintHeader(g2d, x, y);
388     }
389     if (pageLayout.footerPos != 0)
390     {
391       fullRender_.paintFooter(g2d, x, y+pageLayout.footerPos);
392     }
393     for (Iterator iter = pageLayout.blocks.iterator(); iter.hasNext(); )
394     {
395       BlockLayout blockLayout = (BlockLayout)iter.next();
396       fullRender_.paintBlock(blockLayout.layout, g2d,
397         x+(columnWidth_+gutterWidth_)*blockLayout.column,
398         y+blockLayout.yPosition);
399     }
400   }
401 }