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