001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH (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.acacia.client.widgets.I_CmsEditWidget;
031import org.opencms.acacia.shared.CmsSerialDateUtil;
032import org.opencms.acacia.shared.I_CmsSerialDateValue.EndType;
033import org.opencms.acacia.shared.I_CmsSerialDateValue.Month;
034import org.opencms.acacia.shared.I_CmsSerialDateValue.PatternType;
035import org.opencms.acacia.shared.I_CmsSerialDateValue.WeekDay;
036import org.opencms.acacia.shared.I_CmsSerialDateValue.WeekOfMonth;
037import org.opencms.acacia.shared.rpc.I_CmsSerialDateService;
038import org.opencms.acacia.shared.rpc.I_CmsSerialDateServiceAsync;
039import org.opencms.ade.contenteditor.client.Messages;
040import org.opencms.gwt.client.CmsCoreProvider;
041import org.opencms.gwt.client.rpc.CmsRpcAction;
042import org.opencms.gwt.client.ui.CmsConfirmDialog;
043import org.opencms.gwt.client.ui.I_CmsConfirmDialogHandler;
044import org.opencms.gwt.client.util.CmsDomUtil;
045import org.opencms.util.CmsPair;
046
047import java.util.ArrayList;
048import java.util.Collection;
049import java.util.Date;
050import java.util.HashMap;
051import java.util.Map;
052import java.util.Objects;
053import java.util.SortedSet;
054import java.util.TreeSet;
055
056import com.google.gwt.core.shared.GWT;
057import com.google.gwt.dom.client.Element;
058import com.google.gwt.event.dom.client.FocusEvent;
059import com.google.gwt.event.dom.client.FocusHandler;
060import com.google.gwt.event.logical.shared.ValueChangeEvent;
061import com.google.gwt.event.logical.shared.ValueChangeHandler;
062import com.google.gwt.event.shared.HandlerRegistration;
063import com.google.gwt.i18n.client.DateTimeFormat;
064import com.google.gwt.user.client.Command;
065import com.google.gwt.user.client.Timer;
066import com.google.gwt.user.client.rpc.ServiceDefTarget;
067import com.google.gwt.user.client.ui.Composite;
068
069/** Controller for the serial date widget, being the widget implementation itself. */
070public class CmsSerialDateController extends Composite
071implements I_CmsEditWidget, I_ChangeHandler, I_StatusUpdateHandler {
072
073    /** Data wrapper for the default values to set when changing the pattern, dependent on the event's start date. */
074    public static class PatternDefaultValues {
075
076        /** The date used for the initialization. */
077        private final Date m_date;
078        /** The default month. */
079        private final Month m_month;
080        /** The default day of month. */
081        private final int m_dayOfMonth;
082        /** The default week day. */
083        private final WeekDay m_weekDay;
084        /** The default week of month. */
085        private final WeekOfMonth m_weekOfMonth;
086        /** The default interval. */
087        private final int m_interval;
088        /** The default weeks of month. */
089        private Collection<WeekOfMonth> m_weeksOfMonth;
090
091        /**
092         * Default constructor.
093         * @param startDate the date, that determines the default values.
094         */
095        @SuppressWarnings("deprecation")
096        protected PatternDefaultValues(Date startDate) {
097
098            m_date = startDate;
099            m_month = null == startDate ? Month.JANUARY : Month.values()[startDate.getMonth()];
100            m_dayOfMonth = null == startDate ? 1 : startDate.getDate();
101            m_weekDay = null == startDate ? WeekDay.SUNDAY : WeekDay.values()[startDate.getDay()];
102            m_weekOfMonth = null == startDate ? WeekOfMonth.FIRST : WeekOfMonth.values()[(startDate.getDate() / 7)];
103            Collection<WeekOfMonth> weeksOfMonth = new ArrayList<>(1);
104            weeksOfMonth.add(m_weekOfMonth);
105            m_weeksOfMonth = weeksOfMonth;
106            m_interval = 1;
107        }
108
109        /**
110         * Returns the date used for the initialization.
111         * @return the date used for the initialization.
112         */
113        public Date getDate() {
114
115            return m_date;
116        }
117
118        /**
119         * Returns the default day of month.
120         * @return the default day of month.
121         */
122        public int getDayOfMonth() {
123
124            return m_dayOfMonth;
125        }
126
127        /**
128         * Returns the default interval.
129         * @return the default interval.
130         */
131        public int getInterval() {
132
133            return m_interval;
134        }
135
136        /**
137         * Returns the default month.
138         * @return the default month.
139         */
140        public Month getMonth() {
141
142            return m_month;
143        }
144
145        /**
146         * Returns the default week day.
147         * @return the default week day.
148         */
149        public WeekDay getWeekDay() {
150
151            return m_weekDay;
152        }
153
154        /**
155         * Returns the default week of month.
156         * @return the default week of month.
157         */
158        public WeekOfMonth getWeekOfMonth() {
159
160            return m_weekOfMonth;
161        }
162
163        /**
164         * Returns the default weeks of month.
165         * @return the default weeks of month.
166         */
167        public Collection<WeekOfMonth> getWeeksOfMonth() {
168
169            return m_weeksOfMonth;
170        }
171    }
172
173    /**
174     * The status update timer.<p>
175     * Status update takes place at most every 500 milliseconds.
176     * Whenever re-update is triggered during the time waiting, the timer is reset,
177     * i.e., it is waited for 500 milliseconds again.
178     */
179    protected static class StatusUpdateTimer extends Timer {
180
181        /** The single status update timer that is allowed. */
182        private static StatusUpdateTimer m_timer;
183        /** The handler to call for the validation. */
184        private I_StatusUpdateHandler m_handler;
185
186        /**
187         * Constructor.<p>
188         * @param handler the handler to call for the status update.
189         */
190        StatusUpdateTimer(I_StatusUpdateHandler handler) {
191
192            m_handler = handler;
193        }
194
195        /**
196         * Trigger the status update after a certain time out.
197         * @param handler the status update handler, that actually performs the status update.
198         */
199        public static void updateStatus(I_StatusUpdateHandler handler) {
200
201            if (null != m_timer) {
202                m_timer.cancel();
203            }
204            m_timer = new StatusUpdateTimer(handler);
205            m_timer.schedule(500);
206        }
207
208        /**
209         * @see com.google.gwt.user.client.Timer#run()
210         */
211        @Override
212        public void run() {
213
214            m_handler.updateStatus();
215            m_timer = null;
216        }
217
218    }
219
220    /** Confirmation dialog that should be shown when exceptions are removed when the value changes. */
221    private class CmsExceptionsDeleteConfirmDialog {
222
223        /** The confirmation dialog that is shown. */
224        CmsConfirmDialog m_dialog;
225        /** The command to execute on confirmation. */
226        Command m_cmd;
227
228        /** The value to reset the exceptions */
229        final CmsSerialDateValue m_value;
230
231        /**
232         * Default constructor.
233         * @param value the value where the exceptions should be reset.
234         */
235        CmsExceptionsDeleteConfirmDialog(final CmsSerialDateValue value) {
236
237            m_value = value;
238            m_dialog = new CmsConfirmDialog(
239                Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_EXCEPTION_DIALOG_CAPTION_0),
240                Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_EXCEPTION_DIALOG_MESSAGE_0));
241            m_dialog.setOkText(Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_DIALOG_YES_BUTTON_0));
242            m_dialog.setCloseText(Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_DIALOG_NO_BUTTON_0));
243            m_dialog.setHandler(new I_CmsConfirmDialogHandler() {
244
245                public void onClose() {
246
247                    handleClose();
248
249                }
250
251                public void onOk() {
252
253                    handleOk();
254
255                }
256            });
257        }
258
259        /**
260         * Show the dialog.
261         * @param okCmd the command to execute when "ok" is clicked.
262         */
263        public void show(final Command okCmd) {
264
265            m_cmd = okCmd;
266            m_dialog.center();
267        }
268
269        /**
270         * Method called when the dialog is closed not performing the action.
271         */
272        void handleClose() {
273
274            m_view.onValueChange();
275            m_dialog.hide();
276        }
277
278        /**
279         * Method called when the dialog is closed performing the action.
280         */
281        void handleOk() {
282
283            m_value.clearExceptions();
284            m_cmd.execute();
285            m_dialog.hide();
286        }
287    }
288
289    /** Confirmation dialog to show if the series binding is removed. */
290    private class CmsRemoveSeriesBindingConfirmDialog {
291
292        /** The confirmation dialog that is shown. */
293        CmsConfirmDialog m_dialog;
294        /** The command to execute on confirmation. */
295        Command m_cmd;
296
297        /** The value to reset the exceptions */
298        final CmsSerialDateValue m_value;
299
300        /**
301         * Default constructor.
302         * @param value the value where the exceptions should be reset.
303         */
304        CmsRemoveSeriesBindingConfirmDialog(final CmsSerialDateValue value) {
305
306            m_value = value;
307            m_dialog = new CmsConfirmDialog(
308                Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_SERIES_BINDING_DIALOG_CAPTION_0),
309                Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_SERIES_BINDING_DIALOG_MESSAGE_0));
310            m_dialog.setOkText(Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_DIALOG_YES_BUTTON_0));
311            m_dialog.setCloseText(Messages.get().key(Messages.GUI_SERIALDATE_CONFIRM_DIALOG_NO_BUTTON_0));
312            m_dialog.setHandler(new I_CmsConfirmDialogHandler() {
313
314                public void onClose() {
315
316                    handleClose();
317
318                }
319
320                public void onOk() {
321
322                    handleOk();
323
324                }
325            });
326        }
327
328        /**
329         * Show the dialog.
330         * @param okCmd the command to execute when "ok" is clicked.
331         */
332        public void show(final Command okCmd) {
333
334            m_cmd = okCmd;
335            m_dialog.center();
336        }
337
338        /**
339         * Method called when the dialog is closed not performing the action.
340         */
341        void handleClose() {
342
343            m_view.onValueChange();
344            m_dialog.hide();
345        }
346
347        /**
348         * Method called when the dialog is closed performing the action.
349         */
350        void handleOk() {
351
352            m_value.clearExceptions();
353            m_cmd.execute();
354            m_dialog.hide();
355        }
356
357    }
358
359    /** Default date format. */
360    public static final String DEFAULT_DATE_FORMAT = "EEEE, MMMM dd, yyyy";
361
362    /** The RPC service for the serial date widget. */
363    private static I_CmsSerialDateServiceAsync SERVICE;
364
365    /** Flag, indicating if the widget is currently active. */
366    private boolean m_active;
367
368    /** RPC call action to get dates. */
369    private final CmsRpcAction<Collection<CmsPair<Date, Boolean>>> m_getDatesAction;
370
371    /** RPC call action to get the current status. */
372    private final CmsRpcAction<CmsPair<Boolean, String>> m_statusUpdateAction;
373
374    /** The pattern controllers. */
375    private final Map<PatternType, I_CmsSerialDatePatternController> m_patternControllers = new HashMap<>();
376
377    /* Date and time formats */
378
379    /** Format with date only. */
380    DateTimeFormat m_dateFormat = DateTimeFormat.getFormat(
381        Messages.get().keyDefault(Messages.GUI_SERIALDATE_DATE_FORMAT_0, DEFAULT_DATE_FORMAT));
382
383    /** The view */
384    final CmsSerialDateView m_view;
385
386    /** The model */
387    final CmsSerialDateValue m_model;
388
389    /** The default values to use when switching the pattern. They depend on the start date of the events. */
390    private PatternDefaultValues m_patternDefaultValues;
391
392    /** The confirmation dialog for deletion of exceptions. */
393    private CmsExceptionsDeleteConfirmDialog m_exceptionConfirmDialog;
394
395    /** The confirmation dialog for deleting the binding to another series. */
396    private CmsRemoveSeriesBindingConfirmDialog m_removeSeriesBindingConfirmDialog;
397
398    /**
399     * Category field widgets for ADE forms.<p>
400     */
401    public CmsSerialDateController() {
402
403        m_model = new CmsSerialDateValue();
404        m_view = new CmsSerialDateView(this, m_model);
405        initWidget(m_view);
406        setPatternDefaultValues(m_model.getStart());
407        initPatternControllers();
408        m_getDatesAction = new CmsRpcAction<Collection<CmsPair<Date, Boolean>>>() {
409
410            @Override
411            public void execute() {
412
413                getService().getDates(m_model.toString(), this);
414
415            }
416
417            @Override
418            protected void onResponse(Collection<CmsPair<Date, Boolean>> result) {
419
420                CmsSerialDateController.this.m_view.showCurrentDates(result);
421            }
422        };
423        m_statusUpdateAction = new CmsRpcAction<CmsPair<Boolean, String>>() {
424
425            @Override
426            public void execute() {
427
428                getService().getStatus(m_model.toString(), this);
429
430            }
431
432            @Override
433            protected void onResponse(CmsPair<Boolean, String> result) {
434
435                m_view.setManagementButtonEnabled(Objects.equals(Boolean.TRUE, result.getFirst()));
436                m_view.setStatus(result.getSecond());
437
438            }
439
440        };
441        m_active = true;
442        m_exceptionConfirmDialog = new CmsExceptionsDeleteConfirmDialog(m_model);
443        m_removeSeriesBindingConfirmDialog = new CmsRemoveSeriesBindingConfirmDialog(m_model);
444    }
445
446    /**
447     * @see com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.google.gwt.event.dom.client.FocusHandler)
448     */
449    public HandlerRegistration addFocusHandler(FocusHandler handler) {
450
451        return addDomHandler(handler, FocusEvent.getType());
452    }
453
454    /**
455     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
456     */
457    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<String> handler) {
458
459        return addHandler(handler, ValueChangeEvent.getType());
460    }
461
462    /**
463     * @see org.opencms.acacia.client.widgets.serialdate.I_ChangeHandler#conditionallyRemoveExceptionsOnChange(com.google.gwt.user.client.Command, boolean)
464     */
465    @Override
466    public void conditionallyRemoveExceptionsOnChange(Command action, boolean showDialog) {
467
468        if (m_model.hasExceptions() && showDialog) {
469            m_exceptionConfirmDialog.show(action);
470        } else {
471            action.execute();
472        }
473    }
474
475    /**
476     * Show the dates for managing exceptions.
477     */
478    public void executeShowDatesAction() {
479
480        m_getDatesAction.execute();
481
482    }
483
484    /**
485     * Returns the controller for the currently active pattern.
486     * @return the controller for the currently active pattern.
487     */
488    public I_CmsSerialDatePatternController getPattern() {
489
490        return m_patternControllers.get(m_model.getPatternType());
491    }
492
493    /**
494     * Returns the default values to set for the patterns dependent on the current start date.
495     * @return the default values to set for the patterns dependent on the current start date.
496     */
497    @Override
498    public PatternDefaultValues getPatternDefaultValues() {
499
500        return m_patternDefaultValues;
501    }
502
503    /**
504     * Returns the widget to place in the pattern panel.
505     * @return the widget to place in the pattern panel.
506     */
507    public I_CmsSerialDatePatternView getPatternView() {
508
509        return getPattern().getView();
510    }
511
512    /**
513     * @see com.google.gwt.user.client.ui.HasValue#getValue()
514     */
515    public String getValue() {
516
517        return m_model.toString();
518    }
519
520    /**
521     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#isActive()
522     */
523    public boolean isActive() {
524
525        return m_active;
526    }
527
528    /**
529     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#onAttachWidget()
530     */
531    public void onAttachWidget() {
532
533        super.onAttach();
534    }
535
536    /**
537     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#owns(com.google.gwt.dom.client.Element)
538     */
539    public boolean owns(Element element) {
540
541        return getElement().isOrHasChild(element);
542    }
543
544    /**
545     * @see org.opencms.acacia.client.widgets.serialdate.I_ChangeHandler#removeExceptionsOnChange(com.google.gwt.user.client.Command)
546     */
547    @Override
548    public void removeExceptionsOnChange(Command cmd) {
549
550        conditionallyRemoveExceptionsOnChange(cmd, true);
551
552    }
553
554    /**
555     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setActive(boolean)
556     */
557    public void setActive(boolean active) {
558
559        if (active != m_active) {
560            m_active = active;
561            m_view.setActive(active);
562        }
563
564    }
565
566    /**
567     * Set the flag, indicating if the events are displayed as "current" till they end (true) or only till they start (false).
568     * @param isCurrentTillEnd the flag, indicating if the events are displayed as "current" till they end (true) or only till they start (false).
569     */
570    public void setCurrentTillEnd(Boolean isCurrentTillEnd) {
571
572        if (m_model.isCurrentTillEnd() ^ ((null != isCurrentTillEnd) && isCurrentTillEnd.booleanValue())) {
573            m_model.setCurrentTillEnd(isCurrentTillEnd);
574            valueChanged();
575        }
576    }
577
578    /**
579     * Set the end time.
580     * @param date the end time to set.
581     */
582    public void setEndTime(final Date date) {
583
584        if (!Objects.equals(m_model.getEnd(), date)) {
585            m_model.setEnd(date);
586            valueChanged();
587        }
588
589    }
590
591    /**
592     * Set the duration option.
593     * @param value the duration option to set ({@link EndType} as string).
594     */
595    public void setEndType(final String value) {
596
597        final EndType endType = EndType.valueOf(value);
598        if (!endType.equals(m_model.getEndType())) {
599            removeExceptionsOnChange(new Command() {
600
601                public void execute() {
602
603                    switch (endType) {
604                        case SINGLE:
605                            m_model.setOccurrences(0);
606                            m_model.setSeriesEndDate(null);
607                            break;
608                        case TIMES:
609                            m_model.setOccurrences(10);
610                            m_model.setSeriesEndDate(null);
611                            break;
612                        case DATE:
613                            m_model.setOccurrences(0);
614                            m_model.setSeriesEndDate(m_model.getStart() == null ? new Date() : m_model.getStart());
615                            break;
616                        default:
617                            break;
618                    }
619                    m_model.setEndType(endType);
620                    valueChanged();
621                }
622            });
623        }
624
625    }
626
627    /**
628     * Toggle between single events and series.
629     * @param isSeries flag, indicating if we want a series of events.
630     */
631    public void setIsSeries(Boolean isSeries) {
632
633        if (null != isSeries) {
634            final boolean series = isSeries.booleanValue();
635            if ((null != m_model.getParentSeriesId()) && series) {
636                m_removeSeriesBindingConfirmDialog.show(new Command() {
637
638                    public void execute() {
639
640                        m_model.setParentSeriesId(null);
641                        setPattern(PatternType.DAILY.toString());
642
643                    }
644                });
645            } else {
646                setPattern(series ? PatternType.DAILY.toString() : PatternType.NONE.toString());
647            }
648        }
649    }
650
651    /**
652     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setName(java.lang.String)
653     */
654    public void setName(String name) {
655
656        // not necessary
657
658    }
659
660    /**
661     * Set the occurrences. If the String is invalid, the occurrences will be set to "-1" to cause server-side validation to fail.
662     * @param occurrences the interval to set.
663     */
664    public void setOccurrences(String occurrences) {
665
666        int o = CmsSerialDateUtil.toIntWithDefault(occurrences, -1);
667        if (m_model.getOccurrences() != o) {
668            m_model.setOccurrences(o);
669            valueChanged();
670        }
671    }
672
673    /**
674     * Set the serial pattern type.
675     * @param patternType the pattern type to set.
676     */
677    public void setPattern(String patternType) {
678
679        final PatternType type = PatternType.valueOf(patternType);
680        if (type != m_model.getPatternType()) {
681            removeExceptionsOnChange(new Command() {
682
683                public void execute() {
684
685                    EndType oldEndType = m_model.getEndType();
686                    m_model.setPatternType(type);
687                    m_model.setIndividualDates(null);
688                    m_model.setInterval(getPatternDefaultValues().getInterval());
689                    m_model.setEveryWorkingDay(Boolean.FALSE);
690                    m_model.clearWeekDays();
691                    m_model.clearIndividualDates();
692                    m_model.clearWeeksOfMonth();
693                    m_model.clearExceptions();
694                    if (type.equals(PatternType.NONE) || type.equals(PatternType.INDIVIDUAL)) {
695                        m_model.setEndType(EndType.SINGLE);
696                    } else if (oldEndType.equals(EndType.SINGLE)) {
697                        m_model.setEndType(EndType.TIMES);
698                        m_model.setOccurrences(10);
699                        m_model.setSeriesEndDate(null);
700                    }
701                    m_model.setDayOfMonth(getPatternDefaultValues().getDayOfMonth());
702                    m_model.setMonth(getPatternDefaultValues().getMonth());
703                    if (type.equals(PatternType.WEEKLY)) {
704                        m_model.setWeekDay(getPatternDefaultValues().getWeekDay());
705                    }
706                    valueChanged();
707                }
708            });
709        }
710
711    }
712
713    /**
714     * Set the serial end date.
715     * @param date the serial end date.
716     */
717    public void setSeriesEndDate(Date date) {
718
719        if (!Objects.equals(m_model.getSeriesEndDate(), date)) {
720            m_model.setSeriesEndDate(date);
721            valueChanged();
722        }
723
724    }
725
726    /**
727     * Set the start time.
728     * @param date the start time to set.
729     */
730    public void setStartTime(final Date date) {
731
732        if (!Objects.equals(m_model.getStart(), date)) {
733            removeExceptionsOnChange(new Command() {
734
735                public void execute() {
736
737                    m_model.setStart(date);
738                    setPatternDefaultValues(date);
739                    valueChanged();
740                }
741            });
742        }
743
744    }
745
746    /**
747     * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object)
748     */
749    public void setValue(String value) {
750
751        setValue(value, false);
752
753    }
754
755    /**
756     * @see org.opencms.acacia.client.widgets.I_CmsEditWidget#setValue(java.lang.String, boolean)
757     */
758    public void setValue(String value, boolean fireEvent) {
759
760        if (!m_model.toString().equals(value)) {
761            m_model.setValue(value);
762            setPatternDefaultValues(m_model.getStart());
763            if (fireEvent) {
764                valueChanged();
765            }
766        }
767    }
768
769    /**
770     * Sets the whole day flag.
771     * @param isWholeDay flag, indicating if the event lasts whole days.
772     */
773    public void setWholeDay(Boolean isWholeDay) {
774
775        if (m_model.isWholeDay() ^ ((null != isWholeDay) && isWholeDay.booleanValue())) {
776            m_model.setWholeDay(isWholeDay);
777            valueChanged();
778        }
779    }
780
781    /**
782     * @see org.opencms.acacia.client.widgets.serialdate.I_ChangeHandler#sizeChanged()
783     */
784    public void sizeChanged() {
785
786        CmsDomUtil.resizeAncestor(m_view.getParent());
787    }
788
789    /**
790     * Updates the exceptions.
791     * @param exceptions the exceptions to set
792     */
793    public void updateExceptions(SortedSet<Date> exceptions) {
794
795        SortedSet<Date> e = null == exceptions ? new TreeSet<Date>() : exceptions;
796        if (!m_model.getExceptions().equals(e)) {
797            m_model.setExceptions(e);
798            m_view.updateExceptions();
799            valueChanged();
800            sizeChanged();
801        }
802
803    }
804
805    /**
806     * @see org.opencms.acacia.client.widgets.serialdate.I_StatusUpdateHandler#updateStatus()
807     */
808    public void updateStatus() {
809
810        m_statusUpdateAction.execute();
811    }
812
813    /**
814     * @see org.opencms.acacia.client.widgets.serialdate.I_ChangeHandler#valueChanged()
815     */
816    @Override
817    public void valueChanged() {
818
819        StatusUpdateTimer.updateStatus(this);
820        m_view.onValueChange();
821        ValueChangeEvent.fire(this, m_model.toString());
822    }
823
824    /**
825    * Returns the RPC service for serial dates.
826    * @return the RPC service for serial dates.
827    */
828    I_CmsSerialDateServiceAsync getService() {
829
830        if (SERVICE == null) {
831            SERVICE = GWT.create(I_CmsSerialDateService.class);
832            String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.contenteditor.CmsSerialDateService.gwt");
833            ((ServiceDefTarget)SERVICE).setServiceEntryPoint(serviceUrl);
834        }
835        return SERVICE;
836    }
837
838    /**
839     * Sets the default pattern values dependent on the provided start date.
840     * @param startDate the date, the default values are determined with.
841     */
842    void setPatternDefaultValues(Date startDate) {
843
844        if ((m_patternDefaultValues == null) || !Objects.equals(m_patternDefaultValues.getDate(), startDate)) {
845            m_patternDefaultValues = new PatternDefaultValues(startDate);
846        }
847    }
848
849    /**
850     * Initialize the pattern controllers.
851     */
852    private void initPatternControllers() {
853
854        m_patternControllers.put(PatternType.NONE, new CmsPatternPanelNoneController());
855        m_patternControllers.put(PatternType.DAILY, new CmsPatternPanelDailyController(m_model, this));
856        m_patternControllers.put(PatternType.WEEKLY, new CmsPatternPanelWeeklyController(m_model, this));
857        m_patternControllers.put(PatternType.MONTHLY, new CmsPatternPanelMonthlyController(m_model, this));
858        m_patternControllers.put(PatternType.YEARLY, new CmsPatternPanelYearlyController(m_model, this));
859        // m_patternControllers.put(PatternType.INDIVIDUAL, new CmsPatternPanelIndividualController(m_model, this));
860    }
861
862}