View Javadoc

1   package net.sf.statcvs.pages;
2   
3   import java.io.FileWriter;
4   import java.io.IOException;
5   import java.text.DecimalFormat;
6   import java.text.NumberFormat;
7   import java.util.ArrayList;
8   import java.util.Collections;
9   import java.util.Date;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.logging.Logger;
13  
14  import net.sf.statcvs.Messages;
15  import net.sf.statcvs.charts.ChartImage;
16  import net.sf.statcvs.model.Directory;
17  import net.sf.statcvs.output.ReportConfig;
18  import net.sf.statcvs.renderer.TableRenderer;
19  import net.sf.statcvs.reports.TableReport;
20  
21  public class Page implements NavigationNode {
22      private final static NumberFormat[] DOUBLE_FORMATS = { new DecimalFormat("0"), new DecimalFormat("0.0"), new DecimalFormat("0.00"),
23              new DecimalFormat("0.000"), new DecimalFormat("0.0000") };
24      private final static Logger logger = Logger.getLogger("sf.net.statcvs");
25  
26      private final ReportConfig config;
27      private final String fileName;
28      private final String shortTitle;
29      private final String fullTitle;
30      private final MarkupSyntax outputFormat;
31      private StringBuffer contents = new StringBuffer();
32      private NavigationNode parent = null;
33      private String siblingsTitle = null;
34      private List siblings = Collections.EMPTY_LIST;
35      private final List children = new ArrayList();
36      private final List attributeKeys = new ArrayList();
37      private final List attributeValues = new ArrayList();
38      private boolean showLinkToPreviousSibling = false;
39      private boolean inSection = false;
40      private boolean written = false;
41  
42      /**
43       * Creates a new page.
44       * @param config The configuration to use
45       * @param fileName File name for the page, <em>without</em> file extension
46       * @param shortTitle A short navigation title
47       * @param fullTitle A full headline title
48       */
49      public Page(final ReportConfig config, final String fileName, final String shortTitle, final String fullTitle) {
50          this.config = config;
51          this.fileName = fileName;
52          this.shortTitle = shortTitle;
53          this.fullTitle = fullTitle;
54          this.outputFormat = config.getMarkup();
55      }
56  
57      /* (non-Javadoc)
58       * @see net.sf.statcvs.pages.NavigationNode#setParent(net.sf.statcvs.pages.NavigationNode)
59       */
60      public void setParent(final NavigationNode parent) {
61          this.parent = parent;
62      }
63  
64      /**
65       * Sets a list of {@link Page}s that are siblings of this page.
66       * The generated page will contain a navigation list that links
67       * to all siblings. The sibling list may contain the page
68       * itself.
69       * @param siblingsTitle Title for navigation list, e.g. "Monthly Reports"
70       * @param sibling A list of {@link Page}s
71       */
72      public void setSiblings(final String siblingsTitle, final List siblingPages) {
73          this.siblingsTitle = siblingsTitle;
74          this.siblings = siblingPages;
75      }
76  
77      public void addChild(final NavigationNode child) {
78          this.children.add(child);
79          child.setParent(this);
80      }
81  
82      /* (non-Javadoc)
83       * @see net.sf.statcvs.pages.NavigationNode#getURL()
84       */
85      public String getURL() {
86          return this.fileName + ".html";
87      }
88  
89      /* (non-Javadoc)
90       * @see net.sf.statcvs.pages.NavigationNode#getShortTitle()
91       */
92      public String getShortTitle() {
93          return this.shortTitle;
94      }
95  
96      /* (non-Javadoc)
97       * @see net.sf.statcvs.pages.NavigationNode#getFullTitle()
98       */
99      public String getFullTitle() {
100         return this.fullTitle;
101     }
102 
103     public void setShowLinkToPreviousSibling(final boolean showLink) {
104         this.showLinkToPreviousSibling = showLink;
105     }
106 
107     public void addAttribute(final String key, final int value) {
108         addAttribute(key, Integer.toString(value));
109     }
110 
111     public void addAttribute(final String key, final int value, final String unit) {
112         addAttribute(key, Integer.toString(value) + " " + unit);
113     }
114 
115     public void addAttribute(final String key, final Date value) {
116         addRawAttribute(key, HTML.getDateAndTime(value));
117     }
118 
119     public void addAttribute(final String key, final String value) {
120         addRawAttribute(key, HTML.escape(value));
121     }
122 
123     public void addAttribute(final String key, final double value, final int decimalPlaces) {
124         addAttribute(key, DOUBLE_FORMATS[decimalPlaces].format(value));
125     }
126 
127     public void addAttribute(final String key, final double value, final int decimalPlaces, final String unit) {
128         addAttribute(key, DOUBLE_FORMATS[decimalPlaces].format(value) + " " + unit);
129     }
130 
131     public void addRawAttribute(final String key, final String rawValue) {
132         this.attributeKeys.add(key);
133         this.attributeValues.add(rawValue);
134     }
135 
136     public void addRawContent(final String s) {
137         this.contents.append(s);
138     }
139 
140     public void addSection(final String title) {
141         if (this.inSection) {
142             this.contents.append(this.outputFormat.endSection2());
143         }
144         this.contents.append(this.outputFormat.startSection2(title));
145         this.inSection = true;
146     }
147 
148     public void addLink(final String url, final String text) {
149         this.addRawContent("<p>" + HTML.getLink(url, text) + "</p>\n");
150     }
151 
152     public void add(final ChartImage chart) {
153         if (chart == null) {
154             return;
155         }
156         addRawContent("<p class=\"chart\"><img src=\"" + HTML.escape(chart.getURL()) + "\" alt=\"" + HTML.escape(chart.getFullTitle()) + "\" width=\""
157                 + chart.getWidth() + "\" height=\"" + chart.getHeight() + "\" /></p>");
158         chart.write();
159     }
160 
161     public void add(final ChartImage chart, final String linkURL) {
162         if (chart == null) {
163             return;
164         }
165         addRawContent("<p class=\"chart\"><a href=\"" + HTML.escape(linkURL) + "\"><img src=\"" + HTML.escape(chart.getURL()) + "\" alt=\""
166                 + HTML.escape(chart.getFullTitle()) + "\" width=\"" + chart.getWidth() + "\" height=\"" + chart.getHeight() + "\" /></a></p>");
167         chart.write();
168     }
169 
170     public void add(final TableReport table) {
171         table.calculate();
172         addRawContent(new TableRenderer(table.getTable(), this.outputFormat).getRenderedTable());
173     }
174 
175     public void add(final Directory directory, final boolean withRootLinks) {
176         addRawContent(new DirectoryTreeFormatter(directory, withRootLinks).getFormatted());
177     }
178 
179     public void add(final PageGroup pages) {
180         addRawContent(pages.asLinkList());
181         addChild(pages);
182     }
183 
184     /* (non-Javadoc)
185      * @see net.sf.statcvs.pages.NavigationNode#write()
186      */
187     public void write() {
188         if (this.written) {
189             return;
190         }
191         if (this.inSection) {
192             this.contents.append(this.outputFormat.endSection2());
193         }
194         final Iterator it = this.children.iterator();
195         while (it.hasNext()) {
196             final NavigationNode page = (NavigationNode) it.next();
197             page.write();
198         }
199         final String fileWithExtension = this.fileName + "." + this.config.getMarkup().getExtension();
200         logger.info("writing page '" + this.fullTitle + "' to " + fileWithExtension);
201         FileWriter w = null;
202         try {
203             w = new FileWriter(this.config.getRootDirectory() + fileWithExtension);
204             w.write(this.outputFormat.getHeader(this.fullTitle, this.config.getCssHandler().getLink()));
205             w.write(this.outputFormat.startSection1(this.fullTitle));
206             w.write(getLinkToParent());
207             w.write(getNavigationLinks());
208             w.write(getAttributes());
209             w.write(this.contents.toString());
210             w.write(getLinkToPreviousSibling());
211             w.write(this.outputFormat.endSection1());
212             w.write(getGeneratedByBlock());
213             w.write(this.outputFormat.getEndOfPage());
214         } catch (final IOException ex) {
215             logger.warning(ex.getMessage());
216         } finally {
217             if (w != null) {
218                 try {
219                     w.close();
220                 } catch (final IOException e) {
221                     logger.warning(e.getMessage());
222                 }
223             }
224         }
225         this.written = true;
226 
227         // Free memory? Not sure if this has any effect ...
228         this.contents = null;
229     }
230 
231     public String asParentLink() {
232         String result = "&#171; " + HTML.getLink(getURL(), getShortTitle());
233         if (this.parent != null) {
234             result = this.parent.asParentLink() + " " + result;
235         }
236         return result;
237     }
238 
239     private String getLinkToParent() {
240         if (this.parent == null) {
241             return "";
242         }
243         return "<div id=\"parentlink\">" + this.parent.asParentLink() + "</div>\n";
244     }
245 
246     private String getNavigationLinks() {
247         if (this.siblingsTitle == null || this.siblings.isEmpty()) {
248             return "";
249         }
250         final StringBuffer s = new StringBuffer();
251         s.append(this.outputFormat.startSection2(this.siblingsTitle, "nav"));
252         s.append("<ul>\n");
253         final Iterator it = this.siblings.iterator();
254         while (it.hasNext()) {
255             final NavigationNode sibling = (NavigationNode) it.next();
256             s.append("    <li>");
257             if (sibling == this) {
258                 s.append("<span class=\"here\">" + HTML.escape(sibling.getShortTitle()) + "</span>");
259             } else {
260                 s.append(HTML.getLink(sibling.getURL(), sibling.getShortTitle()));
261             }
262             s.append("</li>\n");
263         }
264         s.append("</ul>\n");
265         s.append(this.outputFormat.endSection2());
266         return s.toString();
267     }
268 
269     private String getAttributes() {
270         if (this.attributeKeys.isEmpty()) {
271             return "";
272         }
273         final StringBuffer s = new StringBuffer();
274         s.append("<dl class=\"attributes\">\n");
275         for (int i = 0; i < this.attributeKeys.size(); i++) {
276             final String key = (String) this.attributeKeys.get(i);
277             final String value = (String) this.attributeValues.get(i);
278             s.append("    <dt>" + HTML.escape(key) + ":</dt>\n");
279             s.append("    <dd>" + value + "</dd>\n");
280         }
281         s.append("</dl>\n");
282         return s.toString();
283     }
284 
285     private String getGeneratedByBlock() {
286         final StringBuffer s = new StringBuffer();
287         s.append("<div id=\"generatedby\">");
288         s.append(Messages.getString("PAGE_GENERATED_BY"));
289         s.append(" ");
290         s.append(HTML.getLink(Messages.getString("PROJECT_URL"), Messages.getString("PROJECT_SHORTNAME")) + " " + Messages.getString("PROJECT_VERSION"));
291         s.append("</div>\n");
292         return s.toString();
293     }
294 
295     private String getLinkToPreviousSibling() {
296         if (!this.showLinkToPreviousSibling) {
297             return "";
298         }
299         final NavigationNode sibling = findPreviousSibling();
300         if (sibling == null) {
301             return "";
302         }
303         return "<p class=\"previous\">" + HTML.getLink(sibling.getURL(), sibling.getShortTitle()) + " &#187; </p>\n";
304     }
305 
306     private NavigationNode findPreviousSibling() {
307         final Iterator it = this.siblings.iterator();
308         while (it.hasNext()) {
309             final NavigationNode sibling = (NavigationNode) it.next();
310             if (sibling != this) {
311                 continue;
312             }
313             if (!it.hasNext()) {
314                 return null;
315             }
316             return (NavigationNode) it.next();
317         }
318         return null;
319     }
320 }