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;

Reply via email to