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.I_CmsDescendantResizeHandler;
031import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
032import org.opencms.gwt.client.util.CmsDebugLog;
033import org.opencms.gwt.client.util.CmsFocusedScrollingHandler;
034
035import com.google.gwt.dom.client.Element;
036import com.google.gwt.dom.client.Style.Unit;
037import com.google.gwt.event.dom.client.MouseDownEvent;
038import com.google.gwt.event.dom.client.MouseDownHandler;
039import com.google.gwt.event.dom.client.ScrollEvent;
040import com.google.gwt.event.dom.client.ScrollHandler;
041import com.google.gwt.event.logical.shared.HasResizeHandlers;
042import com.google.gwt.event.logical.shared.ResizeEvent;
043import com.google.gwt.event.logical.shared.ResizeHandler;
044import com.google.gwt.event.shared.HandlerRegistration;
045import com.google.gwt.user.client.DOM;
046import com.google.gwt.user.client.Event;
047import com.google.gwt.user.client.Event.NativePreviewEvent;
048import com.google.gwt.user.client.Event.NativePreviewHandler;
049import com.google.gwt.user.client.ui.ScrollPanel;
050import com.google.gwt.user.client.ui.Widget;
051
052/**
053 * Scroll panel implementation allowing focused scrolling.<p>
054 */
055public class CmsScrollPanel extends ScrollPanel implements HasResizeHandlers, I_CmsDescendantResizeHandler {
056
057    /**Inner class for the resize button. */
058    protected class ResizeButton extends CmsPushButton {
059
060        /**
061         * Default constructor.<p>
062         */
063        public ResizeButton() {
064
065            super();
066            setStyleName(I_CmsLayoutBundle.INSTANCE.buttonCss().resizeButton());
067
068        }
069
070        /**
071         * @see com.google.gwt.user.client.ui.CustomButton#onAttach()
072         */
073        @Override
074        protected void onAttach() {
075
076            super.onAttach();
077        }
078
079        /**
080         * @see com.google.gwt.user.client.ui.CustomButton#onDetach()
081         */
082        @Override
083        protected void onDetach() {
084
085            super.onDetach();
086        }
087    }
088
089    /**
090     * Drag and drop event preview handler.<p>
091     *
092     * To be used while dragging.<p>
093     */
094    protected class ResizeEventPreviewHandler implements NativePreviewHandler {
095
096        /**
097         * @see com.google.gwt.user.client.Event.NativePreviewHandler#onPreviewNativeEvent(com.google.gwt.user.client.Event.NativePreviewEvent)
098         */
099        public void onPreviewNativeEvent(NativePreviewEvent event) {
100
101            Event nativeEvent = Event.as(event.getNativeEvent());
102            switch (DOM.eventGetType(nativeEvent)) {
103                case Event.ONMOUSEMOVE:
104                    // dragging
105                    setNewHeight(nativeEvent);
106                    onResizeDescendant();
107                    event.cancel();
108                    break;
109                case Event.ONMOUSEUP:
110                    m_previewHandlerRegistration.removeHandler();
111                    m_previewHandlerRegistration = null;
112                    break;
113                case Event.ONKEYDOWN:
114                    break;
115                case Event.ONMOUSEWHEEL:
116                    //onMouseWheelScroll(nativeEvent);
117                    break;
118                default:
119                    // do nothing
120            }
121
122            nativeEvent.preventDefault();
123            nativeEvent.stopPropagation();
124
125        }
126
127    }
128
129    /** The preview handler registration. */
130    protected HandlerRegistration m_previewHandlerRegistration;
131
132    /** The start Y coordination. */
133    private int m_clientY;
134
135    /** The default height. */
136    private double m_defaultHeight = -1;
137
138    /** The prevent outer scrolling handler. */
139    private CmsFocusedScrollingHandler m_focusedScrollingHandler;
140
141    /** The scroll handler registration. */
142    private HandlerRegistration m_handlerRegistration;
143
144    /** Saves if the scrolling panel has the resize button. */
145    private boolean m_isResize;
146
147    /** The start height. */
148    private double m_oldheight;
149
150    /** The button to resize the scrolling panel. */
151    private ResizeButton m_resize;
152
153    /**
154     * Constructor.<p>
155     *
156     * @see com.google.gwt.user.client.ui.ScrollPanel#ScrollPanel()
157     */
158    public CmsScrollPanel() {
159
160        m_resize = new ResizeButton();
161
162    }
163
164    /**
165     * Constructor to be used by {@link org.opencms.gwt.client.ui.CmsScrollPanelImpl}.<p>
166     *
167     * @param root the root element of the widget
168     * @param scrollabel the scrollable element of the widget
169     * @param container the container element of the widget
170     */
171    protected CmsScrollPanel(Element root, Element scrollabel, Element container) {
172
173        super(root, scrollabel, container);
174        m_resize = new ResizeButton();
175
176    }
177
178    /**
179     * @see com.google.gwt.event.logical.shared.HasResizeHandlers#addResizeHandler(com.google.gwt.event.logical.shared.ResizeHandler)
180     */
181    public HandlerRegistration addResizeHandler(ResizeHandler handler) {
182
183        return addHandler(handler, ResizeEvent.getType());
184    }
185
186    /**
187     * Enables or disables the focused scrolling feature.<p>
188     * Focused scrolling is enabled by default.<p>
189     *
190     * @param enable <code>true</code> to enable the focused scrolling feature
191     */
192    public void enableFocusedScrolling(boolean enable) {
193
194        if (enable) {
195            if (m_handlerRegistration == null) {
196                m_handlerRegistration = addScrollHandler(new ScrollHandler() {
197
198                    public void onScroll(ScrollEvent event) {
199
200                        ensureFocusedScrolling();
201                    }
202                });
203            }
204        } else if (m_handlerRegistration != null) {
205            m_handlerRegistration.removeHandler();
206            m_handlerRegistration = null;
207        }
208    }
209
210    /**
211     * @see org.opencms.gwt.client.I_CmsDescendantResizeHandler#onResizeDescendant()
212     */
213    public void onResizeDescendant() {
214
215        // not needed
216    }
217
218    /**
219     * @see com.google.gwt.user.client.ui.SimplePanel#remove(com.google.gwt.user.client.ui.Widget)
220     */
221    @Override
222    public boolean remove(Widget w) {
223
224        if (w == m_resize) {
225            try {
226                orphan(m_resize);
227            } finally {
228                getElement().removeChild(m_resize.getElement());
229            }
230            return true;
231        } else {
232            return super.remove(w);
233        }
234    }
235
236    /**
237     * Sets the default height of the scrolling panel.
238     *
239     * @param height the default height
240     */
241    public void setDefaultHeight(double height) {
242
243        m_defaultHeight = height;
244    }
245
246    /**
247     * Sets the scrollpanel resizeable.<p>
248     *
249     * @param resize true if the scrollpanel should be resizeable.
250     */
251    public void setResizable(boolean resize) {
252
253        if (resize != m_isResize) {
254            if (resize) {
255                getElement().appendChild(m_resize.getElement());
256                adopt(m_resize);
257                m_resize.addMouseDownHandler(new MouseDownHandler() {
258
259                    public void onMouseDown(MouseDownEvent event) {
260
261                        setStartParameters(event);
262                        CmsDebugLog.getInstance().printLine("Registering preview handler");
263                        if (m_previewHandlerRegistration != null) {
264                            m_previewHandlerRegistration.removeHandler();
265                        }
266                        m_previewHandlerRegistration = Event.addNativePreviewHandler(new ResizeEventPreviewHandler());
267                    }
268                });
269            } else {
270                m_resize.removeFromParent();
271            }
272            m_isResize = resize;
273        }
274    }
275
276    /**
277     * Ensures the focused scrolling event preview handler is registered.<p>
278     */
279    protected void ensureFocusedScrolling() {
280
281        if (m_focusedScrollingHandler == null) {
282            m_focusedScrollingHandler = CmsFocusedScrollingHandler.installFocusedScrollingHandler(this);
283        } else if (!m_focusedScrollingHandler.isRegistered()) {
284            m_focusedScrollingHandler.register();
285        }
286    }
287
288    /**
289     * @see com.google.gwt.user.client.ui.ScrollPanel#onAttach()
290     */
291    @Override
292    protected void onAttach() {
293
294        super.onAttach();
295        if (m_isResize) {
296            m_resize.onAttach();
297        }
298
299    }
300
301    /**
302     * @see com.google.gwt.user.client.ui.ScrollPanel#onDetach()
303     */
304    @Override
305    protected void onDetach() {
306
307        super.onDetach();
308        if (m_isResize) {
309            m_resize.onDetach();
310        }
311    }
312
313    /**
314     * Executed on mouse move while dragging.<p>
315     *
316     * @param event the event
317     */
318    protected void setNewHeight(Event event) {
319
320        double newheight = m_oldheight + (event.getClientY() - m_clientY);
321        if (m_defaultHeight != -1) {
322            if (newheight < m_defaultHeight) {
323                newheight = m_defaultHeight;
324            }
325        }
326        ResizeEvent.fire(this, getOffsetWidth(), (int)newheight);
327        getElement().getStyle().setHeight(newheight, Unit.PX);
328    }
329
330    /**
331     * Sets the start parameters of the resize event.<p>
332     *
333     * @param event the mouse event
334     */
335    protected void setStartParameters(MouseDownEvent event) {
336
337        m_oldheight = Double.parseDouble(getElement().getStyle().getHeight().replace("px", ""));
338        m_clientY = event.getClientY();
339    }
340
341}