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.client.css.I_CmsWidgetsLayoutBundle;
031import org.opencms.acacia.client.entity.CmsEntityBackend;
032import org.opencms.acacia.client.entity.I_CmsEntityBackend;
033import org.opencms.acacia.client.ui.CmsInlineEditOverlay;
034import org.opencms.acacia.client.widgets.CmsFormWidgetWrapper;
035import org.opencms.acacia.client.widgets.CmsStringWidget;
036import org.opencms.acacia.client.widgets.CmsTinyMCEWidget;
037import org.opencms.acacia.client.widgets.I_CmsEditWidget;
038import org.opencms.acacia.client.widgets.I_CmsFormEditWidget;
039import org.opencms.acacia.client.widgets.complex.CmsDataViewWidgetRenderer;
040import org.opencms.acacia.shared.CmsContentDefinition;
041import org.opencms.acacia.shared.CmsEntity;
042import org.opencms.acacia.shared.CmsEntityHtml;
043import org.opencms.acacia.shared.CmsTabInfo;
044import org.opencms.acacia.shared.CmsType;
045import org.opencms.acacia.shared.CmsValidationResult;
046import org.opencms.acacia.shared.rpc.I_CmsContentServiceAsync;
047import org.opencms.gwt.client.ui.CmsTabbedPanel;
048import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
049
050import java.util.ArrayList;
051import java.util.List;
052import java.util.Set;
053
054import com.google.gwt.dom.client.Element;
055import com.google.gwt.event.dom.client.ClickHandler;
056import com.google.gwt.event.logical.shared.ResizeEvent;
057import com.google.gwt.event.logical.shared.ResizeHandler;
058import com.google.gwt.event.logical.shared.ValueChangeHandler;
059import com.google.gwt.event.shared.HandlerRegistration;
060import com.google.gwt.i18n.client.Dictionary;
061import com.google.gwt.user.client.Command;
062import com.google.gwt.user.client.Timer;
063import com.google.gwt.user.client.Window;
064import com.google.gwt.user.client.rpc.AsyncCallback;
065import com.google.gwt.user.client.ui.FlowPanel;
066import com.google.gwt.user.client.ui.Panel;
067
068/**
069 * The content editor base.<p>
070 */
071public class CmsEditorBase implements I_CmsInlineHtmlUpdateHandler {
072
073    /** Message constant for key in the resource bundle. */
074    public static final String GUI_CHOICE_ADD_CHOICE_1 = "GUI_CHOICE_ADD_CHOICE_1"; //Add choice {0}
075
076    /** Message constant for key in the resource bundle. */
077    public static final String GUI_VIEW_ADD_1 = "GUI_VIEW_ADD_1"; //Add {0}
078
079    /** Message constant for key in the resource bundle. */
080    public static final String GUI_VIEW_CLOSE_0 = "GUI_VIEW_CLOSE_0"; //Close
081
082    /** Message constant for key in the resource bundle. */
083    public static final String GUI_VIEW_DELETE_1 = "GUI_VIEW_DELETE_1"; //Delete {0}
084
085    /** Message constant for key in the resource bundle. */
086    public static final String GUI_VIEW_EDIT_1 = "GUI_VIEW_EDIT_1"; // Edit {0}
087
088    /** Message constant for key in the resource bundle. */
089    public static final String GUI_VIEW_MOVE_1 = "GUI_VIEW_MOVE_1"; //Move {0}
090
091    /** Message constant for key in the resource bundle. */
092    public static final String GUI_VIEW_MOVE_DOWN_0 = "GUI_VIEW_MOVE_DOWN_0"; //Move down
093
094    /** Message constant for key in the resource bundle. */
095    public static final String GUI_VIEW_MOVE_UP_0 = "GUI_VIEW_MOVE_UP_0"; //Move up
096
097    /** The inline edit focus marker. */
098    private static final String INLINE_EDIT_FOCUS_MARKER = "shouldFocusOnInlineEdit";
099
100    /** The localized dictionary. */
101    private static Dictionary m_dictionary;
102
103    /** The entity back-end instance. */
104    protected I_CmsEntityBackend m_entityBackend;
105
106    /** The id of the edited entity. */
107    protected String m_entityId;
108
109    /** The in-line edit overlay hiding other content. */
110    private CmsInlineEditOverlay m_editOverlay;
111
112    /** The edited entity. */
113    private CmsEntity m_entity;
114
115    /** The form panel. */
116    private FlowPanel m_formPanel;
117
118    /** The tab panel if tabs are used. */
119    private CmsTabbedPanel<?> m_formTabs;
120
121    /** The window resize handler registration. */
122    private HandlerRegistration m_resizeHandlerRegistration;
123
124    /** The root attribute handler. */
125    private CmsRootHandler m_rootHandler;
126
127    /** The content service instance. */
128    private I_CmsContentServiceAsync m_service;
129
130    /** The tab infos. */
131    private List<CmsTabInfo> m_tabInfos;
132
133    /** The validation handler. */
134    private CmsValidationHandler m_validationHandler;
135
136    /** The widget service. */
137    private I_CmsWidgetService m_widgetService;
138
139    /**
140     * Constructor.<p>
141     *
142     * @param service the content service
143     * @param widgetService the widget service to use
144     */
145    public CmsEditorBase(I_CmsContentServiceAsync service, I_CmsWidgetService widgetService) {
146
147        I_CmsLayoutBundle.INSTANCE.generalCss().ensureInjected();
148        I_CmsLayoutBundle.INSTANCE.buttonCss().ensureInjected();
149        I_CmsLayoutBundle.INSTANCE.highlightCss().ensureInjected();
150        I_CmsLayoutBundle.INSTANCE.tabbedPanelCss().ensureInjected();
151        I_CmsLayoutBundle.INSTANCE.dialogCss().ensureInjected();
152        org.opencms.acacia.client.css.I_CmsLayoutBundle.INSTANCE.form().ensureInjected();
153        org.opencms.acacia.client.css.I_CmsLayoutBundle.INSTANCE.attributeChoice().ensureInjected();
154        I_CmsWidgetsLayoutBundle.INSTANCE.widgetCss().ensureInjected();
155        I_CmsWidgetsLayoutBundle.INSTANCE.galleryWidgetsCss().ensureInjected();
156        m_service = service;
157        m_entityBackend = CmsEntityBackend.getInstance();
158        m_widgetService = widgetService;
159        I_CmsEntityRenderer renderer = new CmsRenderer(m_entityBackend, m_widgetService);
160        m_widgetService.setDefaultRenderer(renderer);
161        m_widgetService.addWidgetFactory("string", new I_CmsWidgetFactory() {
162
163            public I_CmsFormEditWidget createFormWidget(String configuration) {
164
165                return new CmsFormWidgetWrapper(new CmsStringWidget());
166            }
167
168            public I_CmsEditWidget createInlineWidget(String configuration, Element element) {
169
170                return new CmsStringWidget(element);
171            }
172        });
173        m_widgetService.addWidgetFactory("html", new I_CmsWidgetFactory() {
174
175            public I_CmsFormEditWidget createFormWidget(String configuration) {
176
177                return new CmsFormWidgetWrapper(new CmsTinyMCEWidget(null));
178            }
179
180            public I_CmsEditWidget createInlineWidget(String configuration, Element element) {
181
182                return new CmsTinyMCEWidget(element, null);
183            }
184        });
185
186        // we may want to explicitly use the default renderer for specific attributes.
187        m_widgetService.addRenderer(new CmsRenderer(CmsEntityBackend.getInstance(), getWidgetService()));
188        m_widgetService.addRenderer(new CmsNativeComplexWidgetRenderer());
189        m_widgetService.addRenderer(new CmsDataViewWidgetRenderer());
190        m_validationHandler = new CmsValidationHandler();
191        m_validationHandler.setContentService(m_service);
192    }
193
194    /**
195     * Returns the formated message.<p>
196     *
197     * @param key the message key
198     * @param args  the parameters to insert into the placeholders
199     *
200     * @return the formated message
201     */
202    public static String getMessageForKey(String key, Object... args) {
203
204        String result = null;
205        if (hasDictionary()) {
206            result = m_dictionary.get(key);
207            if ((result != null) && (args != null) && (args.length > 0)) {
208                for (int i = 0; i < args.length; i++) {
209                    result = result.replace("{" + i + "}", String.valueOf(args[i]));
210                }
211            }
212        }
213        if (result == null) {
214            result = "";
215        }
216        return result;
217    }
218
219    /**
220     * Returns if the messages dictionary is set.<p>
221     *
222     * @return <code>true</code> if the messages dictionary is set
223     */
224    public static boolean hasDictionary() {
225
226        return m_dictionary != null;
227    }
228
229    /**
230     * Marks the given element to receive focus once the inline editing is initialized.<p>
231     *
232     * @param element the element to mark
233     */
234    public static void markForInlineFocus(Element element) {
235
236        element.setAttribute("rel", INLINE_EDIT_FOCUS_MARKER);
237    }
238
239    /**
240     * Sets the m_dictionary.<p>
241     *
242     * @param dictionary the m_dictionary to set
243     */
244    public static void setDictionary(Dictionary dictionary) {
245
246        m_dictionary = dictionary;
247    }
248
249    /**
250     * Checks whether the given element is marked to receive focus once the inline editing is initialized.<p>
251     *
252     * @param element the element to check
253     *
254     * @return <code>true</code> if the given element is marked to receive focus once the inline editing is initialized
255     */
256    public static boolean shouldFocusOnInlineEdit(Element element) {
257
258        return INLINE_EDIT_FOCUS_MARKER.equals(element.getAttribute("rel"));
259    }
260
261    /**
262     * Adds the value change handler to the entity with the given id.<p>
263     *
264     * @param entityId the entity id
265     * @param handler the change handler
266     */
267    public void addEntityChangeHandler(String entityId, ValueChangeHandler<CmsEntity> handler) {
268
269        CmsEntity entity = m_entityBackend.getEntity(entityId);
270        if (entity != null) {
271            entity.addValueChangeHandler(handler);
272        }
273    }
274
275    /**
276     * Adds a validation change handler.<p>
277     *
278     * @param handler the validation change handler
279     *
280     * @return the handler registration
281     */
282    public HandlerRegistration addValidationChangeHandler(ValueChangeHandler<CmsValidationContext> handler) {
283
284        return m_validationHandler.addValueChangeHandler(handler);
285    }
286
287    /**
288     * Destroys the form and related resources. Also clears all entities from the entity back-end<p>
289     *
290     * @param clearEntities <code>true</code> to also clear all entities
291     */
292    public void destroyForm(boolean clearEntities) {
293
294        CmsValueFocusHandler.getInstance().destroy();
295        if (clearEntities) {
296            m_entityBackend.clearEntities();
297        }
298    }
299
300    /**
301     * Returns the currently edited entity.<p>
302     *
303     * @return the currently edited entity
304     */
305    public CmsEntity getCurrentEntity() {
306
307        return m_entityBackend.getEntity(m_entityId);
308    }
309
310    /**
311     * Returns editor form tabs or null in case no tabs are used.<p>
312     *
313     * @return the editor form tabs
314     */
315    public CmsTabbedPanel<?> getFormTabs() {
316
317        return m_formTabs;
318    }
319
320    /**
321     * Returns the content service instance.<p>
322     *
323     * @return the content service
324     */
325    public I_CmsContentServiceAsync getService() {
326
327        return m_service;
328    }
329
330    /**
331     * Loads the content definition for the given entity and executes the callback on success.<p>
332     *
333     * @param entityId the entity id
334     * @param callback the callback
335     */
336    public void loadContentDefinition(final String entityId, final Command callback) {
337
338        AsyncCallback<CmsContentDefinition> asyncCallback = new AsyncCallback<CmsContentDefinition>() {
339
340            public void onFailure(Throwable caught) {
341
342                onRpcError(caught);
343            }
344
345            public void onSuccess(CmsContentDefinition result) {
346
347                registerContentDefinition(result);
348                callback.execute();
349            }
350        };
351        getService().loadContentDefinition(entityId, asyncCallback);
352    }
353
354    /**
355     * Registers the types and entities of the given content definition.<p>
356     *
357     * @param definition the content definition
358     */
359    public void registerContentDefinition(CmsContentDefinition definition) {
360
361        m_widgetService.addConfigurations(definition.getConfigurations());
362        CmsType baseType = definition.getTypes().get(definition.getEntityTypeName());
363        m_entityBackend.registerTypes(baseType, definition.getTypes());
364        m_entityBackend.registerEntity(definition.getEntity());
365    }
366
367    /**
368     * @see org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler#reinitWidgets(org.opencms.acacia.client.I_CmsInlineFormParent)
369     */
370    public void reinitWidgets(I_CmsInlineFormParent formParent) {
371
372        renderInlineEntity(m_entityId, formParent);
373    }
374
375    /**
376     * Renders the entity form within the given context.<p>
377     *
378     * @param entityId the entity id
379     * @param tabInfos the tab informations
380     * @param context the context element
381     * @param scrollParent the scroll element to be used for automatic scrolling during drag and drop
382    
383     */
384    public void renderEntityForm(String entityId, List<CmsTabInfo> tabInfos, Panel context, Element scrollParent) {
385
386        CmsEntity entity = m_entityBackend.getEntity(entityId);
387        if (entity != null) {
388            boolean initUndo = (m_entity == null) || !entity.getId().equals(m_entity.getId());
389            m_entity = entity;
390            CmsType type = m_entityBackend.getType(m_entity.getTypeName());
391            m_formPanel = new FlowPanel();
392            context.add(m_formPanel);
393            CmsAttributeHandler.setScrollElement(scrollParent);
394            CmsButtonBarHandler.INSTANCE.setWidgetService(m_widgetService);
395            if (m_rootHandler == null) {
396                m_rootHandler = new CmsRootHandler();
397            } else {
398                m_rootHandler.clearHandlers();
399            }
400            m_tabInfos = tabInfos;
401            m_formTabs = m_widgetService.getRendererForType(
402                type).renderForm(m_entity, m_tabInfos, m_formPanel, m_rootHandler, 0);
403            m_validationHandler.registerEntity(m_entity);
404            m_validationHandler.setRootHandler(m_rootHandler);
405            m_validationHandler.setFormTabPanel(m_formTabs);
406            if (initUndo) {
407                CmsUndoRedoHandler.getInstance().initialize(m_entity, this, m_rootHandler);
408            }
409            // trigger validation right away
410            m_validationHandler.validate(m_entity);
411        }
412    }
413
414    /**
415     * Renders the entity form within the given context.<p>
416     *
417     * @param entityId the entity id
418     * @param context the context element
419     * @param scrollParent the scroll element to be used for automatic scrolling during drag and drop
420     */
421    public void renderEntityForm(String entityId, Panel context, Element scrollParent) {
422
423        CmsEntity entity = m_entityBackend.getEntity(entityId);
424        if (entity != null) {
425            boolean initUndo = (m_entity == null) || !entity.getId().equals(m_entity.getId());
426            m_entity = entity;
427            CmsType type = m_entityBackend.getType(m_entity.getTypeName());
428            m_formPanel = new FlowPanel();
429            context.add(m_formPanel);
430            CmsAttributeHandler.setScrollElement(scrollParent);
431            CmsButtonBarHandler.INSTANCE.setWidgetService(m_widgetService);
432            if (m_rootHandler == null) {
433                m_rootHandler = new CmsRootHandler();
434            } else {
435                m_rootHandler.clearHandlers();
436            }
437            m_widgetService.getRendererForType(type).renderForm(m_entity, m_formPanel, m_rootHandler, 0);
438            m_formTabs = null;
439            m_tabInfos = null;
440            m_validationHandler.setContentService(m_service);
441            m_validationHandler.registerEntity(m_entity);
442            m_validationHandler.setRootHandler(m_rootHandler);
443            m_validationHandler.setFormTabPanel(null);
444            if (initUndo) {
445                CmsUndoRedoHandler.getInstance().initialize(m_entity, this, m_rootHandler);
446            }
447        }
448    }
449
450    /**
451     * Renders the entity form within the given context.<p>
452     *
453     * @param entityId the entity id
454     * @param formParent the form parent widget
455     */
456    public void renderInlineEntity(String entityId, I_CmsInlineFormParent formParent) {
457
458        m_entity = m_entityBackend.getEntity(entityId);
459        if (m_entity != null) {
460            if (m_rootHandler == null) {
461                m_rootHandler = new CmsRootHandler();
462            } else {
463                m_rootHandler.clearHandlers();
464            }
465            m_validationHandler.setContentService(m_service);
466            m_validationHandler.registerEntity(m_entity);
467            m_validationHandler.setRootHandler(m_rootHandler);
468            CmsType type = m_entityBackend.getType(m_entity.getTypeName());
469            CmsButtonBarHandler.INSTANCE.setWidgetService(m_widgetService);
470            m_widgetService.getRendererForType(type).renderInline(m_entity, formParent, this, m_rootHandler, 0);
471            CmsUndoRedoHandler.getInstance().initialize(m_entity, this, m_rootHandler);
472        }
473    }
474
475    /**
476     * Re-renders the form with the given entity data.<p>
477     *
478     * @param newContent the entity data
479     */
480    public void rerenderForm(CmsEntity newContent) {
481
482        m_validationHandler.setPaused(true, m_entity);
483        m_entityBackend.changeEntityContentValues(m_entity, newContent);
484        CmsType type = m_entityBackend.getType(m_entity.getTypeName());
485        if ((m_tabInfos != null) && !m_tabInfos.isEmpty()) {
486            int currentTab = m_formTabs.getSelectedIndex();
487            m_formPanel.clear();
488            m_rootHandler.clearHandlers();
489            m_formTabs = m_widgetService.getRendererForType(
490                type).renderForm(m_entity, m_tabInfos, m_formPanel, m_rootHandler, 0);
491            m_formTabs.selectTab(currentTab);
492        } else {
493            m_formPanel.clear();
494            m_rootHandler.clearHandlers();
495            m_widgetService.getRendererForType(type).renderForm(m_entity, m_tabInfos, m_formPanel, m_rootHandler, 0);
496        }
497        m_validationHandler.setPaused(false, m_entity);
498    }
499
500    /**
501     * Saves the given entities.<p>
502     *
503     * @param entities the entities to save
504     * @param clearOnSuccess <code>true</code> to clear the entity back-end instance on success
505     * @param callback the call back command
506     */
507    public void saveEntities(List<CmsEntity> entities, final boolean clearOnSuccess, final Command callback) {
508
509        AsyncCallback<CmsValidationResult> asyncCallback = new AsyncCallback<CmsValidationResult>() {
510
511            public void onFailure(Throwable caught) {
512
513                onRpcError(caught);
514            }
515
516            public void onSuccess(CmsValidationResult result) {
517
518                callback.execute();
519                if ((result != null) && result.hasErrors()) {
520                    //   CmsValidationHandler.getInstance().displayErrors(null, result)
521                }
522                if (clearOnSuccess) {
523                    destroyForm(true);
524                }
525            }
526        };
527        getService().saveEntities(entities, asyncCallback);
528    }
529
530    /**
531     * Saves the given entity.<p>
532     *
533     * @param entityIds the entity ids
534     * @param clearOnSuccess <code>true</code> to clear all entities from entity back-end on success
535     * @param callback the callback executed on success
536     */
537    public void saveEntities(Set<String> entityIds, boolean clearOnSuccess, Command callback) {
538
539        List<CmsEntity> entities = new ArrayList<CmsEntity>();
540        for (String entityId : entityIds) {
541            CmsEntity entity = m_entityBackend.getEntity(entityId);
542            if (entity != null) {
543                entities.add(entity);
544            }
545        }
546        saveEntities(entities, clearOnSuccess, callback);
547    }
548
549    /**
550     * Saves the given entity.<p>
551     *
552     * @param entity the entity
553     * @param clearOnSuccess <code>true</code> to clear all entities from entity back-end on success
554     * @param callback the callback executed on success
555     */
556    public void saveEntity(CmsEntity entity, final boolean clearOnSuccess, final Command callback) {
557
558        AsyncCallback<CmsValidationResult> asyncCallback = new AsyncCallback<CmsValidationResult>() {
559
560            public void onFailure(Throwable caught) {
561
562                onRpcError(caught);
563            }
564
565            public void onSuccess(CmsValidationResult result) {
566
567                callback.execute();
568                if (clearOnSuccess) {
569                    destroyForm(true);
570                }
571            }
572        };
573        getService().saveEntity(entity, asyncCallback);
574    }
575
576    /**
577     * Saves the given entity.<p>
578     *
579     * @param entityId the entity id
580     * @param clearOnSuccess <code>true</code> to clear all entities from entity back-end on success
581     * @param callback the callback executed on success
582     */
583    public void saveEntity(String entityId, boolean clearOnSuccess, Command callback) {
584
585        CmsEntity entity = m_entityBackend.getEntity(entityId);
586        saveEntity(entity, clearOnSuccess, callback);
587    }
588
589    /**
590     * Saves the given entity.<p>
591     *
592     * @param entityId the entity id
593     * @param callback the callback executed on success
594     */
595    public void saveEntity(String entityId, Command callback) {
596
597        CmsEntity entity = m_entityBackend.getEntity(entityId);
598        saveEntity(entity, false, callback);
599    }
600
601    /**
602    * @see org.opencms.acacia.client.I_CmsInlineHtmlUpdateHandler#updateHtml(org.opencms.acacia.client.I_CmsInlineFormParent, com.google.gwt.user.client.Command)
603    */
604    public void updateHtml(final I_CmsInlineFormParent formParent, final Command onSuccess) {
605
606        AsyncCallback<CmsEntityHtml> callback = new AsyncCallback<CmsEntityHtml>() {
607
608            public void onFailure(Throwable caught) {
609
610                onRpcError(caught);
611            }
612
613            public void onSuccess(CmsEntityHtml result) {
614
615                if (result.getHtmlContent() != null) {
616                    formParent.replaceHtml(result.getHtmlContent());
617                    onSuccess.execute();
618                }
619            }
620        };
621        getService().updateEntityHtml(getCurrentEntity(), getContextUri(), getHtmlContextInfo(), callback);
622    }
623
624    /**
625     * Adds a click handler to the edit overlay.<p>
626     *
627     * @param handler the click handler
628     *
629     * @return the click handler registration
630     */
631    protected HandlerRegistration addOverlayClickHandler(ClickHandler handler) {
632
633        return m_editOverlay.addClickHandler(handler);
634    }
635
636    /**
637     * Clears the editor.<p>
638     */
639    protected void clearEditor() {
640
641        removeEditOverlays();
642        CmsUndoRedoHandler.getInstance().clear();
643        m_validationHandler.clear();
644        m_entity = null;
645        m_entityId = null;
646        m_tabInfos = null;
647        m_rootHandler = null;
648        m_formPanel = null;
649        m_formTabs = null;
650    }
651
652    /**
653     * Returns the context URI.<p>
654     * Needed when updating the HTML due to content data changes.<p>
655     *
656     * Override to supply the required info.<p>
657     *
658     * @return the context URI
659     */
660    protected String getContextUri() {
661
662        return "";
663    }
664
665    /**
666     * Returns the in-line HTML context info.<p>
667     * Needed when updating the HTML due to content data changes.<p>
668     *
669     * Override to supply the required info.<p>
670     *
671     * @return the HTML context info
672     */
673    protected String getHtmlContextInfo() {
674
675        return "";
676    }
677
678    /**
679     * Returns the root attribute handler.<p>
680     *
681     * @return the root attribute handler
682     */
683    protected CmsRootHandler getRootAttributeHandler() {
684
685        return m_rootHandler;
686    }
687
688    /**
689     * Returns the validation handler.<p>
690     *
691     * @return the validation handler
692     */
693    protected CmsValidationHandler getValidationHandler() {
694
695        return m_validationHandler;
696    }
697
698    /**
699     * Returns the widget service.<p>
700     *
701     * @return the widget service
702     */
703    protected I_CmsWidgetService getWidgetService() {
704
705        return m_widgetService;
706    }
707
708    /**
709     * Initializes the edit overlay to be positioned around the given element.<p>
710     *
711     * @param element the element
712     */
713    protected void initEditOverlay(Element element) {
714
715        CmsInlineEditOverlay.removeAll();
716        m_editOverlay = CmsInlineEditOverlay.addOverlayForElement(element);
717        if (m_resizeHandlerRegistration != null) {
718            m_resizeHandlerRegistration.removeHandler();
719        }
720        // add a handler to ensure the edit overlays get adjusted to changed window size
721        m_resizeHandlerRegistration = Window.addResizeHandler(new ResizeHandler() {
722
723            private Timer m_resizeTimer;
724
725            public void onResize(ResizeEvent event) {
726
727                if (m_resizeTimer == null) {
728                    m_resizeTimer = new Timer() {
729
730                        @Override
731                        public void run() {
732
733                            handleResize();
734                        }
735                    };
736                    m_resizeTimer.schedule(300);
737                }
738            }
739
740            /**
741             * Handles the window resize.<p>
742             */
743            void handleResize() {
744
745                m_resizeTimer = null;
746                CmsInlineEditOverlay.updateCurrentOverlayPosition();
747            }
748        });
749    }
750
751    /**
752     * Handles RPC errors.<p>
753     *
754     * Override this for better error handling
755     *
756     * @param caught the error caught from the RPC
757     */
758    protected void onRpcError(Throwable caught) {
759
760        // doing nothing
761    }
762
763    /**
764     * Removes the edit overlay from the DOM.<p>
765     */
766    protected void removeEditOverlays() {
767
768        CmsInlineEditOverlay.removeAll();
769        m_editOverlay = null;
770        if (m_resizeHandlerRegistration != null) {
771            m_resizeHandlerRegistration.removeHandler();
772            m_resizeHandlerRegistration = null;
773        }
774    }
775
776    /**
777     * Updates the edit overlay position.<p>
778     */
779    protected void updateOverlayPosition() {
780
781        if (m_editOverlay != null) {
782            m_editOverlay.updatePosition();
783        }
784    }
785}