View Javadoc
1   /**
2    * Copyright 2011-2019 PrimeFaces Extensions
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.primefaces.extensions.component.exporter;
17  
18  import java.awt.Color;
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.lang.reflect.Array;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.StringTokenizer;
28  
29  import javax.el.MethodExpression;
30  import javax.faces.FacesException;
31  import javax.faces.component.UIComponent;
32  import javax.faces.component.UIPanel;
33  import javax.faces.component.html.HtmlCommandButton;
34  import javax.faces.component.html.HtmlCommandLink;
35  import javax.faces.component.html.HtmlOutputText;
36  import javax.faces.context.ExternalContext;
37  import javax.faces.context.FacesContext;
38  import javax.faces.event.ActionEvent;
39  
40  import org.apache.commons.lang3.StringUtils;
41  import org.apache.poi.ss.usermodel.Cell;
42  import org.apache.poi.ss.usermodel.CellStyle;
43  import org.apache.poi.ss.usermodel.FillPatternType;
44  import org.apache.poi.ss.usermodel.Font;
45  import org.apache.poi.ss.usermodel.HorizontalAlignment;
46  import org.apache.poi.ss.usermodel.PrintSetup;
47  import org.apache.poi.ss.usermodel.Row;
48  import org.apache.poi.ss.usermodel.Sheet;
49  import org.apache.poi.ss.usermodel.VerticalAlignment;
50  import org.apache.poi.ss.util.CellRangeAddress;
51  import org.apache.poi.ss.util.WorkbookUtil;
52  import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap;
53  import org.apache.poi.xssf.usermodel.XSSFCellStyle;
54  import org.apache.poi.xssf.usermodel.XSSFColor;
55  import org.apache.poi.xssf.usermodel.XSSFFont;
56  import org.apache.poi.xssf.usermodel.XSSFRichTextString;
57  import org.apache.poi.xssf.usermodel.XSSFWorkbook;
58  import org.primefaces.component.api.DynamicColumn;
59  import org.primefaces.component.api.UIColumn;
60  import org.primefaces.component.column.Column;
61  import org.primefaces.component.columngroup.ColumnGroup;
62  import org.primefaces.component.datalist.DataList;
63  import org.primefaces.component.datatable.DataTable;
64  import org.primefaces.component.rowexpansion.RowExpansion;
65  import org.primefaces.component.subtable.SubTable;
66  import org.primefaces.expression.SearchExpressionFacade;
67  import org.primefaces.util.Constants;
68  
69  /**
70   * <code>Exporter</code> component.
71   *
72   * @author Sudheer Jonna / last modified by $Author$
73   * @since 0.7.0
74   */
75  public class ExcelExporter extends Exporter {
76  
77      private XSSFWorkbook wb;
78  
79      private CellStyle cellStyle;
80      private CellStyle facetStyle;
81      private CellStyle titleStyle;
82      private Color facetBackground;
83      private Short facetFontSize;
84      private Color facetFontColor;
85      private String facetFontStyle;
86      private String fontName;
87      private Short cellFontSize;
88      private Color cellFontColor;
89      private String cellFontStyle;
90      private String datasetPadding;
91  
92      private CellStyle facetStyleLeftAlign;
93      private CellStyle facetStyleCenterAlign;
94      private CellStyle facetStyleRightAlign;
95      private CellStyle cellStyleLeftAlign;
96      private CellStyle cellStyleCenterAlign;
97      private CellStyle cellStyleRightAlign;
98  
99      @Override
100     public void export(final ActionEvent event, final String tableId, final FacesContext context, final String filename, final String tableTitle,
101                 final boolean pageOnly, final boolean selectionOnly,
102                 final String encodingType, final MethodExpression preProcessor, final MethodExpression postProcessor, final boolean subTable)
103                 throws IOException {
104 
105         wb = new XSSFWorkbook();
106         final String safeName = WorkbookUtil.createSafeSheetName(filename);
107         final Sheet sheet = wb.createSheet(safeName);
108 
109         cellStyle = wb.createCellStyle();
110         facetStyle = wb.createCellStyle();
111         titleStyle = wb.createCellStyle();
112 
113         facetStyleLeftAlign = wb.createCellStyle();
114         facetStyleCenterAlign = wb.createCellStyle();
115         facetStyleRightAlign = wb.createCellStyle();
116         cellStyleLeftAlign = wb.createCellStyle();
117         cellStyleCenterAlign = wb.createCellStyle();
118         cellStyleRightAlign = wb.createCellStyle();
119 
120         createCustomFonts();
121 
122         if (preProcessor != null) {
123             preProcessor.invoke(context.getELContext(), new Object[] {wb});
124         }
125 
126         int maxColumns = 0;
127         final String tokenString = StringUtils.normalizeSpace(tableId.replaceAll(",", StringUtils.SPACE));
128         final StringTokenizer st = new StringTokenizer(tokenString, StringUtils.SPACE);
129         while (st.hasMoreElements()) {
130             final String tableName = (String) st.nextElement();
131             final UIComponent component = SearchExpressionFacade.resolveComponent(context, event.getComponent(), tableName);
132             if (component == null) {
133                 throw new FacesException("Cannot find component \"" + tableName + "\" in view.");
134             }
135             if (!(component instanceof DataTable || component instanceof DataList)) {
136                 throw new FacesException(
137                             "Unsupported datasource target:\"" + component.getClass().getName() + "\", exporter must target a PrimeFaces DataTable/DataList.");
138             }
139             if (!component.isRendered()) {
140                 continue;
141             }
142 
143             DataList list;
144             DataTable table;
145 
146             if (tableTitle != null && !tableTitle.isEmpty() && !tableId.contains(",")) {
147                 final Row titleRow = sheet.createRow(sheet.getLastRowNum());
148                 final int cellIndex = titleRow.getLastCellNum() == -1 ? 0 : titleRow.getLastCellNum();
149                 final Cell cell = titleRow.createCell(cellIndex);
150                 cell.setCellValue(new XSSFRichTextString(tableTitle));
151                 final Font titleFont = wb.createFont();
152                 titleFont.setBold(true);
153                 titleStyle.setFont(titleFont);
154                 cell.setCellStyle(titleStyle);
155                 sheet.createRow(sheet.getLastRowNum() + 3);
156 
157             }
158             if (component instanceof DataList) {
159                 list = (DataList) component;
160 
161                 if (list.getHeader() != null) {
162                     tableFacet(context, sheet, list, "header");
163                 }
164                 if (pageOnly) {
165                     exportPageOnly(context, list, sheet);
166                 }
167                 else {
168                     exportAll(context, list, sheet);
169                 }
170             }
171             else {
172 
173                 table = (DataTable) component;
174                 final int columnsCount = getColumnsCount(table);
175 
176                 if (table.getHeader() != null && !subTable) {
177                     tableFacet(context, sheet, table, columnsCount, "header");
178 
179                 }
180                 if (!subTable) {
181                     tableColumnGroup(sheet, table, "header");
182                 }
183 
184                 addColumnFacets(table, sheet, ColumnType.HEADER);
185 
186                 if (pageOnly) {
187                     exportPageOnly(context, table, sheet);
188                 }
189                 else if (selectionOnly) {
190                     exportSelectionOnly(context, table, sheet);
191                 }
192                 else {
193                     exportAll(context, table, sheet, subTable);
194                 }
195 
196                 if (table.hasFooterColumn() && !subTable) {
197                     addColumnFacets(table, sheet, ColumnType.FOOTER);
198                 }
199                 if (!subTable) {
200                     tableColumnGroup(sheet, table, "footer");
201                 }
202                 table.setRowIndex(-1);
203 
204                 final int cols = table.getColumnsCount();
205 
206                 if (maxColumns < cols) {
207                     maxColumns = cols;
208                 }
209             }
210             sheet.createRow(sheet.getLastRowNum() + Integer.parseInt(datasetPadding));
211         }
212 
213         if (postProcessor != null) {
214             postProcessor.invoke(context.getELContext(), new Object[] {wb});
215         }
216 
217         if (!subTable) {
218             for (int i = 0; i < maxColumns; i++) {
219                 sheet.autoSizeColumn((short) i);
220             }
221         }
222 
223         final PrintSetup printSetup = sheet.getPrintSetup();
224         printSetup.setLandscape(true);
225         printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE);
226         sheet.setPrintGridlines(true);
227 
228         writeExcelToResponse(context.getExternalContext(), wb, filename);
229 
230     }
231 
232     protected void exportAll(final FacesContext context, final DataTable table, final Sheet sheet, final Boolean subTable) {
233 
234         final int first = table.getFirst();
235         final int rowCount = table.getRowCount();
236         final boolean lazy = table.isLazy();
237         int i = 0;
238         if (subTable) {
239             int subTableCount = table.getRowCount();
240             SubTable subtable = table.getSubTable();
241             final int subTableColumnsCount = getColumnsCount(subtable);
242 
243             if (table.getHeader() != null) {
244                 tableFacet(context, sheet, table, subTableColumnsCount, "header");
245             }
246 
247             tableColumnGroup(sheet, table, "header");
248 
249             while (subTableCount > 0) {
250 
251                 subTableCount--;
252                 table.setRowIndex(i);
253                 i++;
254                 if (subtable.getHeader() != null) {
255                     tableFacet(context, sheet, subtable, subTableColumnsCount, "header");
256                 }
257 
258                 if (hasHeaderColumn(subtable)) {
259                     addColumnFacets(subtable, sheet, ColumnType.HEADER);
260                 }
261 
262                 exportAll(context, subtable, sheet);
263 
264                 if (hasFooterColumn(subtable)) {
265 
266                     addColumnFacets(subtable, sheet, ColumnType.FOOTER);
267                 }
268 
269                 if (subtable.getFooter() != null) {
270                     tableFacet(context, sheet, subtable, subTableColumnsCount, "footer");
271                 }
272 
273                 subtable.setRowIndex(-1);
274                 subtable = table.getSubTable();
275             }
276 
277             tableColumnGroup(sheet, table, "footer");
278 
279             if (table.hasFooterColumn()) {
280                 tableFacet(context, sheet, table, subTableColumnsCount, "footer");
281             }
282         }
283         else {
284             if (lazy) {
285                 if (rowCount > 0) {
286                     table.setFirst(0);
287                     table.setRows(rowCount);
288                     table.clearLazyCache();
289                     table.loadLazyData();
290                 }
291                 for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
292                     exportRow(table, sheet, rowIndex);
293                 }
294 
295                 // restore
296                 table.setFirst(first);
297                 table.setRowIndex(-1);
298                 table.clearLazyCache();
299                 table.loadLazyData();
300             }
301             else {
302                 for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
303                     exportRow(table, sheet, rowIndex);
304                 }
305                 // restore
306                 table.setFirst(first);
307             }
308         }
309     }
310 
311     protected void exportAll(final FacesContext context, final SubTable table, final Sheet sheet) {
312         final int rowCount = table.getRowCount();
313 
314         tableColumnGroup(sheet, table, "header");
315         if (hasHeaderColumn(table)) {
316             addColumnFacets(table, sheet, ColumnType.HEADER);
317         }
318         for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
319             exportRow(table, sheet, rowIndex);
320         }
321         if (hasFooterColumn(table)) {
322             addColumnFacets(table, sheet, ColumnType.FOOTER);
323         }
324         tableColumnGroup(sheet, table, "footer");
325 
326     }
327 
328     protected void exportAll(final FacesContext context, final DataList list, final Sheet sheet) {
329         final int first = list.getFirst();
330         final int rowCount = list.getRowCount();
331         final int rows = list.getRows();
332         final boolean lazy = list.isLazy();
333 
334         if (lazy) {
335             for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
336                 if (rowIndex % rows == 0) {
337                     list.setFirst(rowIndex);
338                     list.loadLazyData();
339                 }
340 
341                 exportRow(list, sheet, rowIndex);
342             }
343 
344             // restore
345             list.setFirst(first);
346             list.loadLazyData();
347         }
348         else {
349 
350             for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
351                 exportRow(list, sheet, rowIndex);
352             }
353             // restore
354             list.setFirst(first);
355         }
356 
357     }
358 
359     protected void exportPageOnly(final FacesContext context, final DataTable table, final Sheet sheet) {
360         final int first = table.getFirst();
361         final int rowsToExport = first + table.getRows();
362 
363         for (int rowIndex = first; rowIndex < rowsToExport; rowIndex++) {
364             exportRow(table, sheet, rowIndex);
365         }
366     }
367 
368     protected void exportPageOnly(final FacesContext context, final DataList list, final Sheet sheet) {
369         final int first = list.getFirst();
370         final int rowsToExport = first + list.getRows();
371 
372         for (int rowIndex = first; rowIndex < rowsToExport; rowIndex++) {
373             exportRow(list, sheet, rowIndex);
374         }
375     }
376 
377     protected void exportSelectionOnly(final FacesContext context, final DataTable table, final Sheet sheet) {
378         final Object selection = table.getSelection();
379         final String var = table.getVar();
380 
381         if (selection != null) {
382             final Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
383 
384             if (selection.getClass().isArray()) {
385                 final int size = Array.getLength(selection);
386 
387                 for (int i = 0; i < size; i++) {
388                     requestMap.put(var, Array.get(selection, i));
389                     exportCells(table, sheet);
390                 }
391             }
392             else if (Collection.class.isAssignableFrom(selection.getClass())) {
393                 final Collection<?> collection = (Collection<?>) selection;
394                 for (final Iterator<? extends Object> it = collection.iterator(); it.hasNext();) {
395                     requestMap.put(var, it.next());
396                     exportCells(table, sheet);
397                 }
398             }
399             else {
400                 requestMap.put(var, selection);
401                 exportCells(table, sheet);
402             }
403         }
404     }
405 
406     protected void tableFacet(final FacesContext context, final Sheet sheet, final DataTable table, final int columnCount, final String facetType) {
407         final Map<String, UIComponent> map = table.getFacets();
408         final UIComponent component = map.get(facetType);
409         if (component != null) {
410             String headerValue;
411             if (component instanceof HtmlCommandButton) {
412                 headerValue = exportValue(context, component);
413             }
414             else if (component instanceof HtmlCommandLink) {
415                 headerValue = exportValue(context, component);
416             }
417             else if (component instanceof UIPanel) {
418                 final StringBuilder header = new StringBuilder(Constants.EMPTY_STRING);
419                 for (final UIComponent child : component.getChildren()) {
420                     headerValue = exportValue(context, child);
421                     header.append(headerValue);
422                 }
423                 headerValue = header.toString();
424             }
425             else {
426                 headerValue = exportFacetValue(context, component);
427             }
428 
429             final int sheetRowIndex = sheet.getLastRowNum() + 1;
430             final Row row = sheet.createRow(sheetRowIndex);
431             final Cell cell = row.createCell((short) 0);
432             cell.setCellValue(headerValue);
433             cell.setCellStyle(facetStyle);
434 
435             sheet.addMergedRegion(new CellRangeAddress(
436                         sheetRowIndex, // first row (0-based)
437                         sheetRowIndex, // last row (0-based)
438                         0, // first column (0-based)
439                         columnCount - 1 // last column (0-based)
440             ));
441 
442         }
443     }
444 
445     protected void tableFacet(final FacesContext context, final Sheet sheet, final SubTable table, final int columnCount, final String facetType) {
446         final Map<String, UIComponent> map = table.getFacets();
447         final UIComponent component = map.get(facetType);
448         if (component != null) {
449             String headerValue;
450             if (component instanceof HtmlCommandButton) {
451                 headerValue = exportValue(context, component);
452             }
453             else if (component instanceof HtmlCommandLink) {
454                 headerValue = exportValue(context, component);
455             }
456             else if (component instanceof UIPanel) {
457                 final StringBuilder header = new StringBuilder(Constants.EMPTY_STRING);
458                 for (final UIComponent child : component.getChildren()) {
459                     headerValue = exportValue(context, child);
460                     header.append(headerValue);
461                 }
462                 headerValue = header.toString();
463             }
464             else {
465                 headerValue = exportFacetValue(context, component);
466             }
467 
468             final int sheetRowIndex = sheet.getLastRowNum() + 1;
469             final Row row = sheet.createRow(sheetRowIndex);
470             final Cell cell = row.createCell((short) 0);
471             cell.setCellValue(headerValue);
472             cell.setCellStyle(facetStyle);
473 
474             sheet.addMergedRegion(new CellRangeAddress(
475                         sheetRowIndex, // first row (0-based)
476                         sheetRowIndex, // last row (0-based)
477                         0, // first column (0-based)
478                         columnCount - 1 // last column (0-based)
479             ));
480 
481         }
482     }
483 
484     protected void tableFacet(final FacesContext context, final Sheet sheet, final DataList list, final String facetType) {
485         final Map<String, UIComponent> map = list.getFacets();
486         final UIComponent component = map.get(facetType);
487         if (component != null) {
488             String headerValue;
489             if (component instanceof HtmlCommandButton) {
490                 headerValue = exportValue(context, component);
491             }
492             else if (component instanceof HtmlCommandLink) {
493                 headerValue = exportValue(context, component);
494             }
495             else {
496                 headerValue = exportFacetValue(context, component);
497             }
498 
499             final int sheetRowIndex = sheet.getLastRowNum() + 1;
500             final Row row = sheet.createRow(sheetRowIndex);
501             final Cell cell = row.createCell((short) 0);
502             cell.setCellValue(headerValue);
503             cell.setCellStyle(facetStyle);
504 
505             sheet.addMergedRegion(new CellRangeAddress(
506                         sheetRowIndex, // first row (0-based)
507                         sheetRowIndex, // last row (0-based)
508                         0, // first column (0-based)
509                         1 // last column (0-based)
510             ));
511 
512         }
513     }
514 
515     private int calculateColumnOffset(final Sheet sheet, final int row, int col) {
516         for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
517             final CellRangeAddress merged = sheet.getMergedRegion(j);
518             if (merged.isInRange(row, col)) {
519                 col = merged.getLastColumn() + 1;
520             }
521         }
522         return col;
523     }
524 
525     private void putText(final Row xlRow, final short col, final String text) {
526         final Cell cell = xlRow.createCell(col);
527         cell.setCellValue(text);
528         cell.setCellStyle(facetStyleCenterAlign);
529     }
530 
531     protected void tableColumnGroup(final Sheet sheet, final DataTable table, final String facetType) {
532         facetStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
533         facetStyleCenterAlign.setVerticalAlignment(VerticalAlignment.CENTER);
534         facetStyleCenterAlign.setWrapText(true);
535 
536         final ColumnGroup cg = table.getColumnGroup(facetType);
537         List<UIComponent> headerComponentList = null;
538         if (cg != null) {
539             headerComponentList = cg.getChildren();
540         }
541         if (headerComponentList != null) {
542             for (final UIComponent component : headerComponentList) {
543                 if (component instanceof org.primefaces.component.row.Row) {
544                     final org.primefaces.component.row.Row row = (org.primefaces.component.row.Row) component;
545                     final int rowIndex = sheet.getLastRowNum() + 1;
546                     final Row xlRow = sheet.createRow(rowIndex);
547                     int colIndex = 0;
548                     for (final UIComponent rowComponent : row.getChildren()) {
549                         final UIColumn column = (UIColumn) rowComponent;
550                         if (!column.isRendered() || !column.isExportable()) {
551                             continue;
552                         }
553 
554                         final String text = facetType.equalsIgnoreCase("header") ? column.getHeaderText() : column.getFooterText();
555                         // by default column has 1 rowspan && colspan
556                         final int rowSpan = column.getRowspan() - 1;
557                         final int colSpan = column.getColspan() - 1;
558 
559                         if (rowSpan > 0 && colSpan > 0) {
560                             colIndex = calculateColumnOffset(sheet, rowIndex, colIndex);
561                             sheet.addMergedRegion(new CellRangeAddress(
562                                         rowIndex, // first row (0-based)
563                                         rowIndex + rowSpan, // last row (0-based)
564                                         colIndex, // first column (0-based)
565                                         colIndex + colSpan // last column (0-based)
566                             ));
567                             putText(xlRow, (short) colIndex, text);
568                             colIndex = colIndex + colSpan;
569                         }
570                         else if (rowSpan > 0) {
571                             sheet.addMergedRegion(new CellRangeAddress(
572                                         rowIndex, // first row (0-based)
573                                         rowIndex + rowSpan, // last row (0-based)
574                                         colIndex, // first column (0-based)
575                                         colIndex // last column (0-based)
576                             ));
577                             putText(xlRow, (short) colIndex, text);
578                         }
579                         else if (colSpan > 0) {
580                             colIndex = calculateColumnOffset(sheet, rowIndex, colIndex);
581                             sheet.addMergedRegion(new CellRangeAddress(
582                                         rowIndex, // first row (0-based)
583                                         rowIndex, // last row (0-based)
584                                         colIndex, // first column (0-based)
585                                         colIndex + colSpan // last column (0-based)
586                             ));
587                             putText(xlRow, (short) colIndex, text);
588                             colIndex = colIndex + colSpan;
589                         }
590                         else {
591                             colIndex = calculateColumnOffset(sheet, rowIndex, colIndex);
592                             putText(xlRow, (short) colIndex, text);
593                         }
594                         colIndex++;
595                     }
596                 }
597             }
598         }
599     }
600 
601     protected void tableColumnGroup(final Sheet sheet, final SubTable table, final String facetType) {
602         final ColumnGroup cg = table.getColumnGroup(facetType);
603         List<UIComponent> headerComponentList = null;
604         if (cg != null) {
605             headerComponentList = cg.getChildren();
606         }
607         if (headerComponentList != null) {
608             for (final UIComponent component : headerComponentList) {
609                 if (component instanceof org.primefaces.component.row.Row) {
610                     final org.primefaces.component.row.Row row = (org.primefaces.component.row.Row) component;
611                     final int sheetRowIndex = sheet.getPhysicalNumberOfRows() > 0 ? sheet.getLastRowNum() + 1 : 0;
612                     final Row xlRow = sheet.createRow(sheetRowIndex);
613                     int i = 0;
614                     for (final UIComponent rowComponent : row.getChildren()) {
615                         final UIColumn column = (UIColumn) rowComponent;
616                         String value;
617                         if (facetType.equalsIgnoreCase("header")) {
618                             value = column.getHeaderText();
619                         }
620                         else {
621                             value = column.getFooterText();
622                         }
623                         final int rowSpan = column.getRowspan();
624                         final int colSpan = column.getColspan();
625 
626                         Cell cell;
627 
628                         if (rowSpan > 1 || colSpan > 1) {
629 
630                             if (rowSpan > 1) {
631                                 cell = xlRow.createCell((short) i);
632                                 Boolean rowSpanFlag = false;
633                                 for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
634                                     final CellRangeAddress merged = sheet.getMergedRegion(j);
635                                     if (merged.isInRange(sheetRowIndex, i)) {
636                                         rowSpanFlag = true;
637                                     }
638 
639                                 }
640                                 if (!rowSpanFlag) {
641                                     cell.setCellStyle(cellStyle);
642                                     cell.setCellValue(value);
643                                     sheet.addMergedRegion(new CellRangeAddress(
644                                                 sheetRowIndex, // first row (0-based)
645                                                 sheetRowIndex + rowSpan - 1, // last row (0-based)
646                                                 i, // first column (0-based)
647                                                 i // last column (0-based)
648                                     ));
649                                 }
650                             }
651                             if (colSpan > 1) {
652                                 cell = xlRow.createCell((short) i);
653                                 for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
654                                     final CellRangeAddress merged = sheet.getMergedRegion(j);
655                                     if (merged.isInRange(sheetRowIndex, i)) {
656                                         cell = xlRow.createCell((short) ++i);
657                                     }
658                                 }
659                                 cell.setCellStyle(cellStyle);
660                                 cell.setCellValue(value);
661                                 sheet.addMergedRegion(new CellRangeAddress(
662                                             sheetRowIndex, // first row (0-based)
663                                             sheetRowIndex, // last row (0-based)
664                                             i, // first column (0-based)
665                                             i + colSpan - 1 // last column (0-based)
666                                 ));
667                                 i = i + colSpan - 1;
668                             }
669                         }
670                         else {
671                             cell = xlRow.createCell((short) i);
672                             for (int j = 0; j < sheet.getNumMergedRegions(); j++) {
673                                 final CellRangeAddress merged = sheet.getMergedRegion(j);
674                                 if (merged.isInRange(sheetRowIndex, i)) {
675                                     cell = xlRow.createCell((short) ++i);
676                                 }
677                             }
678                             cell.setCellValue(value);
679                             cell.setCellStyle(facetStyle);
680 
681                         }
682                         i++;
683                     }
684                 }
685 
686             }
687         }
688 
689     }
690 
691     protected void exportRow(final DataTable table, final Sheet sheet, final int rowIndex) {
692         table.setRowIndex(rowIndex);
693         if (!table.isRowAvailable()) {
694             return;
695         }
696 
697         exportCells(table, sheet);
698     }
699 
700     protected void exportRow(final SubTable table, final Sheet sheet, final int rowIndex) {
701         table.setRowIndex(rowIndex);
702 
703         if (!table.isRowAvailable()) {
704             return;
705         }
706 
707         exportCells(table, sheet);
708     }
709 
710     protected void exportRow(final DataList list, final Sheet sheet, final int rowIndex) {
711         list.setRowIndex(rowIndex);
712 
713         if (!list.isRowAvailable()) {
714             return;
715         }
716 
717         exportCells(list, sheet);
718     }
719 
720     protected void exportCells(final DataTable table, final Sheet sheet) {
721         final int sheetRowIndex = sheet.getLastRowNum() + 1;
722         final Row row = sheet.createRow(sheetRowIndex);
723 
724         facetStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
725         facetStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
726         facetStyleCenterAlign.setVerticalAlignment(VerticalAlignment.CENTER);
727         facetStyleCenterAlign.setWrapText(true);
728         facetStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
729         cellStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
730         cellStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
731         cellStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
732 
733         for (final UIColumn col : table.getColumns()) {
734 
735             if (col instanceof DynamicColumn) {
736                 ((DynamicColumn) col).applyStatelessModel();
737             }
738 
739             if (col.isRendered() && col.isExportable()) {
740                 addColumnValue(row, col.getChildren(), "content", col);
741             }
742         }
743         final FacesContext context = null;
744         if (table.getRowIndex() == 0) {
745             for (final UIComponent component : table.getChildren()) {
746                 if (component instanceof RowExpansion) {
747                     final RowExpansion rowExpansion = (RowExpansion) component;
748                     if (rowExpansion.getChildren() != null) {
749                         if (rowExpansion.getChildren().get(0) instanceof DataTable) {
750                             final DataTable childTable = (DataTable) rowExpansion.getChildren().get(0);
751                             childTable.setRowIndex(-1);
752                         }
753                         if (rowExpansion.getChildren().get(0) instanceof DataList) {
754                             final DataList childList = (DataList) rowExpansion.getChildren().get(0);
755                             childList.setRowIndex(-1);
756                         }
757                     }
758 
759                 }
760             }
761         }
762         for (final UIComponent component : table.getChildren()) {
763             if (component instanceof RowExpansion) {
764                 final RowExpansion rowExpansion = (RowExpansion) component;
765                 if (rowExpansion.getChildren() != null) {
766                     for (int i = 0; i < rowExpansion.getChildren().size(); i++) {
767                         final UIComponent child = rowExpansion.getChildren().get(i);
768                         if (child instanceof DataList) {
769                             final DataList list = (DataList) child;
770                             if (list.getHeader() != null) {
771                                 tableFacet(context, sheet, list, "header");
772                             }
773                             exportAll(context, list, sheet);
774                         }
775                     }
776                     for (int i = 0; i < rowExpansion.getChildren().size(); i++) {
777                         if (rowExpansion.getChildren().get(i) instanceof DataTable) {
778                             final DataTable childTable = (DataTable) rowExpansion.getChildren().get(i);
779                             final int columnsCount = getColumnsCount(childTable);
780                             if (columnsCount > 0) { // In case none of the colums are exportable.
781                                 if (childTable.getHeader() != null) {
782                                     tableFacet(context, sheet, childTable, columnsCount, "header");
783 
784                                 }
785                                 tableColumnGroup(sheet, childTable, "header");
786 
787                                 addColumnFacets(childTable, sheet, ColumnType.HEADER);
788 
789                                 exportAll(context, childTable, sheet, false);
790 
791                                 if (childTable.hasFooterColumn()) {
792                                     addColumnFacets(childTable, sheet, ColumnType.FOOTER);
793                                 }
794                                 tableColumnGroup(sheet, childTable, "footer");
795                                 childTable.setRowIndex(-1);
796                             }
797                         }
798                     }
799 
800                 }
801             }
802         }
803     }
804 
805     protected void exportCells(final SubTable table, final Sheet sheet) {
806         final int sheetRowIndex = sheet.getLastRowNum() + 1;
807         final Row row = sheet.createRow(sheetRowIndex);
808 
809         facetStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
810         facetStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
811         facetStyleCenterAlign.setVerticalAlignment(VerticalAlignment.CENTER);
812         facetStyleCenterAlign.setWrapText(true);
813         facetStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
814         cellStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
815         cellStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
816         cellStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
817 
818         for (final UIColumn col : table.getColumns()) {
819 
820             if (col instanceof DynamicColumn) {
821                 ((DynamicColumn) col).applyStatelessModel();
822             }
823 
824             if (col.isRendered() && col.isExportable()) {
825                 addColumnValue(row, col.getChildren(), "content", col);
826             }
827         }
828     }
829 
830     protected void exportCells(final DataList list, final Sheet sheet) {
831         final int sheetRowIndex = sheet.getLastRowNum() + 1;
832         final Row row = sheet.createRow(sheetRowIndex);
833 
834         facetStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
835         facetStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
836         facetStyleCenterAlign.setVerticalAlignment(VerticalAlignment.CENTER);
837         facetStyleCenterAlign.setWrapText(true);
838         facetStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
839         cellStyleLeftAlign.setAlignment(HorizontalAlignment.LEFT);
840         cellStyleCenterAlign.setAlignment(HorizontalAlignment.CENTER);
841         cellStyleRightAlign.setAlignment(HorizontalAlignment.RIGHT);
842 
843         for (final UIComponent component : list.getChildren()) {
844             if (component instanceof Column) {
845                 final UIColumn column = (UIColumn) component;
846                 for (final UIComponent childComponent : column.getChildren()) {
847                     final int cellIndex = row.getLastCellNum() == -1 ? 0 : row.getLastCellNum();
848                     final Cell cell = row.createCell(cellIndex);
849                     if (component.isRendered()) {
850                         final String value = exportValue(FacesContext.getCurrentInstance(), childComponent);
851                         cell.setCellValue(new XSSFRichTextString(value));
852                         cell.setCellStyle(cellStyle);
853                     }
854                 }
855 
856             }
857             else {
858                 final int cellIndex = row.getLastCellNum() == -1 ? 0 : row.getLastCellNum();
859                 final Cell cell = row.createCell(cellIndex);
860                 if (component.isRendered()) {
861                     final String value = exportValue(FacesContext.getCurrentInstance(), component);
862                     cell.setCellValue(new XSSFRichTextString(value));
863                     cell.setCellStyle(cellStyle);
864                 }
865             }
866         }
867 
868     }
869 
870     protected void addColumnFacets(final DataTable table, final Sheet sheet, final ColumnType columnType) {
871 
872         final int sheetRowIndex = sheet.getLastRowNum() + 1;
873         Row rowHeader = null;
874 
875         for (final UIColumn col : table.getColumns()) {
876 
877             if (col instanceof DynamicColumn) {
878                 ((DynamicColumn) col).applyStatelessModel();
879             }
880 
881             if (col.isRendered() && col.isExportable() && col.getFacet(columnType.facet()) != null) {
882                 if (rowHeader == null) {
883                     rowHeader = sheet.createRow(sheetRowIndex);
884                 }
885                 addColumnValue(rowHeader, col.getFacet(columnType.facet()), "facet");
886             }
887         }
888 
889     }
890 
891     protected void addColumnFacets(final SubTable table, final Sheet sheet, final ColumnType columnType) {
892 
893         final int sheetRowIndex = sheet.getPhysicalNumberOfRows() > 0 ? sheet.getLastRowNum() + 1 : 0;
894         final Row rowHeader = sheet.createRow(sheetRowIndex);
895 
896         for (final UIColumn col : table.getColumns()) {
897 
898             if (col instanceof DynamicColumn) {
899                 ((DynamicColumn) col).applyStatelessModel();
900             }
901 
902             if (col.isRendered() && col.isExportable()) {
903                 addColumnValue(rowHeader, col.getFacet(columnType.facet()), "facet");
904             }
905         }
906     }
907 
908     protected void addColumnValue(final Row row, final UIComponent component, final String type) {
909         final int cellIndex = row.getLastCellNum() == -1 ? 0 : row.getLastCellNum();
910         final Cell cell = row.createCell(cellIndex);
911         final String value = component == null ? Constants.EMPTY_STRING : exportValue(FacesContext.getCurrentInstance(), component);
912         cell.setCellValue(new XSSFRichTextString(value));
913         if (type.equalsIgnoreCase("facet")) {
914             addFacetAlignments(component, cell);
915         }
916         else {
917             addColumnAlignments(component, cell);
918         }
919 
920     }
921 
922     protected void addColumnValue(final Row row, final List<UIComponent> components, final String columnType, final UIColumn column) {
923         final int cellIndex = row.getLastCellNum() == -1 ? 0 : row.getLastCellNum();
924         final Cell cell = row.createCell(cellIndex);
925         final FacesContext context = FacesContext.getCurrentInstance();
926 
927         if (column.getExportFunction() != null) {
928             cell.setCellValue(new XSSFRichTextString(exportColumnByFunction(context, column)));
929         }
930         else {
931             final StringBuilder builder = new StringBuilder();
932             for (final UIComponent component : components) {
933                 if (component.isRendered()) {
934                     final String value = exportValue(context, component);
935 
936                     if (value != null) {
937                         builder.append(value);
938                     }
939                 }
940             }
941 
942             cell.setCellValue(new XSSFRichTextString(builder.toString()));
943 
944             if (columnType.equalsIgnoreCase("facet")) {
945                 for (final UIComponent component : components) {
946                     addFacetAlignments(component, cell);
947                 }
948             }
949             else {
950                 for (final UIComponent component : components) {
951                     addColumnAlignments(component, cell);
952                 }
953             }
954         }
955     }
956 
957     protected void addColumnAlignments(final UIComponent component, final Cell cell) {
958         if (component instanceof HtmlOutputText) {
959             final HtmlOutputText output = (HtmlOutputText) component;
960             if (output.getStyle() != null && output.getStyle().contains("left")) {
961                 cell.setCellStyle(cellStyleLeftAlign);
962             }
963             if (output.getStyle() != null && output.getStyle().contains("right")) {
964                 cell.setCellStyle(cellStyleRightAlign);
965             }
966             if (output.getStyle() != null && output.getStyle().contains("center")) {
967                 cell.setCellStyle(cellStyleCenterAlign);
968             }
969         }
970     }
971 
972     protected void addFacetAlignments(final UIComponent component, final Cell cell) {
973         if (component instanceof HtmlOutputText) {
974             final HtmlOutputText output = (HtmlOutputText) component;
975             if (output.getStyle() != null && output.getStyle().contains("left")) {
976                 cell.setCellStyle(facetStyleLeftAlign);
977             }
978             else if (output.getStyle() != null && output.getStyle().contains("right")) {
979                 cell.setCellStyle(facetStyleRightAlign);
980             }
981             else {
982                 cell.setCellStyle(facetStyleCenterAlign);
983             }
984         }
985     }
986 
987     @Override
988     public void customFormat(final String facetBackground, final String facetFontSize, final String facetFontColor, final String facetFontStyle,
989                 final String fontName, final String cellFontSize,
990                 final String cellFontColor, final String cellFontStyle, final String datasetPadding, final String orientation) {
991         if (facetBackground != null) {
992             this.facetBackground = Color.decode(facetBackground);
993         }
994         if (facetFontColor != null) {
995             this.facetFontColor = Color.decode(facetFontColor);
996         }
997         if (fontName != null) {
998             this.fontName = fontName;
999         }
1000         if (cellFontColor != null) {
1001             this.cellFontColor = Color.decode(cellFontColor);
1002         }
1003 
1004         this.facetFontSize = Short.valueOf(facetFontSize);
1005         this.facetFontStyle = facetFontStyle;
1006         this.cellFontSize = Short.valueOf(cellFontSize);
1007         this.cellFontStyle = cellFontStyle;
1008         this.datasetPadding = datasetPadding;
1009 
1010     }
1011 
1012     protected void createCustomFonts() {
1013 
1014         final Font facetFont = wb.createFont();
1015         final Font cellFont = wb.createFont();
1016         final DefaultIndexedColorMap colorMap = new DefaultIndexedColorMap();
1017 
1018         if (cellFontColor != null) {
1019             final XSSFColor cellColor = new XSSFColor(cellFontColor, colorMap);
1020             ((XSSFFont) cellFont).setColor(cellColor);
1021         }
1022         if (cellFontSize != null) {
1023             cellFont.setFontHeightInPoints(cellFontSize);
1024         }
1025 
1026         if (cellFontStyle.equalsIgnoreCase("BOLD")) {
1027             cellFont.setBold(true);
1028         }
1029         if (cellFontStyle.equalsIgnoreCase("ITALIC")) {
1030             cellFont.setItalic(true);
1031         }
1032 
1033         if (facetFontStyle.equalsIgnoreCase("BOLD")) {
1034             facetFont.setBold(true);
1035         }
1036         if (facetFontStyle.equalsIgnoreCase("ITALIC")) {
1037             facetFont.setItalic(true);
1038         }
1039 
1040         if (fontName != null) {
1041             cellFont.setFontName(fontName);
1042             facetFont.setFontName(fontName);
1043         }
1044 
1045         if (facetBackground != null) {
1046             final XSSFColor backgroundColor = new XSSFColor(facetBackground, colorMap);
1047             ((XSSFCellStyle) facetStyle).setFillForegroundColor(backgroundColor);
1048             ((XSSFCellStyle) facetStyleLeftAlign).setFillForegroundColor(backgroundColor);
1049             ((XSSFCellStyle) facetStyleCenterAlign).setFillForegroundColor(backgroundColor);
1050             ((XSSFCellStyle) facetStyleRightAlign).setFillForegroundColor(backgroundColor);
1051             facetStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1052             facetStyleLeftAlign.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1053             facetStyleCenterAlign.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1054             facetStyleRightAlign.setFillPattern(FillPatternType.SOLID_FOREGROUND);
1055         }
1056 
1057         if (facetFontColor != null) {
1058             final XSSFColor facetColor = new XSSFColor(facetFontColor, colorMap);
1059             ((XSSFFont) facetFont).setColor(facetColor);
1060 
1061         }
1062         if (facetFontSize != null) {
1063             facetFont.setFontHeightInPoints(facetFontSize);
1064         }
1065 
1066         cellStyle.setFont(cellFont);
1067         cellStyleLeftAlign.setFont(cellFont);
1068         cellStyleCenterAlign.setFont(cellFont);
1069         cellStyleRightAlign.setFont(cellFont);
1070 
1071         facetStyle.setFont(facetFont);
1072         facetStyleLeftAlign.setFont(facetFont);
1073         facetStyleCenterAlign.setFont(facetFont);
1074         facetStyleRightAlign.setFont(facetFont);
1075         // facetStyle.setAlignment(CellStyle.ALIGN_CENTER);
1076 
1077     }
1078 
1079     protected void writeExcelToResponse(final ExternalContext externalContext, final org.apache.poi.ss.usermodel.Workbook generatedExcel, final String filename)
1080                 throws IOException {
1081 
1082         externalContext.setResponseContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
1083         externalContext.setResponseHeader("Expires", "0");
1084         externalContext.setResponseHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
1085         externalContext.setResponseHeader("Pragma", "public");
1086         externalContext.setResponseHeader("Content-disposition", "attachment;filename=" + filename + ".xlsx");
1087         externalContext.addResponseCookie(Constants.DOWNLOAD_COOKIE, "true", Collections.<String, Object> emptyMap());
1088 
1089         final OutputStream out = externalContext.getResponseOutputStream();
1090         generatedExcel.write(out);
1091         externalContext.responseFlushBuffer();
1092     }
1093 }