001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (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.ade.contenteditor.widgetregistry.client;
029
030import org.opencms.acacia.client.I_CmsEntityRenderer;
031import org.opencms.acacia.client.I_CmsWidgetFactory;
032import org.opencms.ade.contenteditor.shared.CmsExternalWidgetConfiguration;
033import org.opencms.gwt.client.util.CmsDomUtil;
034
035import java.util.Collection;
036import java.util.HashMap;
037import java.util.HashSet;
038import java.util.Iterator;
039import java.util.List;
040import java.util.Map;
041import java.util.Set;
042
043import com.google.gwt.core.client.Scheduler;
044import com.google.gwt.core.client.Scheduler.RepeatingCommand;
045import com.google.gwt.user.client.Command;
046
047/**
048 * The widget registry.<p>
049 */
050public final class WidgetRegistry {
051
052    /** The register widget function name. */
053    public static final String REGISTER_WIDGET_FACTORY_FUNCTION = "registerWidgetFactory";
054
055    /** The widget registry instance. */
056    private static WidgetRegistry INSTANCE;
057
058    /** Map of registered renderers by name. */
059    private Map<String, I_CmsEntityRenderer> m_renderers = new HashMap<String, I_CmsEntityRenderer>();
060
061    /** The widget registry. */
062    private Map<String, I_CmsWidgetFactory> m_widgetRegistry;
063
064    /**
065     * Constructor.<p>
066     */
067    private WidgetRegistry() {
068
069        m_widgetRegistry = new HashMap<String, I_CmsWidgetFactory>();
070        exportWidgetRegistration();
071    }
072
073    /**
074     * Returns the widget registry instance.<p>
075     *
076     * @return the widget registry instance
077     */
078    public static WidgetRegistry getInstance() {
079
080        if (INSTANCE == null) {
081            INSTANCE = new WidgetRegistry();
082        }
083        return INSTANCE;
084    }
085
086    /**
087     * Adds a renderer which should be used by the Acacia editor.<p>
088     *
089     * @param renderer the renderer to add
090     */
091    public void addRenderer(I_CmsEntityRenderer renderer) {
092
093        m_renderers.put(renderer.getName(), renderer);
094    }
095
096    /**
097     * Returns the registered renderers.<p>
098     *
099     * @return the renderers
100     */
101    public Collection<I_CmsEntityRenderer> getRenderers() {
102
103        return m_renderers.values();
104    }
105
106    /**
107     * Returns the registered widget factories.<p>
108     *
109     * @return the registered widget factories
110     */
111    public Map<String, I_CmsWidgetFactory> getWidgetFactories() {
112
113        return m_widgetRegistry;
114    }
115
116    /**
117     * Registers external widgets.<p>
118     *
119     * @param externalWidgetConfigurations the external widget configurations
120     * @param callback the callback to execute when done
121     */
122    public void registerExternalWidgets(
123        List<CmsExternalWidgetConfiguration> externalWidgetConfigurations,
124        final Command callback) {
125
126        final Set<String> initCalls = new HashSet<String>();
127        for (CmsExternalWidgetConfiguration widgetConfiguration : externalWidgetConfigurations) {
128            if (!m_widgetRegistry.containsKey(widgetConfiguration.getWidgetName())) {
129                for (String cssResource : widgetConfiguration.getCssResourceLinks()) {
130                    CmsDomUtil.ensureStyleSheetIncluded(cssResource);
131                }
132                for (String javaScriptResource : widgetConfiguration.getJavaScriptResourceLinks()) {
133                    CmsDomUtil.ensureJavaScriptIncluded(javaScriptResource);
134                }
135                String initCall = widgetConfiguration.getInitCall();
136                if (initCall != null) {
137                    initCalls.add(initCall);
138                }
139            }
140        }
141        if (initCalls.isEmpty()) {
142            callback.execute();
143        } else {
144            Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
145
146                /** The number of repeats. */
147                private int m_repeats;
148
149                /**
150                 * @see com.google.gwt.core.client.Scheduler.RepeatingCommand#execute()
151                 */
152                public boolean execute() {
153
154                    m_repeats++;
155                    Iterator<String> it = initCalls.iterator();
156                    while (it.hasNext()) {
157                        String initCall = it.next();
158                        if (tryInitCall(initCall)) {
159                            it.remove();
160                        }
161                    }
162                    if (initCalls.isEmpty()) {
163                        callback.execute();
164                        return false;
165                    } else {
166                        if (m_repeats < 100) {
167                            return true;
168                        } else {
169                            showInitCallError(initCalls);
170                            return false;
171                        }
172                    }
173
174                }
175            }, 50);
176        }
177    }
178
179    /**
180     * Registers a widget.<p>
181     *
182     * @param widgetName the widget name
183     * @param widgetFactory the widget
184     */
185    public void registerWidgetFactory(String widgetName, I_CmsWidgetFactory widgetFactory) {
186
187        m_widgetRegistry.put(widgetName, widgetFactory);
188    }
189
190    /**
191     * Logs an error.<p>
192     *
193     * @param error the error to log
194     */
195    protected native void showError(String error) /*-{
196                                                  if ($wnd.console) {
197                                                  $wnd.console.log(error);
198                                                  }
199                                                  throw error;
200                                                  }-*/;
201
202    /**
203     * Logs an error for missing init calls.<p>
204     *
205     * @param initCalls the set of missing init calls
206     */
207    protected void showInitCallError(Set<String> initCalls) {
208
209        StringBuffer buffer = new StringBuffer();
210        buffer.append("init call(s) not found: ");
211        for (String init : initCalls) {
212            buffer.append(init);
213            buffer.append(" ");
214        }
215        showError(buffer.toString());
216    }
217
218    /**
219     * Tries to initializes a widget with the given initialization call. Returns false if the init method was not available within the window context yet.<p>
220     *
221     * @param initCall the initialization function name
222     *
223     * @return <code>true</code> if the initialization function was available and has been executed
224     */
225    protected native boolean tryInitCall(String initCall)/*-{
226                                                         try {
227                                                         if ($wnd[initCall]) {
228                                                         $wnd[initCall]();
229                                                         return true;
230                                                         }
231                                                         } catch (error) {
232                                                         throw "Failed excuting " + initCall
233                                                         + " to initialize editing widget. \n" + error
234                                                         }
235                                                         return false;
236                                                         }-*/;
237
238    /**
239     * Exports the widget registration.<p>
240     */
241    private native void exportWidgetRegistration() /*-{
242                                                   var self = this;
243                                                   $wnd[@org.opencms.ade.contenteditor.widgetregistry.client.WidgetRegistry::REGISTER_WIDGET_FACTORY_FUNCTION] = function(
244                                                   factory) {
245                                                   self.@org.opencms.ade.contenteditor.widgetregistry.client.WidgetRegistry::registerWrapper(Lorg/opencms/ade/contenteditor/widgetregistry/client/WidgetFactoryWrapper;)(factory);
246                                                   }
247                                                   }-*/;
248
249    /**
250     * Registers a widget wrapper as widget.<p>
251     *
252     * @param wrapper the wrapper object
253     */
254    private void registerWrapper(WidgetFactoryWrapper wrapper) {
255
256        registerWidgetFactory(wrapper.getName(), wrapper);
257    }
258}