001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.extensions.markup.html.repeater.data.table;
018
019import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
020import org.apache.wicket.extensions.markup.html.repeater.data.table.export.IExportableColumn;
021import org.apache.wicket.markup.html.basic.Label;
022import org.apache.wicket.markup.repeater.Item;
023import org.apache.wicket.model.IModel;
024import org.apache.wicket.util.lang.Args;
025import org.danekja.java.util.function.serializable.SerializableFunction;
026
027/**
028 * An implementation of column that adds a label to the cell whose model is determined by the
029 * provided {@code SerializableFunction} that is evaluated against the current row's model object
030 * <p>
031 * Example for a table of {@code Contact}s:
032 * 
033 * <pre>
034 * columns[0] = new LambdaColumn(new Model&lt;String&gt;(&quot;First Name&quot;), Contact::getFirstName);
035 * </pre>
036 * 
037 * The above will attach a label to the cell which calls {@code #getFirstName()} for each displayed
038 * contact.
039 * 
040 * @param <T>
041 *            The Model object type
042 * @param <S>
043 *            the type of the sort property
044 */
045public class LambdaColumn<T, S> extends AbstractColumn<T, S> implements IExportableColumn<T, S>
046{
047        private static final long serialVersionUID = 1L;
048        
049        private final SerializableFunction<T, ?> function;
050
051        /**
052         * Creates a column that is not sortable.
053         * 
054         * @param displayModel
055         *            display model
056         * @param function
057         *            Wicket function to be applied to each row
058         */
059        public LambdaColumn(final IModel<String> displayModel,
060                final SerializableFunction<T, ?> function)
061        {
062                this(displayModel, null, function);
063        }
064        
065        /**
066         * Creates a property column that is also sortable.
067         * 
068         * @param displayModel
069         *            display model
070         * @param sortProperty
071         *            sort property
072         * @param function
073         *            Wicket function to be applied to each row
074         */
075        public LambdaColumn(final IModel<String> displayModel, final S sortProperty,
076                final SerializableFunction<T, ?> function)
077        {
078                super(displayModel, sortProperty);
079                
080                this.function = Args.notNull(function, "function");
081        }
082        
083        @Override
084        public void populateItem(Item<ICellPopulator<T>> item, String componentId, IModel<T> rowModel)
085        {
086                item.add(new Label(componentId, getDataModel(rowModel)));
087        }
088        
089        /**
090         * Factory method for generating a model that will generated the displayed value.
091         *
092         * @param rowModel
093         * @return model
094         */
095        @Override
096        public IModel<?> getDataModel(IModel<T> rowModel)
097        {
098                IModel<Object> dataModel = new IModel<Object>()
099                {
100                        private static final long serialVersionUID = 1L;
101
102                        @Override
103                        public Object getObject()
104                        {
105                                T before = rowModel.getObject();
106                                
107                                if (before == null) {
108                                        return null;
109                                } else {
110                                        return function.apply(before);
111                                }
112                        }
113                        
114                        @Override
115                        public void detach()
116                        {
117                                rowModel.detach();
118                        }
119                };
120                return dataModel;
121        }
122}