I have a Client entity with attribute “address”. The address is composed of text in multiple lines so I use “\n” as a line feed. In the client browse GroupTable, the address is displayed nicely once i turn on multiLineCells=“true” for the GroupTable.
However, once I export the data to Excel (using the built-in Excel button), the table cell containing address do not display the address in multiple lines but in one straight line.
In order for me to see multi-line, I have to format the address cells within Excel by turning on “Wrap Text” option
Is there a way in Cuba for me to see the line breaks automatically once exported ?
So I decided on creating my own Custom Action Type so that I can easily re-use it in other screens.
So for the final solution I created the following:
(1) New Action type extExcel
(2) New class ExtExcelExporter that extends class ExcelExporter
I created both in modules/web.
New Action Type:
package com.company.lms.web.actions;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.BeanLocator;
import com.haulmont.cuba.core.global.Messages;
import com.haulmont.cuba.gui.ComponentsHelper;
import com.haulmont.cuba.gui.Dialogs;
import com.haulmont.cuba.gui.Notifications;
import com.haulmont.cuba.gui.Notifications.NotificationType;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.actions.ListAction;
import com.haulmont.cuba.gui.components.data.meta.ContainerDataUnit;
//import com.haulmont.cuba.gui.export.ExcelExporter;
import com.company.lms.web.extensions.ExtExcelExporter;
import com.haulmont.cuba.gui.export.ExportDisplay;
import com.haulmont.cuba.gui.icons.CubaIcon;
import com.haulmont.cuba.gui.icons.Icons;
import com.haulmont.cuba.gui.meta.StudioAction;
import com.haulmont.cuba.gui.meta.StudioPropertiesItem;
import com.haulmont.cuba.gui.model.CollectionContainer;
import javax.inject.Inject;
import java.util.List;
import java.util.stream.Collectors;
@StudioAction(category = "List Actions", description = "Exports a list of entities to XLS file")
@ActionType(ExtExcelAction.ID)
public class ExtExcelAction extends ListAction {
public static final String ID = "extExcel";
protected Messages messages;
protected BeanLocator beanLocator;
protected String fileName = null;
/**
* If true and table is aggregatable will export aggregation row to excel document.
*/
protected boolean exportAggregation = true;
public ExtExcelAction() {
super(ID);
}
public ExtExcelAction(String id) {
super(id);
}
@Inject
protected void setIcons(Icons icons) {
this.icon = icons.get(CubaIcon.EXCEL_ACTION);
}
@Inject
protected void setMessages(Messages messages) {
this.messages = messages;
this.caption = messages.getMainMessage("actions.Excel");
}
@Inject
protected void setBeanLocator(BeanLocator beanLocator) {
this.beanLocator = beanLocator;
}
@Override
public void actionPerform(Component component) {
if (!hasSubscriptions(ActionPerformedEvent.class)) {
execute();
} else {
super.actionPerform(component);
}
}
/**
* Executes the action.
*/
public void execute() {
if (target == null) {
throw new IllegalStateException("ExcelAction target is not set");
}
if (needExportAll()) {
export(ExtExcelExporter.ExportMode.ALL_ROWS);
} else {
AbstractAction exportSelectedAction = new AbstractAction("actions.export.SELECTED_ROWS", Status.PRIMARY) {
@Override
public void actionPerform(Component component) {
export(ExtExcelExporter.ExportMode.SELECTED_ROWS);
}
};
exportSelectedAction.setCaption(messages.getMainMessage(exportSelectedAction.getId()));
AbstractAction exportAllAction = new AbstractAction("actions.export.ALL_ROWS") {
@Override
public void actionPerform(Component component) {
export(ExtExcelExporter.ExportMode.ALL_ROWS);
}
};
exportAllAction.setCaption(messages.getMainMessage(exportAllAction.getId()));
Action[] actions = new Action[]{
exportSelectedAction,
exportAllAction,
new DialogAction(DialogAction.Type.CANCEL)
};
Dialogs dialogs = ComponentsHelper.getScreenContext(target).getDialogs();
dialogs.createOptionDialog()
.withCaption(messages.getMainMessage("actions.exportSelectedTitle"))
.withMessage(messages.getMainMessage("actions.exportSelectedCaption"))
.withType(Dialogs.MessageType.CONFIRMATION)
.withActions(actions)
.show();
}
}
protected boolean needExportAll() {
if (target.getSelected().isEmpty()
|| !(target.getItems() instanceof ContainerDataUnit)) {
return true;
}
CollectionContainer container = ((ContainerDataUnit) target.getItems()).getContainer();
return container != null && container.getItems().size() <= 1;
}
public boolean isExportAggregation() {
return exportAggregation;
}
@StudioPropertiesItem(defaultValue = "true")
public void setExportAggregation(boolean exportAggregation) {
this.exportAggregation = exportAggregation;
}
public String getFileName() {
return fileName;
}
@StudioPropertiesItem
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* Export via {@link ExtExcelExporter}.
*/
protected void export(ExtExcelExporter.ExportMode exportMode) {
ExtExcelExporter exporter = new ExtExcelExporter();
exporter.setExportAggregation(exportAggregation);
Window window = ComponentsHelper.getWindowNN(target);
ExportDisplay display = beanLocator.get(ExportDisplay.NAME);
display.setFrame(window);
if (target instanceof Table) {
@SuppressWarnings("unchecked")
Table<Entity> table = (Table<Entity>) target;
exporter.exportTable(table, table.getNotCollapsedColumns(), false, display, null, fileName, exportMode);
}
if (target instanceof DataGrid) {
@SuppressWarnings("unchecked")
DataGrid<Entity> dataGrid = (DataGrid<Entity>) target;
List<DataGrid.Column> columns = dataGrid.getVisibleColumns().stream()
.filter(col -> !col.isCollapsed())
.collect(Collectors.toList());
exporter.exportDataGrid(dataGrid, columns, display, null, fileName, exportMode);
}
if (exporter.isXlsMaxRowNumberExceeded()) {
Notifications notifications = ComponentsHelper.getScreenContext(target).getNotifications();
notifications.create(NotificationType.WARNING)
.withCaption(messages.getMainMessage("actions.warningExport.title"))
.withDescription(messages.getMainMessage("actions.warningExport.message"))
.show();
}
}
}
Extend *ExcelReporter:
/*
Created by Robert Gilbert on 19-May-2020 so that cell contents in Excel will honor CRLF (text will be wrapped)
*/
package com.company.lms.web.extensions;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.gui.export.ExcelExporter;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import javax.annotation.Nullable;
public class ExtExcelExporter extends ExcelExporter {
//@Override
protected void formatValueCell(HSSFCell cell, @Nullable Object cellValue, @Nullable MetaPropertyPath metaPropertyPath, int sizersIndex, int notificationRequired, int level, @Nullable Integer groupChildCount) {
super.formatValueCell(cell, cellValue, metaPropertyPath, sizersIndex, notificationRequired, level, groupChildCount);
if (cellValue instanceof String) {
HSSFCellStyle style = cell.getCellStyle();
style.setWrapText(true);
}
HSSFCellStyle style = cell.getCellStyle();
style.setVerticalAlignment(VerticalAlignment.TOP);
}
}