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