Changeset 3862

Show
Ignore:
Timestamp:
11/22/11 10:07:10 (6 months ago)
Author:
sbrunner
Message:

Inline class rendering in multi columns, fix #650 r=jeichar

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • print/trunk/src/main/java/org/mapfish/print/config/layout/LegendsBlock.java

    r3861 r3862  
    2020package org.mapfish.print.config.layout; 
    2121 
     22import java.io.IOException; 
     23import java.net.URI; 
     24import java.util.ArrayList; 
     25 
     26import org.apache.log4j.Logger; 
     27import org.mapfish.print.InvalidValueException; 
     28import org.mapfish.print.PDFUtils; 
     29import org.mapfish.print.RenderingContext; 
     30import org.mapfish.print.utils.PJsonArray; 
     31import org.mapfish.print.utils.PJsonObject; 
     32 
     33import com.lowagie.text.Chunk; 
    2234import com.lowagie.text.DocumentException; 
    2335import com.lowagie.text.Font; 
     
    2840import com.lowagie.text.pdf.PdfPTable; 
    2941 
    30 import org.apache.log4j.Logger; 
    31 import org.mapfish.print.PDFUtils; 
    32 import org.mapfish.print.RenderingContext; 
    33 import org.mapfish.print.InvalidValueException; 
    34 import org.mapfish.print.utils.PJsonArray; 
    35 import org.mapfish.print.utils.PJsonObject; 
    36  
    37 import java.io.IOException; 
    38 import java.net.URI; 
    39  
    4042/** 
    4143 * Bean to configure a !legends block. 
     
    4648    public static final Logger LOGGER = Logger.getLogger(LegendsBlock.class); 
    4749 
    48     private double maxIconWidth = 0; 
    49     private double maxIconHeight = 8; 
     50    private double maxHeight = 0; // 0 mean multi column disable 
     51    private double maxWidth = 0; 
     52 
     53    private double maxIconWidth = 0; // 0 mean disable 
     54    private double maxIconHeight = 8; // 0 mean disable 
     55    private float scale = 0; // 0 mean disable 
     56    private boolean inline = true; 
    5057    private double classIndentation = 20; 
    51     private double layerSpace = 5; 
    52     private double classSpace = 2; 
     58    private float layerSpace = 5; 
     59    private float classSpace = 2; 
    5360 
    5461    private String layerFont = "Helvetica"; 
     
    5764    protected double classFontSize = 8; 
    5865    private String fontEncoding = BaseFont.WINANSI; 
    59  
     66     
     67    private double columnMargin = 3; 
     68     
     69    /** 
     70     * Render the legends block 
     71     * @see org.mapfish.print.config.layout.Block#render(org.mapfish.print.utils.PJsonObject, org.mapfish.print.config.layout.Block.PdfElement, org.mapfish.print.RenderingContext) 
     72     */ 
    6073    public void render(PJsonObject params, PdfElement target, RenderingContext context) throws DocumentException { 
    61         PdfPTable table = new PdfPTable(1); 
    62         table.setWidthPercentage(100f); 
    63  
    64         Font layerPdfFont = getLayerPdfFont(); 
    65         Font classPdfFont = getClassPdfFont(); 
    66  
    67         PJsonArray legends = context.getGlobalParams().optJSONArray("legends"); 
    68         if (legends != null && legends.size() > 0) { 
    69             for (int i = 0; i < legends.size(); ++i) { 
    70                 PJsonObject layer = legends.getJSONObject(i); 
    71                 final PdfPCell cell = createLine(context, 0.0, layer, layerPdfFont, params); 
    72                 if (i > 0) { 
    73                     cell.setPaddingTop((float) layerSpace); 
    74                 } 
    75                 table.addCell(cell); 
    76  
    77                 PJsonArray classes = layer.getJSONArray("classes"); 
    78                 for (int j = 0; j < classes.size(); ++j) { 
    79                     PJsonObject clazz = classes.getJSONObject(j); 
    80                     final PdfPCell classCell = createLine(context, classIndentation, clazz, classPdfFont, params); 
    81                     classCell.setPaddingTop((float) classSpace); 
    82                     table.addCell(classCell); 
    83                 } 
    84             } 
     74        Renderer renderer = new Renderer(params, context); 
     75        renderer.render(target); 
     76    } 
     77     
     78    /** 
     79     * A renderer to render the legend block 
     80     * @author Stéphane Brunner 
     81     */ 
     82    private class Renderer { 
     83        private PJsonObject params; 
     84        private RenderingContext context; 
     85         
     86        // all the pdf columns 
     87        private ArrayList<PdfPTable> columns = new ArrayList<PdfPTable>(); 
     88        // all the columns width 
     89        private ArrayList<Float> columnsWidth = new ArrayList<Float>(); 
     90        // the current cell width 
     91        private float cellWidth = 0; 
     92        // the current column 
     93        private PdfPTable column = new PdfPTable(1); 
     94        // the curent title 
     95        private PdfPCell title; 
     96        // the current cell height 
     97        private double currentCellHeight = 0; 
     98        // the current column height  
     99        private double currentColumnHeight = 0; 
     100 
     101        /** 
     102         * Construct 
     103         * @param params the params 
     104         * @param context the context 
     105         */ 
     106        public Renderer(PJsonObject params, RenderingContext context) { 
     107            column.setWidthPercentage(100f); 
     108            columns.add(column); 
     109            currentCellHeight = 0; 
     110            columnsWidth.add(0f); 
     111            this.params = params; 
     112            this.context = context; 
    85113        } 
    86         table.setSpacingAfter((float) spacingAfter); 
    87         target.add(table); 
    88     } 
    89  
    90     private PdfPCell createLine(RenderingContext context, double indent, PJsonObject node, Font pdfFont, PJsonObject params) throws DocumentException { 
    91         final String name = node.getString("name"); 
    92         final String icon = node.optString("icon"); 
    93         final PJsonArray icons = node.optJSONArray("icons"); 
    94  
    95         final Paragraph result = new Paragraph(); 
    96         result.setFont(pdfFont); 
    97         if (icon != null) { 
    98                 try { 
    99                         if (icon.indexOf("image%2Fsvg%2Bxml") != -1) { // TaODO: make this cleaner 
    100                                 result.add(PDFUtils.createImageChunkFromSVG(context, icon, maxIconWidth, maxIconHeight)); 
    101                         } else { 
    102                                 result.add(PDFUtils.createImageChunk(context, maxIconWidth, maxIconHeight, URI.create(icon), 0.0f)); 
    103                         } 
    104                     result.add(" "); 
    105                 } catch (IOException ioe) { 
     114         
     115        /** 
     116         * Render 
     117         * @param target the target element 
     118         * @throws DocumentException 
     119         */ 
     120        public void render(PdfElement target) throws DocumentException { 
     121 
     122            Font layerPdfFont = getLayerPdfFont(); 
     123            Font classPdfFont = getClassPdfFont(); 
     124 
     125            // create the legend 
     126            PJsonArray legends = context.getGlobalParams().optJSONArray("legends"); 
     127            if (legends != null && legends.size() > 0) { 
     128                for (int i = 0; i < legends.size(); ++i) { 
     129                    PJsonObject layer = legends.getJSONObject(i); 
     130                    createLine(0.0, layer, layerPdfFont, i == 0 ? 0 : layerSpace, true); 
     131     
     132                    PJsonArray classes = layer.getJSONArray("classes"); 
     133                    for (int j = 0; j < classes.size(); ++j) { 
     134                        PJsonObject clazz = classes.getJSONObject(j); 
     135                        createLine(classIndentation, clazz, classPdfFont, classSpace, false); 
     136                    } 
     137                } 
     138            } 
     139             
     140            // complete the width of the last column 
     141            {  
     142                int index = columnsWidth.size() - 1; 
     143                columnsWidth.set(index, Math.max(columnsWidth.get(index), cellWidth)); 
     144            } 
     145            if (title != null) { 
     146                column.addCell(title); 
     147            } 
     148             
     149            // calculate the fullWidth (sum of width of visible column with margin) 
     150            int len = columns.size(); 
     151            float fullWidth = 0; 
     152            for (int i = 0 ; i < len ; i++) { 
     153                float width = columnsWidth.get(i); 
     154                if (fullWidth + width < maxWidth) { 
     155                    fullWidth += width + columnMargin; 
     156                } 
     157                else { 
     158                    len = i + 1; 
     159                } 
     160            } 
     161             
     162            // create the column with array for the table 
     163            float[] pdfWidths = new float[len + 1]; 
     164            for (int i = 0 ; i < len ; i++) { 
     165                pdfWidths[i] = columnsWidth.get(i); 
     166            } 
     167            // for empty column 
     168            pdfWidths[len] = Math.max(0f, (float)maxWidth - fullWidth); 
     169             
     170            // table used for column 
     171            PdfPTable table = new PdfPTable(pdfWidths); 
     172            table.setWidthPercentage(100f); 
     173            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER); 
     174            table.getDefaultCell().setPadding(0f); 
     175            table.setSpacingAfter((float) spacingAfter); 
     176     
     177            // add columns 
     178            for (int i = 0 ; i < len ; i++) { 
     179                table.addCell(columns.get(i)); 
     180            } 
     181            // create empty column 
     182            table.addCell(""); 
     183             
     184            // add to result  
     185            target.add(table); 
     186        } 
     187     
     188        /** 
     189         * Display a legend or class block (name and icon(s) ). 
     190         * In not inline mode it's a line.  
     191         * @param indent left indentation 
     192         * @param node the json node 
     193         * @param pdfFont the font used for the title 
     194         * @param lineSpace the top indent for the icons 
     195         * @param escapeOrphanTitle don't have orphan title 
     196         * @throws DocumentException 
     197         */ 
     198        private void createLine(double indent, PJsonObject node, Font pdfFont, 
     199                float lineSpace, boolean escapeOrphanTitle) throws DocumentException { 
     200            final String name = node.getString("name"); 
     201            final String icon = node.optString("icon"); 
     202            final PJsonArray icons = node.optJSONArray("icons"); 
     203     
     204            Paragraph result = new Paragraph(); 
     205            if (icon != null) { 
     206                result = createIcon(indent, lineSpace, icon, result, escapeOrphanTitle ? null : name, pdfFont); 
     207            } 
     208            if (icons != null) { 
     209                for (int i = 0; i < icons.size(); ++i) { 
     210                    String iconItem = icons.getString(i); 
     211                    result = createIcon(indent, i == 0 ? lineSpace : 0, 
     212                            iconItem, result, null, null); 
     213                } 
     214            } 
     215     
     216            if (title != null) { 
     217                column.addCell(title); 
     218            } 
     219            title = new PdfPCell(result); 
     220            title.setBorder(PdfPCell.NO_BORDER); 
     221            title.setPadding(0f); 
     222            title.setPaddingLeft((float)indent); 
     223            if (inline) { 
     224                title.setPaddingTop(lineSpace); 
     225            } 
     226 
     227            if (escapeOrphanTitle) { 
     228                result.setFont(pdfFont); 
     229                result.add(name); 
     230                if (name.trim().length() > 0) { 
     231                    float width = pdfFont.getBaseFont().getWidthPoint(name, pdfFont.getSize()); 
     232                    if (escapeOrphanTitle) { 
     233                        currentCellHeight += pdfFont.getSize(); 
     234                        cellWidth = Math.max(cellWidth, width); 
     235                    } 
     236                    else { 
     237                        currentColumnHeight += pdfFont.getSize(); 
     238                        int index = columnsWidth.size() - 1; 
     239                        columnsWidth.set(index, Math.max(columnsWidth.get(index), width)); 
     240                    } 
     241                } 
     242            } 
     243     
     244            if (getBackgroundColorVal(context, params) != null) { 
     245                title.setBackgroundColor(getBackgroundColorVal(context, params)); 
     246            } 
     247            if (!escapeOrphanTitle) { 
     248                column.addCell(title); 
     249                title = null; 
     250            } 
     251        } 
     252 
     253        /** 
     254         * Creates a legend icon 
     255         * @param indent left indentation 
     256         * @param lineSpace the top indent for the icons 
     257         * @param icon the icon to display 
     258         * @param result the element to add to 
     259         * @return the result for the next elements 
     260         * @throws DocumentException 
     261         */ 
     262        private Paragraph createIcon(double indent, float lineSpace, 
     263                final String icon, Paragraph result, String name, Font pdfFont) throws DocumentException { 
     264            try { 
     265                Chunk iconChunk = null; 
     266                if (icon.indexOf("image%2Fsvg%2Bxml") != -1) { // TODO: make this cleaner 
     267                    iconChunk = PDFUtils.createImageChunkFromSVG(context, icon, maxIconWidth, maxIconHeight); 
     268                } else { 
     269                    iconChunk = PDFUtils.createImageChunk(context, maxIconWidth, maxIconHeight, scale,  
     270                            URI.create(icon), 0f); 
     271                } 
     272                result.add(iconChunk); 
     273                 
     274                float textWidth = 0; 
     275                float textHeight = 0; 
     276                if (name != null && name.trim().length() > 0) { 
     277                    result.setFont(pdfFont); 
     278                    result.add(" "); 
     279                    result.add(name); 
     280                    textWidth = pdfFont.getBaseFont().getWidthPoint(" " + name, pdfFont.getSize()); 
     281                    textHeight = pdfFont.getSize(); 
     282                } 
     283 
     284                if (!inline) { 
     285                    currentCellHeight += Math.max(iconChunk.getImage().getPlainHeight(), textHeight) + lineSpace; 
     286                    cellWidth = Math.max(cellWidth, iconChunk.getImage().getPlainWidth() + textWidth); 
     287                    addCell(indent, lineSpace, result); 
     288                    result = new Paragraph(); 
     289                } 
     290                else { 
     291                    result.add(" "); 
     292                } 
     293            } catch (IOException ioe) { 
    106294                LOGGER.warn("Failed to load " + icon + " with " + ioe.getMessage()); 
    107295            } catch (InvalidValueException e) { 
    108296                LOGGER.warn("Failed to create image chunk: " + e.getMessage()); 
    109297            } 
     298            return result; 
    110299        } 
    111         if (icons != null) { 
    112             for (int i = 0; i < icons.size(); ++i) { 
    113                 String iconItem = icons.getString(i); 
    114                 try { 
    115                     if (iconItem.indexOf("image%2Fsvg%2Bxml") != -1) { // TaODO: make this cleaner 
    116                         result.add(PDFUtils.createImageChunkFromSVG(context, iconItem, maxIconWidth, maxIconHeight)); 
    117                     } else { 
    118                         result.add(PDFUtils.createImageChunk(context, maxIconWidth, maxIconHeight, URI.create(iconItem), 0.0f)); 
    119                     } 
    120                     result.add(" "); 
    121                 } catch (IOException ioe) { 
    122                     LOGGER.warn("Failed to load " + iconItem + " with " + ioe.getMessage()); 
    123                 } catch (InvalidValueException e) { 
    124                     LOGGER.warn("Failed to create image chunk: " + e.getMessage()); 
    125                 } 
    126             } 
     300 
     301        /** 
     302         * Add an icon in the column as a cell. 
     303         * @param indent left indentation 
     304         * @param lineSpace the top indent for the icons 
     305         * @param icon the icon element to add 
     306         */ 
     307        private void addCell(double indent, float lineSpace, final Paragraph icon) { 
     308            final PdfPCell cell = new PdfPCell(icon); 
     309            cell.setBorder(PdfPCell.NO_BORDER); 
     310            cell.setPadding(0f); 
     311            cell.setPaddingLeft((float) indent); 
     312     
     313            if (getBackgroundColorVal(context, params) != null) { 
     314                cell.setBackgroundColor(getBackgroundColorVal(context, params)); 
     315            } 
     316     
     317            cell.setPaddingTop(lineSpace); 
     318            currentCellHeight += lineSpace; 
     319            if (!inline && maxHeight != 0 && (currentColumnHeight + currentCellHeight > maxHeight)) { 
     320                column = new PdfPTable(1); 
     321                column.setWidthPercentage(100f); 
     322                columns.add(column); 
     323                currentColumnHeight = 0; 
     324                columnsWidth.add(cellWidth); 
     325            } 
     326            else { 
     327                int index = columnsWidth.size() - 1; 
     328                columnsWidth.set(index, Math.max(columnsWidth.get(index), cellWidth)); 
     329            } 
     330            cellWidth = 0; 
     331            currentColumnHeight += currentCellHeight; 
     332            currentCellHeight = 0; 
     333            if (title != null) { 
     334                column.addCell(title); 
     335                title = null; 
     336            } 
     337            column.addCell(cell); 
    127338        } 
    128  
    129         final PdfPCell cell = new PdfPCell(result); 
    130         cell.setBorder(PdfPCell.NO_BORDER); 
    131         cell.setPadding(0f); 
    132         cell.setPaddingLeft((float) indent); 
    133  
    134         result.add(name); 
    135  
    136         if (getBackgroundColorVal(context, params) != null) { 
    137             cell.setBackgroundColor(getBackgroundColorVal(context, params)); 
    138         } 
    139  
    140         return cell; 
    141     } 
    142  
     339    } 
     340 
     341    public void setMaxWidth(double maxWidth) { 
     342        this.maxWidth = maxWidth; 
     343        if (maxWidth < 0.0) throw new InvalidValueException("maxWidth", maxWidth); 
     344    } 
     345 
     346    public void setMaxHeight(double maxHeight) { 
     347        this.maxHeight = maxHeight; 
     348        if (maxHeight < 0.0) throw new InvalidValueException("maxHeight", maxHeight); 
     349    } 
     350 
     351    public void setDefaultScale(double scale) { 
     352        this.scale = (float)scale; 
     353        if (scale < 0.0) throw new InvalidValueException("scale", scale); 
     354    } 
     355 
     356    public void setInline(String inline) { 
     357        this.inline = "true".equalsIgnoreCase(inline); 
     358        if (!(inline.equalsIgnoreCase("true") || inline.equalsIgnoreCase("false"))) throw new InvalidValueException("inline", inline); 
     359    } 
     360     
    143361    public void setMaxIconWidth(double maxIconWidth) { 
    144362        this.maxIconWidth = maxIconWidth; 
     
    178396 
    179397    public void setLayerSpace(double layerSpace) { 
    180         this.layerSpace = layerSpace; 
     398        this.layerSpace = (float)layerSpace; 
    181399        if (layerSpace < 0.0) throw new InvalidValueException("layerSpace", layerSpace); 
    182400    } 
    183401 
    184402    public void setClassSpace(double classSpace) { 
    185         this.classSpace = classSpace; 
     403        this.classSpace = (float)classSpace; 
    186404        if (classSpace < 0.0) throw new InvalidValueException("classSpace", classSpace); 
    187405    } 
     
    199417        this.fontEncoding = fontEncoding; 
    200418    } 
     419     
     420    public void setColumnMargin(double columnMargin) { 
     421        this.columnMargin = columnMargin; 
     422    } 
    201423}