001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.acacia.client.widgets.serialdate;
029
030import org.opencms.gwt.client.ui.input.CmsCheckBox;
031import org.opencms.util.CmsPair;
032
033import java.util.Collection;
034import java.util.Comparator;
035import java.util.Date;
036import java.util.SortedSet;
037import java.util.TreeSet;
038
039import com.google.gwt.dom.client.Style.Display;
040import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
041import com.google.gwt.event.logical.shared.ValueChangeEvent;
042import com.google.gwt.event.logical.shared.ValueChangeHandler;
043import com.google.gwt.event.shared.HandlerRegistration;
044import com.google.gwt.i18n.client.DateTimeFormat;
045import com.google.gwt.user.client.ui.Composite;
046import com.google.gwt.user.client.ui.FlowPanel;
047import com.google.gwt.user.client.ui.Label;
048import com.google.gwt.user.client.ui.Panel;
049import com.google.gwt.user.client.ui.Widget;
050
051/** Special list for checkboxes with dates. */
052public class CmsCheckableDatePanel extends Composite implements HasValueChangeHandlers<SortedSet<Date>> {
053
054    /** The various style options for the checkable date panel. */
055    public static enum Style {
056        /** One column. */
057        ONE_COLUMN,
058        /** Two columns. */
059        TWO_COLUMNS,
060        /** Three columns. */
061        THREE_COLUMNS;
062
063        /**
064         * Get the width of elements dependent on the style.
065         * @return the element width, e.g., "50%"
066         */
067        public String getWidth() {
068
069            switch (this) {
070                case ONE_COLUMN:
071                    return "100%";
072                case TWO_COLUMNS:
073                    return "50%";
074                case THREE_COLUMNS:
075                    return "33%";
076                default:
077                    return "100%";
078            }
079        }
080    }
081
082    /** Default date format to use if no other format is specified in the message bundle. */
083    private static final String DEFAULT_DATE_FORMAT = "E, MMMM d, yyyy";
084
085    /** The map from the checkboxes in the list to the dates of the boxes. */
086    SortedSet<CmsCheckBox> m_checkBoxes;
087
088    /** The dates in the widget. */
089    SortedSet<Date> m_dates;
090    /** The date format. */
091    DateTimeFormat m_dateFormat;
092
093    /** The panel where checkboxes with the dates are places. */
094    Panel m_panel;
095
096    /** Flag, indicating if only labels should be shown. */
097    boolean m_onlyLabels;
098
099    /** The style of the panel. */
100    Style m_style;
101
102    /** The element width determined by the style. */
103    String m_width;
104
105    /**
106     * Constructor for creating a one column list with check boxes.
107     * @param dateFormat The date format to use.
108     */
109    public CmsCheckableDatePanel(String dateFormat) {
110        this(dateFormat, Style.ONE_COLUMN, false);
111    }
112
113    /**
114     * Constructor for creating a list with check boxes.
115     * @param dateFormat The date format to use.
116     * @param style the style to use for displaying the dates.
117     */
118    public CmsCheckableDatePanel(String dateFormat, Style style) {
119        this(dateFormat, style, false);
120    }
121
122    /**
123     * Constructor where all options can be set.
124     * @param dateFormat The date format to use.
125     * @param style the style to use for displaying the dates.
126     * @param onlyLabels flag, indicating if only labels should be shown.
127     */
128    public CmsCheckableDatePanel(String dateFormat, Style style, boolean onlyLabels) {
129        m_panel = new FlowPanel();
130        m_style = null == style ? Style.ONE_COLUMN : style;
131        m_width = m_style.getWidth();
132        m_onlyLabels = onlyLabels;
133        initWidget(m_panel);
134        m_checkBoxes = new TreeSet<CmsCheckBox>(new Comparator<CmsCheckBox>() {
135
136            public int compare(CmsCheckBox o1, CmsCheckBox o2) {
137
138                Date date1 = (Date)o1.getElement().getPropertyObject("date");
139                Date date2 = (Date)o2.getElement().getPropertyObject("date");
140                if ((null == date1) || (null == date2)) {
141                    return 0;
142                } else {
143                    return date1.compareTo(date2);
144                }
145            }
146        });
147        try {
148            m_dateFormat = DateTimeFormat.getFormat(dateFormat);
149        } catch (@SuppressWarnings("unused") Exception e) {
150            m_dateFormat = DateTimeFormat.getFormat(DEFAULT_DATE_FORMAT);
151        }
152        m_dates = new TreeSet<>();
153
154    }
155
156    /**
157     * Adds a date to the list (unchecked).
158     * @param date the date to add.
159     */
160    public void addDate(Date date) {
161
162        addDateWithCheckState(date, false);
163    }
164
165    /**
166     * Adds a date that is already checked.
167     * @param date the date to add.
168     */
169    public void addDateChecked(Date date) {
170
171        addDateWithCheckState(date, true);
172    }
173
174    /**
175     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
176     */
177    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<SortedSet<Date>> handler) {
178
179        return addHandler(handler, ValueChangeEvent.getType());
180    }
181
182    /**
183     * Returns all checked dates.
184     * @return all checked dates.
185     */
186    public SortedSet<Date> getCheckedDates() {
187
188        return getDates(Boolean.TRUE);
189    }
190
191    /**
192     * Returns all dates in the list.
193     * @return all dates in the list.
194     */
195    public SortedSet<Date> getDates() {
196
197        return new TreeSet<Date>(m_dates);
198    }
199
200    /**
201     * Returns all dates with the specified check state, if the check state is <code>null</code>, all dates are returned.
202     * @param checkState the check state, the returned dates should have.
203     * @return all dates with the specified check state, if the check state is <code>null</code>, all dates are returned.
204     */
205    public SortedSet<Date> getDates(Boolean checkState) {
206
207        TreeSet<Date> result = new TreeSet<Date>();
208        for (CmsCheckBox cb : m_checkBoxes) {
209            if ((checkState == null) || (cb.isChecked() == checkState.booleanValue())) {
210                Date date = (Date)cb.getElement().getPropertyObject("date");
211                result.add(date);
212            }
213        }
214        return result;
215    }
216
217    /**
218     * Returns all dates that are not checked.
219     * @return all dates that are not checked.
220     */
221    public SortedSet<Date> getUncheckedDates() {
222
223        return getDates(Boolean.FALSE);
224    }
225
226    /**
227     * Sets all dates in the list (unchecked).
228     * @param dates the dates to set.
229     */
230    public void setDates(SortedSet<Date> dates) {
231
232        setDates(dates, false);
233    }
234
235    /**
236     * Sets all dates in the list.
237     * @param dates the dates to set
238     * @param checked flag, indicating if all should be checked or unchecked.
239     */
240    public void setDates(SortedSet<Date> dates, boolean checked) {
241
242        m_checkBoxes.clear();
243        for (Date date : dates) {
244            CmsCheckBox cb = generateCheckBox(date, checked);
245            m_checkBoxes.add(cb);
246        }
247        reInitLayoutElements();
248        setDatesInternal(dates);
249    }
250
251    /**
252     * Set dates with the provided check states.
253     * @param datesWithCheckInfo the dates to set, accompanied with the check state to set.
254     */
255    public void setDatesWithCheckState(Collection<CmsPair<Date, Boolean>> datesWithCheckInfo) {
256
257        SortedSet<Date> dates = new TreeSet<>();
258        m_checkBoxes.clear();
259        for (CmsPair<Date, Boolean> p : datesWithCheckInfo) {
260            addCheckBox(p.getFirst(), p.getSecond().booleanValue());
261            dates.add(p.getFirst());
262        }
263        reInitLayoutElements();
264        setDatesInternal(dates);
265    }
266
267    /**
268     * Add a new check box.
269     * @param date the date for the check box
270     * @param checkState the initial check state.
271     */
272    private void addCheckBox(Date date, boolean checkState) {
273
274        CmsCheckBox cb = generateCheckBox(date, checkState);
275        m_checkBoxes.add(cb);
276        reInitLayoutElements();
277
278    }
279
280    /**
281     * Add a date with a certain check state.
282     * @param date the date to add.
283     * @param checkState the check state.
284     */
285    private void addDateWithCheckState(Date date, boolean checkState) {
286
287        addCheckBox(date, checkState);
288        if (!m_dates.contains(date)) {
289            m_dates.add(date);
290            fireValueChange();
291        }
292    }
293
294    /**
295     * Fire a value change event.
296     */
297    private void fireValueChange() {
298
299        ValueChangeEvent.fire(this, m_dates);
300    }
301
302    /**
303     * Generate a new check box with the provided date and check state.
304     * @param date date for the check box.
305     * @param checkState the initial check state.
306     * @return the created check box
307     */
308    private CmsCheckBox generateCheckBox(Date date, boolean checkState) {
309
310        CmsCheckBox cb = new CmsCheckBox();
311        cb.setText(m_dateFormat.format(date));
312        cb.setChecked(checkState);
313        cb.getElement().setPropertyObject("date", date);
314        return cb;
315
316    }
317
318    /**
319     * Refresh the layout element.
320     */
321    private void reInitLayoutElements() {
322
323        m_panel.clear();
324        for (CmsCheckBox cb : m_checkBoxes) {
325            m_panel.add(setStyle(m_onlyLabels ? new Label(cb.getText()) : cb));
326        }
327    }
328
329    /**
330     * Updates the internal list of dates and fires a value change if necessary.
331     *
332     * @param dates the dates to set.
333     */
334    private void setDatesInternal(SortedSet<Date> dates) {
335
336        if (!m_dates.equals(dates)) {
337            m_dates = new TreeSet<>(dates);
338            fireValueChange();
339        }
340    }
341
342    /**
343     * Set the style for the widgets in the panel according to the chosen style option.
344     * @param widget the widget that should be styled.
345     * @return the styled widget.
346     */
347    private Widget setStyle(Widget widget) {
348
349        widget.setWidth(m_width);
350        widget.getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
351        return widget;
352    }
353
354}