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.gwt.client.ui;
029
030import org.opencms.ade.galleries.client.ui.CmsGalleryDialog;
031import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
032import org.opencms.gwt.client.util.CmsPositionBean;
033
034import com.google.gwt.dom.client.Element;
035import com.google.gwt.dom.client.Style.Unit;
036import com.google.gwt.user.client.DOM;
037import com.google.gwt.user.client.Window;
038import com.google.gwt.user.client.ui.ButtonBase;
039
040/**
041 * A popup which can be displayed below buttons in a toolbar.
042 */
043public class CmsToolbarPopup extends CmsPopup {
044
045    /** The minimum distance of the popup to the window border. */
046    private static final int MIN_MARGIN = 8;
047
048    /** The 'arrow-shaped' connector element above the popup. */
049    protected Element m_arrow = DOM.createDiv();
050
051    /** The toolbar button to which this popup belongs. */
052    protected ButtonBase m_button;
053
054    /** The toolbar width. */
055    protected int m_toolbarWidth;
056
057    /** The 'toolbar mode' flag. */
058    protected boolean m_isToolbarMode;
059
060    /** The base element of the toolbar button. */
061    protected Element m_baseElement;
062
063    /**
064     * Creates a new toolbar popup.<p>
065     *
066     * @param button the toolbar button to which this popup belongs
067     * @param toolbarMode the toolbar mode flag
068     * @param baseElement the base element of the toolbar button
069     */
070    public CmsToolbarPopup(ButtonBase button, boolean toolbarMode, Element baseElement) {
071
072        super();
073        m_button = button;
074        m_baseElement = baseElement;
075        m_isToolbarMode = toolbarMode;
076        setModal(false);
077        setAutoHideEnabled(true);
078        setWidth(DEFAULT_WIDTH);
079        removePadding();
080    }
081
082    /**
083     * Calculates the popup height to use.<p>
084     *
085     * @return the height
086     */
087    public static int getAvailableHeight() {
088
089        int height = CmsGalleryDialog.DEFAULT_DIALOG_HEIGHT;
090        if (Window.getClientHeight() > 590) {
091            height = (int)Math.ceil((Window.getClientHeight() - 50) * 0.9);
092        }
093        return height;
094    }
095
096    /**
097     * Calculates the popup width to use.<p>
098     *
099     * @return the width
100     */
101    public static int getAvailableWidth() {
102
103        int width = CmsGalleryDialog.DEFAULT_DIALOG_WIDTH;
104        if (Window.getClientWidth() > 1100) {
105            width = 1000;
106        }
107        return width;
108    }
109
110    /**
111     * Positions the popup below the toolbar button.<p>
112     */
113    public void position() {
114
115        // get the window client width
116        int windowWidth = Window.getClientWidth();
117        // get the min left position
118        int minLeft = MIN_MARGIN;
119
120        // get the max right position
121        int maxRight = windowWidth - MIN_MARGIN;
122        // get the middle button position
123        CmsPositionBean buttonPosition = CmsPositionBean.generatePositionInfo(m_button.getElement());
124        int buttonMiddle = (buttonPosition.getLeft() - Window.getScrollLeft()) + (buttonPosition.getWidth() / 2);
125        // get the content width
126        int contentWidth = getOffsetWidth();
127
128        // the optimum left position is in the middle of the button minus the half content width
129        // assume that the optimum fits into the space
130        int contentLeft = buttonMiddle - (contentWidth / 2);
131
132        if (minLeft > contentLeft) {
133            // if the optimum left position of the popup is outside the min left position:
134            // move the popup to the right (take the min left position as left)
135            contentLeft = minLeft;
136        } else if ((contentLeft + contentWidth) > maxRight) {
137            // if the left position plus the content width is outside the max right position:
138            // move the popup to the left (take the max right position minus the content width)
139            contentLeft = maxRight - contentWidth;
140        }
141
142        // limit the right position if the popup is right outside the window
143        if ((contentLeft + contentWidth + MIN_MARGIN) > windowWidth) {
144            contentLeft = windowWidth - contentWidth - MIN_MARGIN;
145        }
146
147        // limit the left position if the popup is left outside the window
148        if (contentLeft < MIN_MARGIN) {
149            contentLeft = MIN_MARGIN;
150        }
151
152        int arrowSpace = 10;
153        int arrowWidth = 40;
154        int arrowHeight = 12;
155
156        // the optimum position for the arrow is in the middle of the button
157        int arrowLeft = buttonMiddle - contentLeft - (arrowWidth / 2);
158        if ((arrowLeft + arrowWidth + arrowSpace) > contentWidth) {
159            // limit the arrow position if the maximum is reached (content width 'minus x')
160            arrowLeft = contentWidth - arrowWidth - arrowSpace;
161        } else if ((arrowLeft - arrowSpace) < 0) {
162            // limit the arrow position if the minimum is reached ('plus x')
163            arrowLeft = arrowWidth + arrowSpace;
164        }
165
166        int arrowTop = -(arrowHeight - 2);
167        String arrowClass = I_CmsLayoutBundle.INSTANCE.dialogCss().menuArrowTop();
168
169        int contentTop = (((buttonPosition.getTop() + buttonPosition.getHeight()) - Window.getScrollTop())
170            + arrowHeight) - 2;
171        if (!m_isToolbarMode) {
172            contentTop = (buttonPosition.getTop() + buttonPosition.getHeight() + arrowHeight) - 2;
173            int contentHeight = getOffsetHeight();
174            int windowHeight = Window.getClientHeight();
175
176            if (((contentHeight + MIN_MARGIN) < windowHeight)
177                && ((buttonPosition.getTop() - Window.getScrollTop()) > contentHeight)
178                && (((contentHeight + MIN_MARGIN + contentTop) - Window.getScrollTop()) > windowHeight)) {
179                // content fits into the window height,
180                // there is enough space above the button
181                // and there is to little space below the button
182                // so show above
183                contentTop = ((buttonPosition.getTop() - arrowHeight) + 2) - contentHeight;
184                arrowTop = contentHeight - 1;
185                arrowClass = I_CmsLayoutBundle.INSTANCE.dialogCss().menuArrowBottom();
186            }
187        } else {
188            contentLeft = contentLeft - Window.getScrollLeft();
189            setPositionFixed();
190        }
191
192        m_arrow.setClassName(arrowClass);
193        m_arrow.getStyle().setLeft(arrowLeft, Unit.PX);
194        m_arrow.getStyle().setTop(arrowTop, Unit.PX);
195
196        showArrow(m_arrow);
197        setPopupPosition(contentLeft + Window.getScrollLeft(), contentTop);
198    }
199
200    /**
201     * Sets the isToolbarMode.<p>
202     *
203     * @param isToolbarMode the isToolbarMode to set
204     */
205    public void setToolbarMode(boolean isToolbarMode) {
206
207        m_isToolbarMode = isToolbarMode;
208        if (m_isToolbarMode) {
209            // important, so a click on the button won't trigger the auto-close
210            addAutoHidePartner(m_baseElement);
211        } else {
212            removeAutoHidePartner(m_baseElement);
213        }
214    }
215}