001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.client.ui.table.cell;
021
022import com.google.gwt.cell.client.Cell;
023import com.google.gwt.cell.client.Cell.Context;
024import com.google.gwt.cell.client.FieldUpdater;
025import com.google.gwt.cell.client.HasCell;
026import com.google.gwt.cell.client.ValueUpdater;
027import com.google.gwt.dom.client.Element;
028import com.google.gwt.dom.client.NativeEvent;
029import com.google.gwt.dom.client.Style;
030import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
031import gwt.material.design.client.base.HasHideOn;
032import gwt.material.design.client.base.HasTextAlign;
033import gwt.material.design.client.base.constants.StyleName;
034import gwt.material.design.client.constants.HideOn;
035import gwt.material.design.client.constants.TextAlign;
036import gwt.material.design.client.data.component.RowComponent;
037
038import java.util.Comparator;
039import java.util.HashMap;
040import java.util.Map;
041
042/**
043 * A representation of a column in a table.
044 * 
045 * @param <T> the row type
046 * @param <C> the column type
047 *
048 * @author Ben Dol
049 */
050public abstract class Column<T, C> implements HasCell<T, C>, HasHideOn, HasTextAlign {
051
052    /**
053     * The {@link Cell} responsible for rendering items in the column.
054     */
055    private final Cell<C> cell;
056
057    /**
058     * The {@link FieldUpdater} used for updating values in the column.
059     */
060    private FieldUpdater<T, C> fieldUpdater;
061
062    private boolean isDefaultSortAscending = true;
063    private boolean isNumeric = false;
064    private boolean autoSort = false;
065    private String name;
066    private String width;
067    private HideOn hideOn;
068    private TextAlign textAlign;
069
070    private Map<StyleName, String> styleProps;
071
072    private Comparator<? super RowComponent<T>> sortComparator;
073
074    /**
075     * Construct a new Column with a given {@link Cell}.
076     * 
077     * @param cell the Cell used by this Column
078     */
079    public Column(Cell<C> cell) {
080        this.cell = cell;
081
082        setFieldUpdater(fieldUpdater());
083        setDefaultSortAscending(defaultSortAscending());
084        setAutoSort(autoSort());
085        setNumeric(numeric());
086        setName(name());
087        setWidth(width());
088        setHideOn(hideOn());
089        setTextAlign(textAlign());
090        setStyleProperties(styleProperties());
091        setSortComparator(sortComparator());
092    }
093
094    /**
095     * Handle a browser event that took place within the column.
096     *
097     * @param context the cell context
098     * @param elem the parent Element
099     * @param object the base object to be updated
100     * @param event the native browser event
101     */
102    public void onBrowserEvent(Context context, Element elem, final T object, NativeEvent event) {
103        final int index = context.getIndex();
104        ValueUpdater<C> valueUpdater = (fieldUpdater == null) ? null : (ValueUpdater<C>) value -> {
105            fieldUpdater.update(index, object, value);
106        };
107        cell.onBrowserEvent(context, elem, getValue(object), event, valueUpdater);
108    }
109
110    /**
111     * Returns the {@link Cell} responsible for rendering items in the column.
112     * 
113     * @return a Cell
114     */
115    @Override
116    public final Cell<C> getCell() {
117        return cell;
118    }
119    
120    /**
121     * Returns the column value from within the underlying data object.
122     */
123    @Override
124    public abstract C getValue(T object);
125
126    /**
127     * Render the object into the cell.
128     * 
129     * @param object the object to render
130     * @param sb the buffer to render into
131     */
132    public void render(Context context, T object, SafeHtmlBuilder sb) {
133        cell.render(context, getValue(object), sb);
134    }
135
136    /**
137     * Sets a string that identifies this column in a data query.
138     *
139     * @param name name of the column from the data store's perspective
140     */
141    public final void setName(String name) {
142        this.name = name;
143    }
144
145    /**
146     * @return the database name of the column, or null if it's never been set
147     */
148    public final String getName() {
149        return name;
150    }
151
152    /**
153     * @return the database name of the column, or null if it's never been set
154     */
155    public String name() { return ""; }
156
157    /**
158     * Check if the default sort order of the column is ascending or descending.
159     *
160     * @return true if default sort is ascending, false if not
161     */
162    public final boolean isDefaultSortAscending() {
163        return isDefaultSortAscending;
164    }
165
166    /**
167     * Set whether or not the default sort order is ascending.
168     * 
169     * @param isAscending true to set the default order to ascending, false for
170     *                    descending
171     */
172    public final void setDefaultSortAscending(boolean isAscending) {
173        this.isDefaultSortAscending = isAscending;
174    }
175
176    /**
177     * Check if the default sort order of the column is ascending or descending.
178     *
179     * @return true if default sort is ascending, false if not
180     */
181    public boolean defaultSortAscending() { return true; }
182
183    /**
184     * Is this column auto sorting when rendered.
185     * @return true if this column is auto sorted.
186     */
187    public final boolean isAutoSort() {
188        return autoSort;
189    }
190
191    /**
192     * Make this column auto sort on rendering, if multiple columns are auto
193     * sorting it will be based on the first one set to auto sort.
194     */
195    public final void setAutoSort(boolean autoSort) {
196        this.autoSort = autoSort;
197    }
198
199    public boolean autoSort() { return false; }
200
201    /**
202     * Check if the column is sortable.
203     *
204     * @return true if sortable, false if not
205     */
206    public boolean isSortable() {
207        return getSortComparator() != null;
208    }
209
210    public final void setSortComparator(Comparator<? super RowComponent<T>> sortComparator) {
211        this.sortComparator = sortComparator;
212    }
213
214    public final Comparator<? super RowComponent<T>> getSortComparator() {
215        return sortComparator;
216    }
217
218    public Comparator<? super RowComponent<T>> sortComparator() { return null; }
219
220    @Override
221    public final FieldUpdater<T, C> getFieldUpdater() {
222        return fieldUpdater;
223    }
224
225    public final void setFieldUpdater(FieldUpdater<T, C> fieldUpdater) {
226        this.fieldUpdater = fieldUpdater;
227    }
228
229    public FieldUpdater<T, C> fieldUpdater() { return null; }
230
231    public final boolean isNumeric() {
232        return isNumeric;
233    }
234
235    public final void setNumeric(boolean numeric) {
236        isNumeric = numeric;
237    }
238
239    public boolean numeric() { return false; }
240
241    @Override
242    public final void setHideOn(HideOn hideOn) {
243        this.hideOn = hideOn;
244    }
245
246    @Override
247    public final HideOn getHideOn() {
248        return hideOn;
249    }
250
251    public HideOn hideOn() { return null; }
252
253    @Override
254    public final void setTextAlign(TextAlign align) {
255        this.textAlign = align;
256    }
257
258    @Override
259    public final TextAlign getTextAlign() {
260        return textAlign;
261    }
262
263    public TextAlign textAlign() { return null; }
264
265    /**
266     * Set a style property using its name as the key. Please ensure the style name and value
267     * are appropriately configured or it may result in unexpected behavior.
268     *
269     * @param styleName the style name as seen here {@link Style#STYLE_Z_INDEX} for example.
270     * @param value the string value required for the given style property.
271     */
272    public final void setStyleProperty(StyleName styleName, String value) {
273        if(styleProps == null) {
274            styleProps = new HashMap<>();
275        }
276        styleProps.put(styleName, value);
277    }
278
279    /**
280     * Get a styles property.
281     * @param styleName the styles name as represented in a {@link Style} class.
282     * @return null if the style property is not set.
283     */
284    public final String getStyleProperty(StyleName styleName) {
285        return styleProps!=null ? styleProps.get(styleName) : null;
286    }
287
288    /**
289     * Return the registered style properties.
290     * @return null if no styles are added.
291     */
292    public final Map<StyleName, String> getStyleProperties() {
293        return styleProps;
294    }
295
296    /**
297     * Set the style properties map.
298     */
299    public final void setStyleProperties(Map<StyleName, String> styleProps) {
300        this.styleProps = styleProps;
301    }
302
303    public Map<StyleName, String> styleProperties() { return null;}
304
305    /**
306     * Set the columns header width.
307     */
308    public final void setWidth(String width) {
309        this.width = width;
310    }
311
312    /**
313     * Get the columns header width.
314     * @return null if not defined.
315     */
316    public final String getWidth() {
317        return width;
318    }
319
320    public String width() { return null; }
321
322    @Override
323    public String toString() {
324        return "Column{" +
325            "cell=" + cell +
326            ", fieldUpdater=" + fieldUpdater +
327            ", isDefaultSortAscending=" + isDefaultSortAscending +
328            ", isNumeric=" + isNumeric +
329            ", name='" + name + '\'' +
330            ", width='" + width + '\'' +
331            ", hideOn=" + hideOn +
332            ", textAlign=" + textAlign +
333            ", styleProps=" + styleProps +
334            ", sortComparator=" + sortComparator +
335            '}';
336    }
337}