added better support for article urls in PDF files
[mir.git] / source / mircoders / pdf / PDFGenerator.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mircoders.pdf;
31
32 import gnu.regexp.RE;
33 import gnu.regexp.REException;
34 import gnu.regexp.REMatch;
35 import gnu.regexp.REMatchEnumeration;
36
37 import java.io.ByteArrayOutputStream;
38 import java.io.IOException;
39 import java.net.MalformedURLException;
40 import java.util.*;
41
42 import mir.config.MirPropertiesConfiguration;
43 import mir.entity.EntityBrowser;
44 import mir.entity.adapter.EntityAdapter;
45 import mir.log.LoggerWrapper;
46 import mir.misc.StringUtil;
47 import mir.util.DateTimeRoutines;
48 import mir.util.HTMLRoutines;
49 import mir.util.ParameterExpander;
50 import mir.generator.GeneratorHelper;
51 import mir.generator.GeneratorExc;
52 import mircoders.entity.EntityContent;
53 import mircoders.entity.EntityImages;
54 import mircoders.storage.DatabaseImages;
55 import mircoders.global.MirGlobal;
56 import mircoders.localizer.MirLocalizerExc;
57
58 import com.lowagie.text.BadElementException;
59 import com.lowagie.text.Document;
60 import com.lowagie.text.DocumentException;
61 import com.lowagie.text.Element;
62 import com.lowagie.text.Font;
63 import com.lowagie.text.Image;
64 import com.lowagie.text.PageSize;
65 import com.lowagie.text.Paragraph;
66 import com.lowagie.text.Phrase;
67 import com.lowagie.text.pdf.BaseFont;
68 import com.lowagie.text.pdf.ColumnText;
69 import com.lowagie.text.pdf.PdfContentByte;
70 import com.lowagie.text.pdf.PdfTemplate;
71 import com.lowagie.text.pdf.PdfWriter;
72 import multex.Failure;
73
74 public class PDFGenerator {
75   public Document document;
76   public PdfWriter writer;
77   public PdfContentByte cb;
78   public String localImageDir;
79   public float currentYPosition;
80   public int currentPage;
81   public float pageWidth;
82   public float pageHeight;
83   public float verticalMargin;
84   public float horizontalMargin;
85   public float topEdge;
86   public float bottomEdge;
87   public float rightEdge;
88   public float leftEdge;
89
90   public int maxImageHeight;
91   public int maxImageWidth;
92   protected LoggerWrapper logger;
93
94   public int indexFontSize;
95   public int indexLineHeight;
96   public int indexFontFamily;
97
98   public float footerHeight;
99   public String footerText;
100   public int footerFontSize;
101   public int footerFontFamily;
102
103   public int metaHeight;
104   public int metaFontSize;
105   public int metaFontFamily;
106
107   public int descriptionLineHeight;
108   public int descriptionFontSize;
109   public int descriptionFontFamily;
110
111   public int contentLineHeight;
112   public int contentFontSize;
113   public int contentFontFamily;
114
115   public int sourceLineHeight;
116   public int sourceFontSize;
117   public int sourceFontFamily;
118
119   public int bigImageCaptionFontSize;
120   public int bigImageCaptionFontFamily;
121
122   protected MirPropertiesConfiguration configuration;
123
124
125   public PDFGenerator(ByteArrayOutputStream out) {
126     logger = new LoggerWrapper("PDFGenerator");
127     configuration = MirPropertiesConfiguration.instance();
128     localImageDir = configuration.getString("Producer.Image.Path");
129
130     try {
131       indexFontSize = Integer.parseInt(configuration.getString("PDF.Index.FontSize"));
132       indexLineHeight = Integer.parseInt(configuration.getString("PDF.Index.LineHeight"));
133       indexFontFamily = getFontByName(configuration.getString("PDF.Index.FontFamily"));
134
135       footerText = configuration.getString("PDF.Footer.String");
136       footerFontSize = Integer.parseInt(configuration.getString("PDF.Footer.FontSize"));
137       footerFontFamily = getFontByName(configuration.getString("PDF.Footer.FontFamily"));
138       footerHeight = Integer.parseInt(configuration.getString("PDF.Footer.Height"));
139
140       metaFontSize = Integer.parseInt(configuration.getString("PDF.Meta.FontSize"));
141       metaFontFamily = getFontByName(configuration.getString("PDF.Meta.FontFamily"));
142       metaHeight = Integer.parseInt(configuration.getString("PDF.Meta.Height"));
143
144       descriptionFontSize = Integer.parseInt(configuration.getString("PDF.Description.FontSize"));
145       descriptionLineHeight = Integer.parseInt(configuration.getString("PDF.Description.LineHeight"));
146       descriptionFontFamily = getFontByName(configuration.getString("PDF.Description.FontFamily"));
147
148       contentFontSize = Integer.parseInt(configuration.getString("PDF.Content.FontSize"));
149       contentLineHeight = Integer.parseInt(configuration.getString("PDF.Content.LineHeight"));
150       contentFontFamily = getFontByName(configuration.getString("PDF.Content.FontFamily"));
151
152       sourceFontSize = Integer.parseInt(configuration.getString("PDF.Source.FontSize"));
153       sourceLineHeight = Integer.parseInt(configuration.getString("PDF.Source.LineHeight"));
154       sourceFontFamily = getFontByName(configuration.getString("PDF.Source.FontFamily"));
155
156       bigImageCaptionFontSize = Integer.parseInt(configuration.getString("PDF.BigImageCaption.FontSize"));
157       bigImageCaptionFontFamily = getFontByName(configuration.getString("PDF.BigImageCaption.FontFamily"));
158
159     }
160     catch (NumberFormatException e) {
161       throw new Failure(e.getMessage(), e);
162     }
163
164     // step 1: make a document
165
166     String pageSize = configuration.getString("PDF.Pagesize");
167
168     if (pageSize.equals("LETTER")) {
169       document = new Document(PageSize.LETTER);
170       pageWidth = 612;
171       pageHeight = 792;
172     } else {
173       document = new Document(PageSize.A4);
174       pageWidth = 595;
175       pageHeight = 842;
176     }
177
178     maxImageHeight = 250;
179     maxImageWidth = 250;
180
181
182     verticalMargin = 20;
183     horizontalMargin = 20;
184
185
186     topEdge = pageHeight - verticalMargin;
187     bottomEdge = verticalMargin;
188     rightEdge = pageWidth - horizontalMargin;
189     leftEdge = horizontalMargin;
190
191     currentYPosition = topEdge;
192     currentPage = 1;
193
194     String headerText = configuration.getString("PDF.Title.String");
195
196     try {
197       writer = PdfWriter.getInstance(document, out);
198       cb = writer.getDirectContent();
199
200       document.open();
201       addHeader(headerText);
202     }
203     catch (DocumentException de) {
204       logger.error(de.getMessage());
205     }
206   }
207
208   public void stop() {
209     addFooter();
210     document.close();
211   }
212
213   public void addHeader(String headerText) {
214     int titleFontSize = Integer.parseInt(configuration.getString("PDF.Title.FontSize"));
215     int titleLineHeight = Integer.parseInt(configuration.getString("PDF.Title.LineHeight"));
216     String titleFontFamily = configuration.getString("PDF.Title.FontFamily");
217     String headerImage = configuration.getString("PDF.Header.Image");
218     int headerImageHeight = Integer.parseInt(configuration.getString("PDF.Header.ImageHeight"));
219
220     try {
221       if ((! headerImage.equals("")) && headerImageHeight != 0) {
222         PdfTemplate template = cb.createTemplate(rightEdge - horizontalMargin, headerImageHeight);
223
224         float toYPosition = currentYPosition - headerImageHeight;
225         Image theImage = Image.getInstance(headerImage);
226         theImage.setAbsolutePosition(0, 0);
227         //      theImage.scaleAbsolute(img_width,img_height);
228         template.addImage(theImage);
229
230
231         cb.addTemplate(template, leftEdge, toYPosition);
232         currentYPosition = toYPosition;
233       }
234       if (! headerText.equals("")) {
235         ColumnText ct = new ColumnText(cb);
236         //add a basic header
237         ct.addText(new Phrase(headerText, new Font(getFontByName(titleFontFamily), titleFontSize, Font.BOLD)));
238         float[] rightCol = {rightEdge, currentYPosition, rightEdge, currentYPosition - titleLineHeight};
239         float[] leftCol = {leftEdge, currentYPosition, leftEdge, currentYPosition - titleLineHeight};
240         ct.setColumns(leftCol, rightCol);
241         ct.setYLine(currentYPosition);
242         ct.setAlignment(Element.ALIGN_CENTER);
243         ct.go();
244
245         currentYPosition = currentYPosition - titleLineHeight;
246       }
247     }
248     catch (DocumentException de) {
249       logger.error(de.getMessage());
250     }
251     catch (MalformedURLException de) {
252       logger.error(de.getMessage());
253     }
254     catch (IOException de) {
255       logger.error(de.getMessage());
256     }
257   }
258
259   public void addIndexItem(EntityContent entityContent) {
260     try {
261
262       ColumnText ict = new ColumnText(cb);
263       String theTitle = entityContent.getFieldValue("title");
264       String theCreator = entityContent.getFieldValue("creator");
265       Phrase titleP = new Phrase(" - " + theTitle, new Font(indexFontFamily, indexFontSize, Font.BOLD));
266       Phrase creatorP = new Phrase(" :: " + theCreator, new Font(indexFontFamily, indexFontSize));
267       float toYPosition = currentYPosition - indexLineHeight;
268       float[] leftIndexCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
269       float[] rightIndexCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
270       ict.addText(titleP);
271       ict.addText(creatorP);
272       ict.setColumns(leftIndexCols, rightIndexCols);
273       ict.setYLine(currentYPosition);
274       ict.setAlignment(Element.ALIGN_LEFT);
275       ict.go();
276       currentYPosition = toYPosition;
277     }
278     catch (DocumentException de) {
279       logger.error(de.getMessage());
280     }
281
282
283   }
284
285   private int addTextLine(ColumnText ct, int lineHeight, int alignment, float left, float right) {
286     logger.debug("adding a line of text");
287     if (! enoughY(lineHeight)) {
288       newPage();
289     }
290     float toYPosition = currentYPosition - lineHeight;
291     float[] leftContentCols = {left, currentYPosition, left, toYPosition};
292     float[] rightContentCols = {right, currentYPosition, right, toYPosition};
293     ct.setColumns(leftContentCols, rightContentCols);
294     ct.setYLine(currentYPosition);
295     ct.setAlignment(alignment);
296     try {
297       int status = ct.go();
298       currentYPosition = toYPosition;
299       return status;
300     }
301     catch (DocumentException de) {
302       logger.error(de.getMessage());
303     }
304     return 0;
305   }
306
307   public void addLine() {
308     cb.setLineWidth(1f);
309     cb.moveTo(rightEdge, currentYPosition - 5);
310     cb.lineTo(leftEdge, currentYPosition - 5);
311     cb.stroke();
312     currentYPosition = currentYPosition - 10;
313
314   }
315
316   public void addFooter() {
317     try {
318       ColumnText fct = new ColumnText(cb);
319       cb.setLineWidth(1f);
320       cb.moveTo(rightEdge, bottomEdge + footerHeight - 5);
321       cb.lineTo(leftEdge, bottomEdge + footerHeight - 5);
322       cb.stroke();
323       float[] leftFooterCols = {leftEdge, bottomEdge + footerHeight - 1, leftEdge, bottomEdge};
324       float[] rightFooterCols = {rightEdge, bottomEdge + footerHeight - 1, rightEdge, bottomEdge};
325
326       Paragraph footerP = new Paragraph(footerText, new Font(footerFontFamily, footerFontSize));
327       fct.addText(footerP);
328
329       fct.setColumns(leftFooterCols, rightFooterCols);
330       fct.setYLine(bottomEdge + footerHeight - 1);
331       fct.setAlignment(Element.ALIGN_JUSTIFIED);
332       fct.go();
333
334       Paragraph numberP = new Paragraph((new Integer(currentPage)).toString(), new Font(footerFontFamily, footerFontSize, Font.BOLD));
335       fct.addText(numberP);
336       fct.setAlignment(Element.ALIGN_RIGHT);
337       fct.go();
338
339     }
340     catch (DocumentException de) {
341       logger.error(de.getMessage());
342     }
343
344
345   }
346
347   public void newPage() {
348     try {
349       //add a footer
350       addFooter();
351       document.newPage();
352       currentPage++;
353       currentYPosition = topEdge;
354     }
355     catch (DocumentException de) {
356       logger.error(de.getMessage());
357     }
358   }
359
360   public void addArticleSeparator() {
361     // make a line
362     if (! enoughY(10)) {
363       newPage();
364     }
365     cb.setLineWidth(1f);
366     cb.moveTo(rightEdge, currentYPosition - 5);
367     cb.lineTo(leftEdge, currentYPosition - 5);
368     cb.stroke();
369     currentYPosition = currentYPosition - 10;
370   }
371
372   public void addArticleMetaInfo(ColumnText ct, String theTitle, String theCreator, String theDate) {
373     //see if we have room for the author and title
374
375     if (! enoughY(metaHeight)) {
376       newPage();
377     }
378
379     Paragraph titleP = new Paragraph(theTitle + "\n", new Font(metaFontFamily, metaFontSize, Font.BOLD));
380     Paragraph whowhenP = new Paragraph(theCreator + "  " + theDate, new Font(metaFontFamily, metaFontSize));
381     ct.addText(titleP);
382     ct.addText(whowhenP);
383
384     ct.setYLine(currentYPosition);
385     ct.setAlignment(Element.ALIGN_LEFT);
386
387     float toYPosition = currentYPosition - metaHeight;
388     float[] leftHeadCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
389     float[] rightHeadCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
390
391     ct.setColumns(leftHeadCols, rightHeadCols);
392     try {
393       ct.go();
394       currentYPosition = toYPosition;
395     }
396     catch (DocumentException de) {
397       logger.error(de.getMessage());
398     }
399
400   }
401
402   public void addArticleDescription(ColumnText ct, String theDescription) {
403     // Now we add the description, one line at a time, the ct should be empty at this point
404
405
406     Paragraph descP = new Paragraph(theDescription, new Font(descriptionFontFamily, descriptionFontSize, Font.BOLD));
407     ct.addText(descP);
408
409     // every article has a description, so we can assume that:
410     int status = ColumnText.NO_MORE_COLUMN;
411
412     int brake = 1000;
413     while ((status & ColumnText.NO_MORE_TEXT) == 0 && brake > 0) {
414       //there is still text left in the description.
415       status = addTextLine(ct, descriptionLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
416       brake--;
417     }
418     if (brake == 0)
419       logger.error("runaway description...try increasing the line height or decreasing the font size");
420   }
421
422   public void addArticleContent(ColumnText ct, String theContent, Iterator images) {
423     //let's go ahead and add in all the body text
424     Paragraph contentP = new Paragraph(theContent, new Font(contentFontFamily, contentFontSize));
425     ct.addText(contentP);
426
427     int contentLinesBeforeImages = 3;
428     //and assume we have at least one line of text in the content
429     int status = ColumnText.NO_MORE_COLUMN;
430
431     // let's add a little bit of text, like a couple of lines
432     int x = 0;
433     while (((status & ColumnText.NO_MORE_TEXT) == 0) && x < contentLinesBeforeImages) {
434       status = addTextLine(ct, contentLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
435       x++;
436     }
437
438     boolean addImageOnLeft = true; //we will alternate within articles
439     while (images.hasNext()) {
440
441       EntityImages currentImage = (EntityImages) images.next();
442       float img_width = (new Float(currentImage.getFieldValue("img_width"))).floatValue();
443       float img_height = (new Float(currentImage.getFieldValue("img_height"))).floatValue();
444       if (img_height > maxImageHeight) {
445         img_width = (new Float((new Float(img_width * (maxImageHeight / img_height))).intValue())).floatValue();
446         img_height = maxImageHeight;
447       }
448       if (img_width > maxImageWidth) {
449         img_height = (new Float((new Float(img_height * (maxImageWidth / img_width))).intValue())).floatValue();
450         img_width = maxImageWidth;
451       }
452
453       String img_title = currentImage.getFieldValue("title");
454       String img_path = currentImage.getFieldValue("publish_path");
455
456       if ((status & ColumnText.NO_MORE_TEXT) == 0) {
457         // there is still text, so add an image which will have text wrapped around it, then add the text which
458         // will be on the left or the right of the image
459
460         float templateMinimumHeight = img_height + 20;
461         float templateWidth = img_width + 10;
462         float templateHeight = templateMinimumHeight + contentLineHeight - (templateMinimumHeight % contentLineHeight);
463
464         PdfTemplate template = cb.createTemplate(templateWidth, templateHeight);
465
466         //here we need a page check
467         if (! enoughY((new Float(templateHeight)).intValue())) {
468           //ok, well just fill text to the bottom then
469           float toYPosition = bottomEdge + footerHeight;
470           float[] leftBottomCols = {leftEdge, currentYPosition, leftEdge, toYPosition};
471           float[] rightBottomCols = {rightEdge, currentYPosition, rightEdge, toYPosition};
472           ct.setColumns(leftBottomCols, rightBottomCols);
473           ct.setYLine(currentYPosition);
474           ct.setAlignment(Element.ALIGN_JUSTIFIED);
475           try {
476             status = ct.go();
477           }
478           catch (DocumentException de) {
479             logger.error(de.getMessage());
480           }
481           newPage();
482         }
483
484         float toYPosition = currentYPosition - templateHeight;
485
486         try {
487           Image theImage = Image.getInstance(localImageDir + img_path);
488           theImage.scaleAbsolute(img_width, img_height);
489           theImage.setAbsolutePosition(5, 13);
490
491           template.addImage(theImage);
492           template.beginText();
493           BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
494           template.setFontAndSize(bf, 8);
495           template.setTextMatrix(5, 3);
496           template.showText(img_title);
497           template.endText();
498         }
499         catch (BadElementException de) {
500           logger.error(de.getMessage());
501         }
502         catch (DocumentException de) {
503           logger.error(de.getMessage());
504         }
505         catch (MalformedURLException de) {
506           logger.error(de.getMessage());
507         }
508         catch (IOException de) {
509           logger.error(de.getMessage());
510         }
511
512
513         float leftImageTextEdge = leftEdge;
514         float rightImageTextEdge = rightEdge;
515
516
517         if (addImageOnLeft) {
518           cb.addTemplate(template, leftEdge, toYPosition);
519           leftImageTextEdge = leftEdge + templateWidth + 5;
520           addImageOnLeft = false;
521         } else {
522           cb.addTemplate(template, rightEdge - templateWidth, toYPosition);
523           rightImageTextEdge = rightEdge - templateWidth - 5;
524           addImageOnLeft = true;
525         }
526
527         logger.debug("adding template at " + leftEdge + "," + toYPosition);
528
529         //and fill some text while we are at it
530
531         float[] leftBottomCols = {leftImageTextEdge, currentYPosition, leftImageTextEdge, toYPosition};
532         float[] rightBottomCols = {rightImageTextEdge, currentYPosition, rightImageTextEdge, toYPosition};
533         ct.setColumns(leftBottomCols, rightBottomCols);
534         ct.setYLine(currentYPosition);
535         ct.setAlignment(Element.ALIGN_JUSTIFIED);
536         try {
537           status = ct.go();
538           currentYPosition = toYPosition;
539         }
540         catch (DocumentException de) {
541           logger.error(de.getMessage());
542         }
543
544
545       } else {
546         //add an image on the left with a big caption to the right
547         currentYPosition = currentYPosition - 10;
548         float templateMinimumHeight = img_height;
549         float templateWidth = img_width;
550         float templateHeight = templateMinimumHeight + contentLineHeight - (templateMinimumHeight % contentLineHeight);
551         PdfTemplate template = cb.createTemplate(templateWidth, templateHeight);
552         if (! enoughY((new Float(templateHeight)).intValue())) {
553           newPage();
554         }
555         float toYPosition = currentYPosition - templateHeight;
556         try {
557           Image theImage = Image.getInstance(localImageDir + img_path);
558           theImage.setAbsolutePosition(0, 13);
559           theImage.scaleAbsolute(img_width, img_height);
560           template.addImage(theImage);
561         }
562         catch (BadElementException de) {
563           logger.error(de.getMessage());
564         }
565         catch (DocumentException de) {
566           logger.error(de.getMessage());
567         }
568         catch (MalformedURLException de) {
569           logger.error(de.getMessage());
570         }
571         catch (IOException de) {
572           logger.error(de.getMessage());
573         }
574
575         cb.addTemplate(template, leftEdge, toYPosition);
576
577         // add a big caption
578         ColumnText cct = new ColumnText(cb);
579         float[] leftCaptionCols = {leftEdge + templateWidth + 5, currentYPosition - 5, leftEdge + templateWidth + 5, toYPosition};
580         float[] rightCaptionCols = {rightEdge, currentYPosition - 5, rightEdge, toYPosition};
581
582         Paragraph captionP = new Paragraph(img_title, new Font(bigImageCaptionFontFamily, bigImageCaptionFontSize, Font.BOLD));
583         cct.addText(captionP);
584         cct.setColumns(leftCaptionCols, rightCaptionCols);
585         cct.setYLine(currentYPosition - 5);
586         cct.setAlignment(Element.ALIGN_LEFT);
587         try {
588           cct.go();
589           currentYPosition = toYPosition;
590         }
591         catch (DocumentException de) {
592           logger.error(de.getMessage());
593         }
594       }
595     }
596
597     //add the rest of the text which might be left
598     int brake = 10000;
599     while ((status & ColumnText.NO_MORE_TEXT) == 0 && brake > 0) {
600       status = addTextLine(ct, contentLineHeight, Element.ALIGN_JUSTIFIED, leftEdge, rightEdge);
601       brake --;
602     }
603     if (brake == 0)
604       logger.error("runaway content....try decreasing font size or increasing line height");
605   }
606
607   private void addArticleSource(ColumnText ct, String theSource) {
608     Paragraph sourceP = new Paragraph(theSource, new Font(sourceFontFamily, sourceFontSize, Font.BOLD));
609     ct.addText(sourceP);
610     addTextLine(ct, sourceLineHeight, Element.ALIGN_RIGHT, leftEdge, rightEdge);
611   }
612
613
614   private boolean enoughY(int heightOfBlockToAdd) {
615     if ((currentYPosition - heightOfBlockToAdd - footerHeight) < bottomEdge)
616       return false;
617     return true;
618   }
619
620
621   public void add(EntityContent anArticle, Locale aLocale) throws GeneratorExc, MirLocalizerExc, Exception {
622     logger.debug("adding a content Entity");
623
624     /*
625      * initialize
626      * separate
627      * meta info
628      * description
629      * content
630      * --image with text
631      * --normal text
632      * --image without text
633      * source
634     */
635
636     List extraTables = new ArrayList();
637     extraTables.add("content_x_media cxm");
638     Iterator images = new EntityBrowser(
639         DatabaseImages.getInstance(), "i", extraTables,
640         "cxm.content_id=" + anArticle.getId() + "and cxm.media_id=i.id",
641         "i.id desc", 30, -1, 0);
642
643     String isHTML = anArticle.getFieldValue("is_html");
644     String theTitle = anArticle.getFieldValue("title");
645     String theCreator = anArticle.getFieldValue("creator");
646     String theDate = DateTimeRoutines.advancedDateFormat(
647         configuration.getString("RDF.Meta.DateFormat"),
648         StringUtil.convertMirInternalDateToDate(anArticle.getFieldValue("webdb_create")),
649         configuration.getString("Mir.DefaultTimezone"));
650
651
652     String theDescriptionRaw = anArticle.getFieldValue("description");
653     String theContentRaw = anArticle.getFieldValue("content_data");
654
655     MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
656     Map variables = GeneratorHelper.makeBasicGenerationData(new Locale[] {
657             aLocale ,new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "")},
658             "bundles.open","bundles.open");
659
660     EntityAdapter article =
661             MirGlobal.localizer().dataModel().adapterModel().makeEntityAdapter("content", anArticle);
662     variables.put("article", article);
663     String source = ParameterExpander.expandExpression(
664             variables,
665             configuration.getString("PDF.Source")
666     );
667     String theContent = "";
668     String theDescription = "";
669
670     if (isHTML.equals("1")) {
671
672
673       try {
674         RE nobackslashr = new RE("\r");
675         theContent = nobackslashr.substituteAll(theContentRaw, "");
676         theDescription = nobackslashr.substituteAll(theDescriptionRaw, "");
677
678         RE HxTag = new RE("</?h[1-6][^>]*>", RE.REG_ICASE);
679         theContent = HxTag.substituteAll(theContent, "\n\n");
680         theDescription = HxTag.substituteAll(theDescription, "\n\n");
681
682         RE ListItemTag = new RE("<li[^>]*>", RE.REG_ICASE);
683         theContent = ListItemTag.substituteAll(theContent, "\n * ");
684         theDescription = ListItemTag.substituteAll(theDescription, "\n * ");
685
686         RE ListTag = new RE("<(u|o)l[^>]*>", RE.REG_ICASE);
687         theContent = ListTag.substituteAll(theContent, "\n");
688         theDescription = ListTag.substituteAll(theDescription, "\n");
689
690         RE DivTag = new RE("</?div[^>]*>", RE.REG_ICASE);
691         theContent = DivTag.substituteAll(theContent, "\n");
692         theDescription = DivTag.substituteAll(theDescription, "\n");
693
694         RE PTag = new RE("<(p|P)([:space:]+[^>]*)?>");
695         theContent = PTag.substituteAll(theContent, "\n    ");
696         theDescription = PTag.substituteAll(theDescription, "\n    ");
697
698         RE PTagClose = new RE("</(p|P)([:space:]+[^>]*)?>");
699         theContent = PTagClose.substituteAll(theContent, "\n");
700         theDescription = PTagClose.substituteAll(theDescription, "\n");
701
702         RE BRTag = new RE("<(br|BR)([:space:]+[^>]*)?>");
703         theContent = BRTag.substituteAll(theContent, "\n");
704         theDescription = BRTag.substituteAll(theDescription, "\n");
705
706         RE ATagAll = new RE("<a[^>]*href=(?:\"|\')([^#\"\'][^\'\"]+)(?:\"|\')[^>]*>(.*?)</a>", RE.REG_ICASE);
707         REMatchEnumeration atags = ATagAll.getMatchEnumeration(theContent);
708         String theContentCopy = theContent;
709         while (atags.hasMoreMatches()) {
710           REMatch atag = atags.nextMatch();
711           String atagString = atag.toString();
712           String atagStringHref = atag.toString(1);
713           String atagStringText = atag.toString(2);
714           int begin = theContentCopy.indexOf(atagString);
715           theContentCopy = theContentCopy.substring(0, begin) + atagStringText + " [" + atagStringHref + "] " + theContentCopy.substring(begin + atagString.length());
716         }
717         theContent = theContentCopy;
718
719         REMatchEnumeration atags2 = ATagAll.getMatchEnumeration(theDescription);
720         String theDescriptionCopy = theDescription;
721         while (atags2.hasMoreMatches()) {
722           REMatch atag = atags2.nextMatch();
723           String atagString = atag.toString();
724           String atagStringHref = atag.toString(1);
725           String atagStringText = atag.toString(2);
726           int begin = theDescriptionCopy.indexOf(atagString);
727           theDescriptionCopy = theDescriptionCopy.substring(0, begin) + atagStringText + " [" + atagStringHref + "] " + theDescriptionCopy.substring(begin + atagString.length());
728         }
729         theDescription = theDescriptionCopy;
730
731
732         RE noTags = new RE("<[^>]*>");
733         theContent = noTags.substituteAll(theContent, " ");
734         theDescription = noTags.substituteAll(theDescription, " ");
735
736         theContent = HTMLRoutines.resolveHTMLEntites(theContent);
737         theDescription = HTMLRoutines.resolveHTMLEntites(theDescription);
738
739         RE re1 = new RE("\r?\n\r?\n");
740         String theDescription1 = re1.substituteAll(theDescription, "BREAKHERE");
741
742         RE re2 = new RE("\r?\n");
743         String theDescription2 = re2.substituteAll(theDescription1, " ");
744
745         RE re3 = new RE("BREAKHERE");
746         theDescription = re3.substituteAll(theDescription2, "\n    ");
747
748
749       }
750       catch (REException ree) {
751         logger.error(ree.getMessage());
752       }
753     } else {
754       try {
755         RE re1 = new RE("\r?\n\r?\n");
756         String theContent1 = re1.substituteAll(theContentRaw, "BREAKHERE");
757         String theDescription1 = re1.substituteAll(theDescriptionRaw, "BREAKHERE");
758
759         RE re2 = new RE("\r?\n");
760         String theContent2 = re2.substituteAll(theContent1, " ");
761         String theDescription2 = re2.substituteAll(theDescription1, " ");
762
763         RE re3 = new RE("BREAKHERE");
764         theContent = "    " + re3.substituteAll(theContent2, "\n    ");
765         theDescription = re3.substituteAll(theDescription2, "\n    ");
766
767       }
768       catch (REException ree) {
769         logger.error(ree.getMessage());
770       }
771     }
772
773     addArticleSeparator();
774
775     ColumnText ct = new ColumnText(cb);
776
777     addArticleMetaInfo(ct, theTitle, theCreator, theDate);
778     addArticleDescription(ct, theDescription);
779     addArticleContent(ct, theContent, images);
780     addArticleSource(ct, source);
781   }
782
783   public int getFontByName(String fontName) {
784     int theFont = 0;
785     if ("helvetica".equalsIgnoreCase(fontName)) {
786       theFont = Font.HELVETICA;
787     }
788     else if ("courier".equalsIgnoreCase(fontName)) {
789       theFont = Font.COURIER;
790     }
791     else if ("times".equalsIgnoreCase(fontName)) {
792       theFont = Font.TIMES_ROMAN;
793     }
794     else {
795       logger.error("using helvetica because I can't get font for name: " + fontName);
796       theFont = Font.HELVETICA;
797     }
798
799     return theFont;
800   }
801 }