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.gwt.client.ui;
029
030import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
031import org.opencms.gwt.client.util.CmsDomUtil;
032import org.opencms.gwt.client.util.CmsDomUtil.Method;
033
034import java.util.Map;
035
036import com.google.gwt.core.client.Scheduler;
037import com.google.gwt.core.client.Scheduler.ScheduledCommand;
038import com.google.gwt.dom.client.FormElement;
039import com.google.gwt.dom.client.Style.Unit;
040import com.google.gwt.event.logical.shared.CloseEvent;
041import com.google.gwt.event.logical.shared.CloseHandler;
042import com.google.gwt.user.client.ui.FlowPanel;
043import com.google.gwt.user.client.ui.PopupPanel;
044import com.google.gwt.user.client.ui.RootPanel;
045import com.google.gwt.user.client.ui.SimplePanel;
046import com.google.gwt.user.client.ui.Widget;
047
048/**
049 * Frame dialog utility class.<p>
050 *
051 * Use to render the dialog content within an iFrame on top of a regular {@link org.opencms.gwt.client.ui.CmsPopup}.
052 * May also be used to wrap the popup if no iFrame is needed.<p>
053 *
054 * Provides function to show an iFrame dialog.<p>
055 *
056 * @since 8.5
057 */
058public class CmsFrameDialog {
059
060    /** The name of the close function. */
061    public static final String CLOSE_FUNCTION = "cmsDialogClose";
062
063    /** The dialog height. */
064    public static final int DIALOG_HEIGHT = 300;
065
066    /** The dialog width. */
067    public static final int DIALOG_WIDTH = 200;
068
069    /** The name of the enable dialog close function. */
070    public static final String ENABLE_CLOSE_FUNCTION = "cmsEnableDialogClose";
071
072    /** The name of the dialog height function. */
073    public static final String HEIGHT_FUNCTION = "cmsDialogHeight";
074
075    /** The name of the IFrame used for displaying the upload hook page. */
076    public static final String IFRAME_NAME = "upload_hook";
077
078    /** The name of the dialog title function. */
079    public static final String TITLE_FUNCTION = "cmsDialogTitle";
080
081    /** The name of the dialog width function. */
082    public static final String WIDTH_FUNCTION = "cmsUploadHookDialogWidth";
083
084    /** The button panel. */
085    private FlowPanel m_buttonPanel;
086
087    /** The content widget. */
088    private Widget m_content;
089
090    /** The panel holding the content widget. */
091    private SimplePanel m_contentPanel;
092
093    /** Flag indicating if this dialog is displayed within an iFrame on top of a popup. */
094    private boolean m_isFrame;
095
096    /** Flag indicating that the dialog is showing.< */
097    private boolean m_isShowing;
098
099    /** The main panel. */
100    private FlowPanel m_main;
101
102    /** The popup. */
103    private CmsPopup m_popup;
104
105    /**
106     * Constructor.<p>
107     */
108    public CmsFrameDialog() {
109
110        m_isFrame = hasParentFrame();
111        if (m_isFrame) {
112            m_main = new FlowPanel();
113            m_main.addStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().frameDialog());
114            m_contentPanel = new SimplePanel();
115            m_contentPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().popupMainContent());
116            m_contentPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().contentPadding());
117            m_main.add(m_contentPanel);
118
119        } else {
120            m_popup = new CmsPopup();
121            m_popup.setGlassEnabled(true);
122        }
123    }
124
125    /**
126     * Returns if this dialog has a parent frame.<p>
127     *
128     * @return <code>true</code> if the parent frame is available
129     */
130    public static native boolean hasParentFrame() /*-{
131                                                  if ($wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::CLOSE_FUNCTION]) {
132                                                  return true;
133                                                  }
134                                                  return false;
135
136                                                  }-*/;
137
138    /**
139     * Shows an iFrame dialog popup.<p>
140     *
141     * @param title the dialog title
142     * @param dialogUri the dialog URI
143     * @param parameters the dialog post parameters
144     * @param closeHandler the dialog close handler
145     *
146     * @return the opened popup
147     */
148    public static CmsPopup showFrameDialog(
149        String title,
150        String dialogUri,
151        Map<String, String> parameters,
152        CloseHandler<PopupPanel> closeHandler) {
153
154        CmsPopup popup = new CmsPopup(title);
155        popup.removePadding();
156        popup.addStyleName(I_CmsLayoutBundle.INSTANCE.contentEditorCss().contentEditor());
157        popup.setGlassEnabled(true);
158        CmsIFrame editorFrame = new CmsIFrame(IFRAME_NAME, "");
159        popup.add(editorFrame);
160        final FormElement formElement = CmsDomUtil.generateHiddenForm(dialogUri, Method.post, IFRAME_NAME, parameters);
161        RootPanel.getBodyElement().appendChild(formElement);
162        exportDialogFunctions(popup);
163        popup.addCloseHandler(new CloseHandler<PopupPanel>() {
164
165            public void onClose(CloseEvent<PopupPanel> event) {
166
167                formElement.removeFromParent();
168                removeExportedFunctions();
169            }
170        });
171        if (closeHandler != null) {
172            popup.addCloseHandler(closeHandler);
173        }
174        popup.center();
175        formElement.submit();
176        return popup;
177    }
178
179    /**
180     * Removes exported functions from the window context.<p>
181     */
182    protected static native void removeExportedFunctions() /*-{
183                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::CLOSE_FUNCTION] = null;
184                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::HEIGHT_FUNCTION] = null;
185                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::WIDTH_FUNCTION] = null;
186                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::TITLE_FUNCTION] = null;
187                                                           }-*/;
188
189    /**
190     * Installs the Javascript function which should be called by the child iframe when the dialog should be closed.<p>
191     *
192     * @param popup the popup
193     */
194    private static native void exportDialogFunctions(final CmsPopup popup) /*-{
195                                                                           var self = this;
196                                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::CLOSE_FUNCTION] = function() {
197                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::hide()();
198                                                                           };
199                                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::HEIGHT_FUNCTION] = function(
200                                                                           height) {
201                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::setHeight(I)(height);
202                                                                           if (popup.@org.opencms.gwt.client.ui.CmsPopup::isShowing()) {
203                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::center()();
204                                                                           }
205                                                                           };
206                                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::WIDTH_FUNCTION] = function(
207                                                                           width) {
208                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::setWidth(I)(width);
209                                                                           if (popup.@org.opencms.gwt.client.ui.CmsPopup::isShowing()) {
210                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::center()();
211                                                                           }
212                                                                           };
213                                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::TITLE_FUNCTION] = function(
214                                                                           title) {
215                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::setCaption(Ljava/lang/String;)(title);
216                                                                           };
217                                                                           $wnd[@org.opencms.gwt.client.ui.CmsFrameDialog::ENABLE_CLOSE_FUNCTION] = function(
218                                                                           title) {
219                                                                           popup.@org.opencms.gwt.client.ui.CmsPopup::addDialogClose(Lcom/google/gwt/user/client/Command;)(null);
220                                                                           };
221                                                                           }-*/;
222
223    /**
224     * Adds a new button to the button bar.<p>
225     *
226     * @param button the button to add
227     */
228    public void addButton(Widget button) {
229
230        if (m_isFrame) {
231            initButtonPanel();
232            m_buttonPanel.insert(button, 0);
233        } else {
234            m_popup.addButton(button);
235        }
236    }
237
238    /**
239     * Adds a new button to the button bar at the specified index position.<p>
240     *
241     * @param button the button to add
242     * @param index the index position
243     */
244    public void addButton(Widget button, int index) {
245
246        if (m_isFrame) {
247            initButtonPanel();
248            m_buttonPanel.insert(button, index);
249        } else {
250            m_popup.addButton(button, index);
251        }
252    }
253
254    /**
255     * Enables the dialog close button on the popup.<p>
256     */
257    public void enableDialogClose() {
258
259        if (m_isFrame) {
260            enableParentDialogClose();
261        } else {
262            m_popup.addDialogClose(null);
263        }
264    }
265
266    /**
267     * Hides the dialog.<p>
268     */
269    public void hide() {
270
271        if (m_isFrame) {
272            hideParent();
273        } else {
274            m_popup.hide();
275        }
276    }
277
278    /**
279     * Returns if the popup is showing and the content is rendered.<p>
280     *
281     * @return <code>true</code> if the popup and content are showing
282     */
283    public boolean isShowing() {
284
285        if (m_isFrame) {
286            return m_isShowing;
287        } else {
288            return m_popup.isShowing();
289        }
290    }
291
292    /**
293     * Removes the given button from the button bar.<p>
294     *
295     * @param button the button to remove
296     */
297    public void removeButton(Widget button) {
298
299        if (m_isFrame) {
300            if (m_buttonPanel != null) {
301                m_buttonPanel.remove(button);
302            }
303        } else {
304            m_popup.removeButton(button);
305        }
306    }
307
308    /**
309     * Sets the content widget.<p>
310     *
311     * @param content the content widget
312     */
313    public void setContent(Widget content) {
314
315        if (m_content != null) {
316            m_content.removeFromParent();
317        }
318        if (m_isFrame) {
319            m_contentPanel.setWidget(content);
320        } else {
321            m_popup.setMainContent(content);
322        }
323        m_content = content;
324    }
325
326    /**
327     * Sets the popup height.<p>
328     *
329     * @param height the height
330     */
331    public void setHeight(int height) {
332
333        if (m_isFrame) {
334            setParentHeight(height);
335        } else {
336            m_popup.setHeight(height);
337            if (m_popup.isShowing()) {
338                m_popup.center();
339            }
340        }
341    }
342
343    /**
344     * Sets the dialog title.<p>
345     *
346     * @param title the title
347     */
348    public void setTitle(String title) {
349
350        if (m_isFrame) {
351            setParentTitle(title);
352        } else {
353            m_popup.setCaption(title);
354        }
355    }
356
357    /**
358     * Sets the popup width.<p>
359     *
360     * @param width the width
361     */
362    public void setWidth(int width) {
363
364        if (m_isFrame) {
365            setParentWidth(width);
366        } else {
367            m_popup.setWidth(width);
368            if (m_popup.isShowing()) {
369                m_popup.center();
370            }
371        }
372    }
373
374    /**
375     * Shows the dialog.<p>
376     */
377    public void show() {
378
379        if (m_isFrame) {
380            RootPanel root = RootPanel.get();
381            root.getElement().getStyle().setMargin(0, Unit.PX);
382            root.getElement().getStyle().setPadding(0, Unit.PX);
383            RootPanel.get().add(m_main);
384            m_isShowing = true;
385            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
386
387                public void execute() {
388
389                    adjustContentSize();
390                }
391            });
392        } else {
393            m_popup.center();
394        }
395
396    }
397
398    /**
399     * Adjusts the content panel size according to the button panel height.<p>
400     */
401    protected void adjustContentSize() {
402
403        if (m_isFrame && m_isShowing) {
404            if (m_buttonPanel != null) {
405                m_contentPanel.getElement().getStyle().setBottom(m_buttonPanel.getOffsetHeight() + 6, Unit.PX);
406            } else {
407                m_contentPanel.getElement().getStyle().clearBottom();
408            }
409        }
410    }
411
412    /**
413     * Enables the dialog close button on the parent frame popup.<p>
414     */
415    private native void enableParentDialogClose() /*-{
416                                                  $wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::ENABLE_CLOSE_FUNCTION]
417                                                  ();
418                                                  }-*/;
419
420    /**
421     * Hides the parent dialog.<p>
422     */
423    private native void hideParent() /*-{
424                                     $wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::CLOSE_FUNCTION]();
425                                     }-*/;
426
427    /**
428     * Initializes the button panel within frame mode.<p>
429     */
430    private void initButtonPanel() {
431
432        if ((m_buttonPanel == null) && m_isFrame) {
433            m_buttonPanel = new FlowPanel();
434            m_buttonPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.dialogCss().popupButtonPanel());
435            m_main.add(m_buttonPanel);
436        }
437    }
438
439    /**
440     * Sets the parent dialog height.<p>
441     *
442     * @param height the height to set
443     */
444    private native void setParentHeight(int height) /*-{
445                                                    $wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::HEIGHT_FUNCTION]
446                                                    (height);
447                                                    }-*/;
448
449    /**
450     * Sets the title of the parent dialog.<p>
451     *
452     * @param title the title
453     */
454    private native void setParentTitle(String title) /*-{
455                                                     $wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::TITLE_FUNCTION]
456                                                     (title);
457                                                     }-*/;
458
459    /**
460     * Sets the parent dialog width.<p>
461     *
462     * @param width the width to set
463     */
464    private native void setParentWidth(int width) /*-{
465                                                  $wnd.parent[@org.opencms.gwt.client.ui.CmsFrameDialog::WIDTH_FUNCTION]
466                                                  (width);
467                                                  }-*/;
468}