001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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;
029
030import org.opencms.acacia.shared.CmsContentDefinition;
031import org.opencms.acacia.shared.CmsEntity;
032import org.opencms.acacia.shared.CmsValidationResult;
033import org.opencms.acacia.shared.rpc.I_CmsContentServiceAsync;
034import org.opencms.gwt.client.ui.CmsTabbedPanel;
035import org.opencms.util.CmsPair;
036
037import java.util.Map.Entry;
038
039import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
040import com.google.gwt.event.logical.shared.ValueChangeEvent;
041import com.google.gwt.event.logical.shared.ValueChangeHandler;
042import com.google.gwt.event.shared.EventHandler;
043import com.google.gwt.event.shared.GwtEvent;
044import com.google.gwt.event.shared.HandlerRegistration;
045import com.google.gwt.event.shared.SimpleEventBus;
046import com.google.gwt.user.client.Timer;
047import com.google.gwt.user.client.rpc.AsyncCallback;
048
049/**
050 * Validation handler.<p>
051 */
052public final class CmsValidationHandler
053implements ValueChangeHandler<CmsEntity>, HasValueChangeHandlers<CmsValidationContext> {
054
055    /**
056     * The validation timer.<p>
057     */
058    protected class ValidationTimer extends Timer {
059
060        /** The entity to validate. */
061        private CmsEntity m_entity;
062
063        /**
064         * Constructor.<p>
065         *
066         * @param entity the entity to validate
067         */
068        protected ValidationTimer(CmsEntity entity) {
069
070            m_entity = entity;
071        }
072
073        /**
074         * @see com.google.gwt.user.client.Timer#run()
075         */
076        @Override
077        public void run() {
078
079            validate(m_entity);
080            m_validationTimer = null;
081        }
082    }
083
084    /** Flag indicating the a validation call is running. */
085    boolean m_validating;
086
087    /** The current validation timer instance. */
088    Timer m_validationTimer;
089
090    /** The content service use for validation. */
091    private I_CmsContentServiceAsync m_contentService;
092
093    /** The event bus. */
094    private SimpleEventBus m_eventBus;
095
096    /** The forms tabbed panel. */
097    private CmsTabbedPanel<?> m_formTabPanel;
098
099    /** The handler registration. */
100    private HandlerRegistration m_handlerRegistration;
101
102    /** Indicates validation is paused. */
103    private boolean m_paused;
104
105    /** The root attribute handler. */
106    private CmsRootHandler m_rootHandler;
107
108    /** The validation context. */
109    private CmsValidationContext m_validationContext;
110
111    /**
112     * Clears validation message for an attribute handler.<p>
113     *
114     * @param handler the handler for which to clear the validation message
115     */
116    public static void clearValidation(I_CmsAttributeHandler handler) {
117
118        if (handler instanceof CmsAttributeHandler) {
119            ((CmsAttributeHandler)handler).removeValidationMessages();
120        }
121
122    }
123
124    /**
125     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
126     */
127    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<CmsValidationContext> handler) {
128
129        return addHandler(handler, ValueChangeEvent.getType());
130    }
131
132    /**
133     * Destroys the current handler instance.<p>
134     */
135    public void clear() {
136
137        if (m_handlerRegistration != null) {
138            m_handlerRegistration.removeHandler();
139            m_handlerRegistration = null;
140        }
141        m_validationContext = null;
142        m_paused = false;
143        m_validating = false;
144        if (m_validationTimer != null) {
145            m_validationTimer.cancel();
146            m_validationTimer = null;
147        }
148    }
149
150    /**
151     * Displays the given error messages within the form.<p>
152     *
153     * @param entityId the entity id
154     * @param validationResult the validationResult
155     */
156    public void displayValidation(String entityId, CmsValidationResult validationResult) {
157
158        if (m_formTabPanel != null) {
159            CmsAttributeHandler.clearErrorStyles(m_formTabPanel);
160        }
161        m_rootHandler.visit(CmsValidationHandler::clearValidation);
162        if (validationResult.hasWarnings(entityId)) {
163            for (Entry<String[], CmsPair<String, String>> warning : validationResult.getWarnings(entityId).entrySet()) {
164                String[] pathElements = warning.getKey();
165                // check if there are no errors for this attribute
166                if (!validationResult.hasErrors(entityId)
167                    || !validationResult.getErrors(entityId).containsKey(pathElements)) {
168                    CmsAttributeHandler handler = m_rootHandler.getHandlerByPath(pathElements);
169                    if (handler != null) {
170                        String attributeName = pathElements[pathElements.length - 1];
171                        handler.setWarningMessage(
172                            CmsContentDefinition.extractIndex(attributeName),
173                            warning.getValue().getFirst(),
174                            m_formTabPanel);
175                    }
176                }
177            }
178        }
179        if (validationResult.hasErrors(entityId)) {
180            String invalidFields = "";
181            for (Entry<String[], CmsPair<String, String>> error : validationResult.getErrors(entityId).entrySet()) {
182                String[] pathElements = error.getKey();
183                CmsAttributeHandler handler = m_rootHandler.getHandlerByPath(pathElements);
184                if (handler != null) {
185                    String attributeName = pathElements[pathElements.length - 1];
186                    handler.setErrorMessage(
187                        CmsContentDefinition.extractIndex(attributeName),
188                        error.getValue().getFirst(),
189                        m_formTabPanel);
190                }
191                invalidFields += error.getValue().getSecond() + ", ";
192            }
193            if (invalidFields.length() > 0) {
194                invalidFields = invalidFields.substring(0, invalidFields.length() - 2);
195            }
196            m_validationContext.addInvalidEntity(entityId, invalidFields);
197        } else {
198            m_validationContext.addValidEntity(entityId);
199        }
200        ValueChangeEvent.fire(this, m_validationContext);
201        m_validating = false;
202    }
203
204    /**
205     * @see com.google.gwt.event.shared.HasHandlers#fireEvent(com.google.gwt.event.shared.GwtEvent)
206     */
207    public void fireEvent(GwtEvent<?> event) {
208
209        ensureHandlers().fireEventFromSource(event, this);
210    }
211
212    /**
213     * Returns the validation context.<p>
214     *
215     * @return the validation context
216     */
217    public CmsValidationContext getValidationContext() {
218
219        return m_validationContext;
220    }
221
222    /**
223     * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent)
224     */
225    public void onValueChange(final ValueChangeEvent<CmsEntity> event) {
226
227        if (!m_paused) {
228            if (m_validationTimer != null) {
229                m_validationTimer.cancel();
230            }
231            m_validationTimer = new ValidationTimer(event.getValue());
232            m_validationTimer.schedule(300);
233        }
234    }
235
236    /**
237     * Registers the validation handler for the given entity.<p>
238     *
239     * @param entity the entity
240     */
241    public void registerEntity(CmsEntity entity) {
242
243        if (m_validationContext == null) {
244            m_validationContext = new CmsValidationContext();
245        }
246        if (m_handlerRegistration != null) {
247            m_handlerRegistration.removeHandler();
248        }
249        m_paused = false;
250        m_handlerRegistration = entity.addValueChangeHandler(this);
251    }
252
253    /**
254     * Sets the content service used for validation.<p>
255     *
256     * @param contentService the content service
257     */
258    public void setContentService(I_CmsContentServiceAsync contentService) {
259
260        m_contentService = contentService;
261    }
262
263    /**
264     * Sets the form tabbed panel.<p>
265     *
266     * @param tabPanel the tabbed panel
267     */
268    public void setFormTabPanel(CmsTabbedPanel<?> tabPanel) {
269
270        m_formTabPanel = tabPanel;
271    }
272
273    /**
274     * Sets the validation to pause.<p>
275     *
276     * @param paused <code>true</code> to pause the validation
277     * @param entity the entity will be revalidated when setting paused to <code>false</code>
278     */
279    public void setPaused(boolean paused, CmsEntity entity) {
280
281        if (paused != m_paused) {
282            m_paused = paused;
283            if (m_paused) {
284                if (m_validationTimer != null) {
285                    m_validationTimer.cancel();
286                    m_validationTimer = null;
287                }
288            } else {
289                m_validationTimer = new ValidationTimer(entity);
290                m_validationTimer.schedule(300);
291            }
292
293        }
294    }
295
296    /**
297     * Sets the root attribute handler.<p>
298     *
299     * @param rootHandler the root attribute handler
300     */
301    public void setRootHandler(CmsRootHandler rootHandler) {
302
303        m_rootHandler = rootHandler;
304    }
305
306    /**
307     * Adds this handler to the widget.
308     *
309     * @param <H> the type of handler to add
310     * @param type the event type
311     * @param handler the handler
312     * @return {@link HandlerRegistration} used to remove the handler
313     */
314    protected <H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type) {
315
316        return ensureHandlers().addHandlerToSource(type, this, handler);
317    }
318
319    /**
320     * Validates the given entity.<p>
321     *
322     * @param entity the entity
323     */
324    protected void validate(final CmsEntity entity) {
325
326        if (!m_validating) {
327            m_validating = true;
328            m_contentService.validateEntity(entity, new AsyncCallback<CmsValidationResult>() {
329
330                public void onFailure(Throwable caught) {
331
332                    // can be ignored
333                }
334
335                public void onSuccess(CmsValidationResult result) {
336
337                    displayValidation(entity.getId(), result);
338                }
339            });
340        }
341    }
342
343    /**
344     * Lazy initializing the handler manager.<p>
345     *
346     * @return the handler manager
347     */
348    private SimpleEventBus ensureHandlers() {
349
350        if (m_eventBus == null) {
351            m_eventBus = new SimpleEventBus();
352        }
353        return m_eventBus;
354    }
355}