Updated Branches: refs/heads/master 024c7abbd -> f6f576e20
WICKET-4802 Add functionality to be able to export DataTable content Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/f6f576e2 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/f6f576e2 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/f6f576e2 Branch: refs/heads/master Commit: f6f576e2046f069bb1c89677384ac99d8eae7944 Parents: 024c7ab Author: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Authored: Tue Oct 16 11:44:56 2012 +0200 Committer: Martin Tzvetanov Grigorov <mgrigo...@apache.org> Committed: Tue Oct 16 11:44:56 2012 +0200 ---------------------------------------------------------------------- .../wicket/examples/repeater/DataTablePage.html | 1 + .../wicket/examples/repeater/DataTablePage.java | 19 +- .../wicket/extensions/Initializer.properties | 2 + .../html/repeater/data/table/PropertyColumn.java | 23 +- .../data/table/export/AbstractDataExporter.java | 116 +++++ .../table/export/AbstractExportableColumn.java | 86 ++++ .../data/table/export/CSVDataExporter.java | 250 +++++++++++ .../repeater/data/table/export/ExportToolbar.html | 25 + .../repeater/data/table/export/ExportToolbar.java | 346 +++++++++++++++ .../repeater/data/table/export/IDataExporter.java | 76 ++++ .../data/table/export/IExportableColumn.java | 54 +++ .../repeater/data/table/export/package-info.java | 21 + 12 files changed, 1009 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.html b/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.html index e61e412..8eb4b70 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.html @@ -21,6 +21,7 @@ This is a demo of the DataTable (DataView wrapper). Provided features:<br/> <li>Takes care of adding class="odd" and class="even" to table rows</li> <li>Adds a navigator message</li> <li>Different CSS class for certain columns</li> +<li>Export to CSV toolbar</li> </ul> <br/> http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.java index c353fc5..cf42767 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/repeater/DataTablePage.java @@ -21,9 +21,12 @@ import java.util.List; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.export.CSVDataExporter; +import org.apache.wicket.extensions.markup.html.repeater.data.table.export.ExportToolbar; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -55,7 +58,7 @@ public class DataTablePage extends BasePage } }); - columns.add(new PropertyColumn(new Model<String>("ID"), "id") + columns.add(new PropertyColumn<Contact, String>(new Model<String>("ID"), "id") { @Override public String getCssClass() @@ -64,9 +67,9 @@ public class DataTablePage extends BasePage } }); - columns.add(new PropertyColumn(new Model<String>("First Name"), "firstName", "firstName")); + columns.add(new PropertyColumn<Contact, String>(new Model<String>("First Name"), "firstName", "firstName")); - columns.add(new PropertyColumn(new Model<String>("Last Name"), "lastName", "lastName") + columns.add(new PropertyColumn<Contact, String>(new Model<String>("Last Name"), "lastName", "lastName") { @Override public String getCssClass() @@ -75,9 +78,13 @@ public class DataTablePage extends BasePage } }); - columns.add(new PropertyColumn(new Model<String>("Home Phone"), "homePhone")); - columns.add(new PropertyColumn(new Model<String>("Cell Phone"), "cellPhone")); + columns.add(new PropertyColumn<Contact, String>(new Model<String>("Home Phone"), "homePhone")); + columns.add(new PropertyColumn<Contact, String>(new Model<String>("Cell Phone"), "cellPhone")); - add(new DefaultDataTable("table", columns, new SortableContactDataProvider(), 8)); + DataTable dataTable = new DefaultDataTable<Contact, String>("table", columns, + new SortableContactDataProvider(), 8); + dataTable.addBottomToolbar(new ExportToolbar(dataTable).addDataExporter(new CSVDataExporter())); + + add(dataTable); } } http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/Initializer.properties ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/Initializer.properties b/wicket-extensions/src/main/java/org/apache/wicket/extensions/Initializer.properties index 9a16445..ddf852e 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/Initializer.properties +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/Initializer.properties @@ -14,6 +14,8 @@ # limitations under the License. NavigatorLabel=Showing ${from} to ${to} of ${of} datatable.no-records-found=No Records Found +datatable.export-to=Export to +datatable.export-file-name=export UploadProgressBar.starting=Upload starting... UploadStatusResource.status=${percentageComplete}% finished, ${bytesUploadedString} of ${totalBytesString} at ${transferRateString}; ${remainingTimeString} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/PropertyColumn.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/PropertyColumn.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/PropertyColumn.java index 6a6f3a4..48c077f 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/PropertyColumn.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/PropertyColumn.java @@ -17,6 +17,7 @@ package org.apache.wicket.extensions.markup.html.repeater.data.table; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.export.IExportableColumn; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; @@ -45,7 +46,7 @@ import org.apache.wicket.model.PropertyModel; * @param <S> * the type of the sort property */ -public class PropertyColumn<T, S> extends AbstractColumn<T, S> +public class PropertyColumn<T, S> extends AbstractColumn<T, S> implements IExportableColumn<T, S, Object> { private static final long serialVersionUID = 1L; @@ -102,12 +103,13 @@ public class PropertyColumn<T, S> extends AbstractColumn<T, S> * * @param rowModel * @return model + * @deprecated + * since 6.2.0, scheduled for removal in 7.0.0. Please use {@link #getDataModel(org.apache.wicket.model.IModel)} + * instead. */ protected IModel<?> createLabelModel(final IModel<T> rowModel) { - @SuppressWarnings("rawtypes") - PropertyModel<?> propertyModel = new PropertyModel(rowModel, propertyExpression); - return propertyModel; + return getDataModel(rowModel); } /** @@ -118,4 +120,17 @@ public class PropertyColumn<T, S> extends AbstractColumn<T, S> return propertyExpression; } + /** + * Factory method for generating a model that will generated the displayed value. Typically the + * model is a property model using the {@link #propertyExpression} specified in the constructor. + * + * @param rowModel + * @return model + */ + @Override + public IModel<Object> getDataModel(IModel<T> rowModel) + { + PropertyModel<Object> propertyModel = new PropertyModel<Object>(rowModel, propertyExpression); + return propertyModel; + } } http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractDataExporter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractDataExporter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractDataExporter.java new file mode 100644 index 0000000..b48b0d8 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractDataExporter.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import org.apache.wicket.model.IModel; + +/** + * An abstract helper implementation of {@link IDataExporter}. + * + * @author Jesse Long + */ +public abstract class AbstractDataExporter implements IDataExporter +{ + private IModel<String> dataFormatNameModel; + + private String contentType; + + private String fileNameExtension; + + /** + * Creates a new instance with the data format name model, content type and file name extensions provided. + * + * @param dataFormatNameModel + * The model of the exported data format name. + * @param contentType + * The MIME content type of the exported data type. + * @param fileNameExtension + * The file name extensions to use in the file name for the exported data. + */ + public AbstractDataExporter(IModel<String> dataFormatNameModel, String contentType, String fileNameExtension) + { + this.dataFormatNameModel = dataFormatNameModel; + this.contentType = contentType; + this.fileNameExtension = fileNameExtension; + } + + /** + * {@inheritDoc } + */ + @Override + public IModel<String> getDataFormatNameModel() + { + return dataFormatNameModel; + } + + /** + * {@inheritDoc } + */ + @Override + public String getContentType() + { + return contentType; + } + + /** + * {@inheritDoc } + */ + @Override + public String getFileNameExtension() + { + return fileNameExtension; + } + + /** + * Sets the MIME contentType for the data export format. + * + * @param contentType + * The MIME contentType for the data export format. + * @return {@code this}, for chaining. + */ + public AbstractDataExporter setContentType(String contentType) + { + this.contentType = contentType; + return this; + } + + /** + * Sets the data format name model. + * + * @param dataFormatNameModel + * the data format name model. + * @return {@code this}, for chaining. + */ + public AbstractDataExporter setDataFormatNameModel(IModel<String> dataFormatNameModel) + { + this.dataFormatNameModel = dataFormatNameModel; + return this; + } + + /** + * Sets the file name extension to be used in the exported file name. + * + * @param fileNameExtension + * the file name extension to be used in the exported file name. + * @return {@code this}, for chaining. + */ + public AbstractDataExporter setFileNameExtension(String fileNameExtension) + { + this.fileNameExtension = fileNameExtension; + return this; + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractExportableColumn.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractExportableColumn.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractExportableColumn.java new file mode 100644 index 0000000..464138f --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/AbstractExportableColumn.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import org.apache.wicket.Component; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.model.IModel; + +/** + * A helper implementation of {@link IExportableColumn}. This implementation requires you to only + * implement {@link #getDataModel(org.apache.wicket.model.IModel)}. + * @author Jesse Long + * @param <T> The type of each row in the table. + * @param <S> The type of the sort property of the table. + * @param <D> The type of the data displayed in this column. + */ +public abstract class AbstractExportableColumn<T, S, D> + extends AbstractColumn<T, S> + implements IExportableColumn<T, S, D> +{ + /** + * Creates a new {@link AbstractExportableColumn} with the provided display model, and without a sort property. + * @param displayModel The {@link IModel} of the text to be used in the column header. + */ + public AbstractExportableColumn(IModel<String> displayModel) + { + super(displayModel); + } + + /** + * Creates a new {@link AbstractExportableColumn} with the provided display model, and sort property. + * @param displayModel The {@link IModel} of the text to be used in the column header. + * @param sortProperty The sort property used by this column. + */ + public AbstractExportableColumn(IModel<String> displayModel, S sortProperty) + { + super(displayModel, sortProperty); + } + + /** + * Creates a {@link Component} which will be used to display the content of the column in this row. + * The default implementation simply creates a label with the data model provided. + * @param componentId + * The component id of the display component. + * @param dataModel + * The model of the data for this column in the row. This should usually be passed as the model + * of the display component. + * @return a {@link Component} which will be used to display the content of the column in this row. + */ + protected Component createDisplayComponent(String componentId, IModel<D> dataModel) + { + return new Label(componentId, dataModel); + } + + /** + * Populated the data for this column in the row into the {@code cellItem}. + * <p> + * This implementation adds the {@link Component} returned by {@link #createDisplayComponent(java.lang.String, org.apache.wicket.model.IModel) } + * to the cell. + * @param cellItem The cell to be populated. + * @param componentId The component id to be used for the component that will be added to the cell. + * @param rowModel A model of the row data. + */ + @Override + public void populateItem(Item<ICellPopulator<T>> cellItem, String componentId, IModel<T> rowModel) + { + cellItem.add(createDisplayComponent(componentId, getDataModel(rowModel))); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/CSVDataExporter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/CSVDataExporter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/CSVDataExporter.java new file mode 100644 index 0000000..8368906 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/CSVDataExporter.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.Iterator; +import java.util.List; +import org.apache.wicket.Application; +import org.apache.wicket.Session; +import org.apache.wicket.markup.repeater.data.IDataProvider; +import org.apache.wicket.model.Model; +import org.apache.wicket.util.convert.IConverter; +import org.apache.wicket.util.lang.Args; + +/** + * An {@link IDataExporter} that exports data to a CSV file. This class allows for customization of the exact CSV format, including + * setting the delimiter, the text quoting character and the character set. + * <p> + * This class will export CSV files in a format consistent with RFC4180 by default. + * + * @author Jesse Long + */ +public class CSVDataExporter extends AbstractDataExporter +{ + private char delimiter = ','; + + private String characterSet = "utf-8"; + + private char quoteCharacter = '"'; + + private boolean exportHeadersEnabled = true; + + /** + * Creates a new instance. + */ + public CSVDataExporter() + { + super(Model.of("CSV"), "text/csv", "csv"); + } + + /** + * Sets the delimiter to be used to separate fields. The default delimiter is a colon. + * + * @param delimiter + * The delimiter to be used to separate fields. + * @return {@code this}, for chaining. + */ + public CSVDataExporter setDelimiter(char delimiter) + { + this.delimiter = delimiter; + return this; + } + + /** + * Returns the delimiter to be used for separating fields. + * + * @return the delimiter to be used for separating fields. + */ + public char getDelimiter() + { + return delimiter; + } + + /** + * Returns the character set encoding to be used when exporting data. + * + * @return the character set encoding to be used when exporting data. + */ + public String getCharacterSet() + { + return characterSet; + } + + /** + * Sets the character set encoding to be used when exporting data. This defaults to UTF-8. + * + * @param characterSet + * The character set encoding to be used when exporting data. + * @return {@code this}, for chaining. + */ + public CSVDataExporter setCharacterSet(String characterSet) + { + this.characterSet = Args.notNull(characterSet, "characterSer"); + return this; + } + + /** + * Returns the character to be used for quoting fields. + * + * @return the character to be used for quoting fields. + */ + public char getQuoteCharacter() + { + return quoteCharacter; + } + + /** + * Sets the character to be used to quote fields. This defaults to double quotes, + * + * @param quoteCharacter + * The character to be used to quote fields. + * @return {@code this}, for chaining. + */ + public CSVDataExporter setQuoteCharacter(char quoteCharacter) + { + this.quoteCharacter = quoteCharacter; + return this; + } + + /** + * Returns the content type of the exported data. For CSV, this is normally + * "text/csv". This methods adds the character set and header values, in accordance with + * RFC4180. + * + * @return the content type of the exported data. + */ + @Override + public String getContentType() + { + return super.getContentType() + "; charset=" + characterSet + "; header=" + ((exportHeadersEnabled) ? "present" : "absent"); + } + + /** + * Turns on or off export headers functionality. If this is set to {@code true}, then the first + * line of the export will contain the column headers. This defaults to {@code true}. + * + * @param exportHeadersEnabled + * A boolean indicating whether or not headers should be exported. + * @return {@code this}, for chaining. + */ + public CSVDataExporter setExportHeadersEnabled(boolean exportHeadersEnabled) + { + this.exportHeadersEnabled = exportHeadersEnabled; + return this; + } + + /** + * Indicates if header exporting is enabled. Defaults to {@code true}. + * + * @return a boolean indicating if header exporting is enabled. + */ + public boolean isExportHeadersEnabled() + { + return exportHeadersEnabled; + } + + /** + * Quotes a value for export to CSV. According to RFC4180, this should just duplicate all occurrences + * of the quote character and wrap the result in the quote character. + * + * @param value + * The value to be quoted. + * @return a quoted copy of the value. + */ + protected String quoteValue(String value) + { + return quoteCharacter + value.replace("" + quoteCharacter, "" + quoteCharacter + quoteCharacter) + quoteCharacter; + } + + @Override + public <T> void exportData(IDataProvider<T> dataProvider, List<IExportableColumn<T, ?, ?>> columns, OutputStream outputStream) + throws IOException + { + PrintWriter out = new PrintWriter(new OutputStreamWriter(outputStream, Charset.forName(characterSet))); + try + { + if (isExportHeadersEnabled()) + { + boolean first = true; + for (IExportableColumn<T, ?, ?> col : columns) + { + if (first) + { + first = false; + } + else + { + out.print(delimiter); + } + out.print(quoteValue(col.getDisplayModel().getObject())); + } + out.print("\r\n"); + } + long numberOfRows = dataProvider.size(); + Iterator<? extends T> rowIterator = dataProvider.iterator(0, numberOfRows); + while (rowIterator.hasNext()) + { + T row = rowIterator.next(); + + boolean first = true; + for (IExportableColumn<T, ?, ?> col : columns) + { + if (first) + { + first = false; + } + else + { + out.print(delimiter); + } + + Object o = col.getDataModel(dataProvider.model(row)).getObject(); + + if (o != null) + { + Class<?> c = o.getClass(); + + String s; + + IConverter converter = Application.get().getConverterLocator().getConverter(c); + + if (converter == null) + { + s = o.toString(); + } + else + { + s = converter.convertToString(o, Session.get().getLocale()); + } + + out.print(quoteValue(s)); + } + } + out.print("\r\n"); + } + } + finally + { + out.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.html ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.html b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.html new file mode 100644 index 0000000..da98339 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.html @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<wicket:panel xmlns:wicket="http://wicket.apache.org"> + <tr class="export-tr"> + <td wicket:id="td" class="export-td"> + <span wicket:id="exportTo">[export to message]</span> + <span wicket:id="linkContainer"><a href="#" wicket:id="exportLink">[data format name]</a></span> + </td> + </tr> +</wicket:panel> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.java new file mode 100644 index 0000000..d239ebd --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/ExportToolbar.java @@ -0,0 +1,346 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.LinkedList; +import java.util.List; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.Component; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractToolbar; +import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.link.ResourceLink; +import org.apache.wicket.markup.repeater.RepeatingView; +import org.apache.wicket.markup.repeater.data.IDataProvider; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.request.resource.IResource; +import org.apache.wicket.request.resource.ResourceStreamResource; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.resource.AbstractResourceStreamWriter; +import org.apache.wicket.util.resource.IResourceStream; +import org.apache.wicket.util.resource.IResourceStreamWriter; + +/** + * A toolbar that provides links to download the data represented by all {@link IExportableColumn}s in the table + * exported to formats supported by the {@link IDataExporter}s configured. + * + * @author Jesse Long + * @see IDataExporter + * @see IExportableColumn + */ +public class ExportToolbar extends AbstractToolbar +{ + private static final long serialVersionUID = 1L; + + private static final IModel<String> DEFAULT_MESSAGE_MODEL = new ResourceModel( + "datatable.export-to"); + + private static final IModel<String> DEFAULT_FILE_NAME_MODEL = new ResourceModel( + "datatable.export-file-name"); + + private final List<IDataExporter> dataExporters = new LinkedList<IDataExporter>(); + + private IModel<String> messageModel; + + private IModel<String> fileNameModel; + + /** + * Creates a new instance with the default message model. This instance will use "export." as the exported + * file name prefix. + * + * @param table + * The data table this toolbar belongs to. + */ + public ExportToolbar(final DataTable<?, ?> table) + { + this(table, DEFAULT_MESSAGE_MODEL, DEFAULT_FILE_NAME_MODEL); + } + + /** + * Creates a new instance with the provided data table and file name model. + * + * @param table + * The table to which this toolbar belongs. + * @param fileNameModel + * The model of the file name. This should exclude the file extensions. + */ + public ExportToolbar(DataTable<?, ?> table, IModel<String> fileNameModel) + { + this(table, DEFAULT_MESSAGE_MODEL, fileNameModel); + } + + /** + * Creates a new instance. + * + * @param table + * The table to which this toolbar belongs. + * @param messageModel + * The model of the export message. + * @param fileNameModel + * The model of the file name. This should exclude the file extensions. + */ + public ExportToolbar(DataTable<?, ?> table, IModel<String> messageModel, IModel<String> fileNameModel) + { + super(table); + this.messageModel = messageModel; + this.fileNameModel = fileNameModel; + } + + /** + * Sets the models of the export message displayed in the toolbar. + * + * @param messageModel + * the models of the export message displayed in the toolbar. + * @return {@code this}, for chaining. + */ + public ExportToolbar setMessageModel(IModel<String> messageModel) + { + this.messageModel = Args.notNull(messageModel, "messageModel"); + return this; + } + + /** + * Sets the model of the file name used for the exported data. + * + * @param fileNameModel + * The model of the file name used for the exported data. + * @return {@code this}, for chaining. + */ + public ExportToolbar setFileNameModel(IModel<String> fileNameModel) + { + this.fileNameModel = Args.notNull(fileNameModel, "fileNameModel"); + return this; + } + + /** + * Returns the model of the file name used for the exported data. + * + * @return the model of the file name used for the exported data. + */ + public IModel<String> getFileNameModel() + { + return fileNameModel; + } + + /** + * Returns the model of the export message displayed in the toolbar. + * + * @return the model of the export message displayed in the toolbar. + */ + public IModel<String> getMessageModel() + { + return messageModel; + } + + /** + * {@inheritDoc } + */ + @Override + protected void onInitialize() + { + super.onInitialize(); + + WebMarkupContainer td = new WebMarkupContainer("td"); + add(td); + + td.add(AttributeModifier.replace("colspan", new AbstractReadOnlyModel<String>() + { + private static final long serialVersionUID = 1L; + + @Override + public String getObject() + { + return String.valueOf(getTable().getColumns().size()); + } + })); + + td.add(new Label("exportTo", messageModel)); + + RepeatingView linkContainers = new RepeatingView("linkContainer"); + td.add(linkContainers); + + for (IDataExporter exporter : dataExporters) + { + WebMarkupContainer span = new WebMarkupContainer(linkContainers.newChildId()); + linkContainers.add(span); + + span.add(createExportLink("exportLink", exporter)); + } + } + + /** + * Creates a new link to the exported data for the provided {@link IDataExporter}. + * + * @param componentId + * The component of the link. + * @param dataExporter + * The data exporter to use to export the data. + * @return a new link to the exported data for the provided {@link IDataExporter}. + */ + protected Component createExportLink(String componentId, final IDataExporter dataExporter) + { + IResource resource = new ResourceStreamResource() + { + @Override + protected IResourceStream getResourceStream() + { + return new DataExportResourceStreamWriter(dataExporter, getTable()); + } + }.setFileName(fileNameModel.getObject() + "." + dataExporter.getFileNameExtension()); + + return new ResourceLink<Void>(componentId, resource) + .setBody(dataExporter.getDataFormatNameModel()); + } + + /** + * This toolbar is only visible if there are rows in the data set and if there are exportable columns in the + * data table and if there are data exporters added to the toolbar. + */ + @Override + public boolean isVisible() + { + if (dataExporters.isEmpty()) + { + return false; + } + + if (getTable().getRowCount() == 0) + { + return false; + } + + for (IColumn<?, ?> col : getTable().getColumns()) + { + if (col instanceof IExportableColumn) + { + return true; + } + } + + return false; + } + + @Override + protected void onDetach() + { + fileNameModel.detach(); + messageModel.detach(); + super.onDetach(); + } + + /** + * Adds a {@link IDataExporter} to the list of data exporters to be used in this toolbar. + * + * @param exporter + * The {@link IDataExporter} to add to the toolbar. + * @return {@code this}, for chaining. + */ + public ExportToolbar addDataExporter(IDataExporter exporter) + { + Args.notNull(exporter, "exporter"); + dataExporters.add(exporter); + return this; + } + + /** + * An {@link IResourceStreamWriter} which writes the exportable data from a table to an output stream. + */ + public static class DataExportResourceStreamWriter extends AbstractResourceStreamWriter + { + private final IDataExporter dataExporter; + + private final DataTable<?, ?> dataTable; + + /** + * Creates a new instance using the provided {@link IDataExporter} to export data. + * + * @param dataExporter + * The {@link IDataExporter} to use to export data. + */ + public DataExportResourceStreamWriter(IDataExporter dataExporter, DataTable<?, ?> dataTable) + { + this.dataExporter = dataExporter; + this.dataTable = dataTable; + } + + /** + * Writes the exported data to the output stream. This implementation calls + * {@link #exportData(org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable, org.apache.wicket.extensions.markup.html.repeater.data.table.export.IDataExporter, java.io.OutputStream) }. + * + * @param output + * The output stream to which to export the data. + * @throws IOException if an error occurs. + */ + @Override + public void write(OutputStream output) + throws IOException + { + exportData(dataTable, dataExporter, output); + } + + /** + * {@inheritDoc} + * <p> + * This method returns the content type returned by {@link IDataExporter#getContentType()}. + * + * @return the content type returned by {@link IDataExporter#getContentType()}. + */ + @Override + public String getContentType() + { + return dataExporter.getContentType(); + } + + /** + * Exports the data from the provided data table to the provided output stream. + * This methods calls {@link IDataExporter#exportData(org.apache.wicket.markup.repeater.data.IDataProvider, java.util.List, java.io.OutputStream) } + * passing it the {@link IDataProvider} of the {@link DataTable}, and a list of the {@link IExportableColumn}s in the table. + * + * @param <T> + * The type of each row in the data table. + * @param <S> + * The type of the sort property of the table. + * @param dataTable + * The {@link DataTable} to export. + * @param dataExporter + * The {@link IDataExporter} to use to export the data. + * @param outputStream + * The {@link OutputStream} to which the data should be exported to. + * @throws IOException + */ + private <T, S> void exportData(DataTable<T, S> dataTable, IDataExporter dataExporter, OutputStream outputStream) + throws IOException + { + IDataProvider<T> dataProvider = dataTable.getDataProvider(); + List<IExportableColumn<T, ?, ?>> exportableColumns = new LinkedList<IExportableColumn<T, ?, ?>>(); + for (IColumn<T, S> col : dataTable.getColumns()) + { + if (col instanceof IExportableColumn) + { + exportableColumns.add((IExportableColumn<T, ?, ?>)col); + } + } + dataExporter.exportData(dataProvider, exportableColumns, outputStream); + } + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IDataExporter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IDataExporter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IDataExporter.java new file mode 100644 index 0000000..a55fbbd --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IDataExporter.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import org.apache.wicket.markup.repeater.data.IDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.util.io.IClusterable; + +/** + * Exports data provided by a {@link IDataProvider} as described by {@link IExportableColumn}s. This interface is used by + * {@link ExportToolbar} to provide the export functionality. + * + * @author Jesse Long + * @see ExportToolbar + * @see IExportableColumn + */ +public interface IDataExporter + extends IClusterable +{ + /** + * Returns a model of the exported data format name. This should be something like "CSV" or "Excel" etc. The + * value of the model returned is displayed as the export type in the {@link ExportToolbar}. + * + * @return a model of the exported data format name. + */ + IModel<String> getDataFormatNameModel(); + + /** + * Returns the MIME content type of the export data type. This could be something like "text/csv". This is used to provide + * the correct content type when downloading the exported data. + * + * @return the MIME content type of the export data type. + */ + String getContentType(); + + /** + * Returns the file name extensions for the exported data, without the ".". For CSV, this should be "csv". For Excel + * exports, this should be "xls". + * + * @return the file name extensions for the exported data, without the ".". + */ + String getFileNameExtension(); + + /** + * Exports the data provided by the {@link IDataProvider} to the {@link OutputStream}. + * + * @param <T> + * The type of each row of data provided by the {@link IDataProvider}. + * @param dataProvider + * The {@link IDataProvider} from which to retrieve the data. + * @param columns + * The {@link IExportableColumn} to use to describe the data. + * @param outputStream + * The {@link OutputStream} to which to write the exported data. + * @throws IOException If an error occurs. + */ + <T> void exportData(IDataProvider<T> dataProvider, List<IExportableColumn<T, ?, ?>> columns, OutputStream outputStream) + throws IOException; +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IExportableColumn.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IExportableColumn.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IExportableColumn.java new file mode 100644 index 0000000..d09f79e --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/IExportableColumn.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export; + +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.model.IModel; + +/** + * An {@link IColumn} that can be exported. {@link IExportableColumn}s provide methods for retrieving the data + * displayed by this column in a row. This data is used by {@link IDataExporter}s to export data. + * + * @author Jesse Long + * @param <T> + * The type of each row in the table. + * @param <S> + * The type of the sort property of the table. + * @param <D> + * The type of the data displayed by this column. + * @see IDataExporter + * @see ExportToolbar + */ +public interface IExportableColumn<T, S, D> extends IColumn<T, S> +{ + /** + * Returns an {@link IModel} of the data displayed by this column for the {@code rowModel} provided. + * + * @param rowModel + * An {@link IModel} of the row data. + * @return an {@link IModel} of the data displayed by this column for the {@code rowModel} provided. + */ + IModel<D> getDataModel(IModel<T> rowModel); + + /** + * Returns a model of the column header. The content of this model is used as a heading for the column + * when it is exported. + * + * @return a model of the column header. + */ + IModel<String> getDisplayModel(); +} http://git-wip-us.apache.org/repos/asf/wicket/blob/f6f576e2/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/package-info.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/package-info.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/package-info.java new file mode 100644 index 0000000..29bffb6 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/repeater/data/table/export/package-info.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Package for exporting data tables. + */ +package org.apache.wicket.extensions.markup.html.repeater.data.table.export;