javauis/eswt_qt/org.eclipse.swt/Eclipse SWT/qt/org/eclipse/swt/widgets/Scrollable.java
changeset 21 2a9601315dfc
child 35 85266cc22c7f
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*******************************************************************************
       
     2  * Copyright (c) 2000, 2007 IBM Corporation and others.
       
     3  * Portion Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     4  * All rights reserved. This program and the accompanying materials
       
     5  * are made available under the terms of the Eclipse Public License v1.0
       
     6  * which accompanies this distribution, and is available at
       
     7  * http://www.eclipse.org/legal/epl-v10.html
       
     8  *
       
     9  * Contributors:
       
    10  *     IBM Corporation - initial API and implementation
       
    11  *     Nokia Corporation - Qt implementation
       
    12  *******************************************************************************/
       
    13 package org.eclipse.swt.widgets;
       
    14 
       
    15 import org.eclipse.swt.SWT;
       
    16 import org.eclipse.swt.graphics.Point;
       
    17 import org.eclipse.swt.graphics.Rectangle;
       
    18 import org.eclipse.swt.internal.qt.OS;
       
    19 import org.eclipse.swt.internal.qt.WidgetConstant;
       
    20 import org.eclipse.swt.internal.qt.WidgetState;
       
    21 
       
    22 /**
       
    23  * This class is the abstract superclass of all classes which represent controls
       
    24  * that have standard scroll bars.
       
    25  * <dl>
       
    26  * <dt><b>Styles:</b></dt>
       
    27  * <dd>H_SCROLL, V_SCROLL</dd>
       
    28  * <dt><b>Events:</b>
       
    29  * <dd>(none)</dd>
       
    30  * </dl>
       
    31  * <p>
       
    32  * IMPORTANT: This class is intended to be subclassed <em>only</em> within the
       
    33  * SWT implementation.
       
    34  * </p>
       
    35  */
       
    36 public abstract class Scrollable extends Control {
       
    37     ScrollBar horizontalBar;
       
    38     ScrollBar verticalBar;
       
    39 
       
    40     /*
       
    41      * Handle of the native object implementing QAbstractScrollArea for the
       
    42      * widget. May be 0 because not all Scrollable objects derive from
       
    43      * QAbstractScrollArea in native side.
       
    44      * Must be checked if this is valid before using!
       
    45      */
       
    46     int scrollAreaHandle;
       
    47 
       
    48     /**
       
    49      * Prevents uninitialized instances from being created outside the package.
       
    50      */
       
    51     Scrollable() {
       
    52     }
       
    53 
       
    54     /**
       
    55      * Constructs a new instance of this class given its parent and a style
       
    56      * value describing its behavior and appearance.
       
    57      * <p>
       
    58      * The style value is either one of the style constants defined in class
       
    59      * <code>SWT</code> which is applicable to instances of this class, or must
       
    60      * be built by <em>bitwise OR</em>'ing together (that is, using the
       
    61      * <code>int</code> "|" operator) two or more of those <code>SWT</code>
       
    62      * style constants. The class description lists the style constants that are
       
    63      * applicable to the class. Style bits are also inherited from superclasses.
       
    64      * </p>
       
    65      * 
       
    66      * @param parent
       
    67      *            a composite control which will be the parent of the new
       
    68      *            instance (cannot be null)
       
    69      * @param style
       
    70      *            the style of control to construct
       
    71      * 
       
    72      * @exception IllegalArgumentException
       
    73      *                <ul>
       
    74      *                <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
       
    75      *                </ul>
       
    76      * @exception SWTException
       
    77      *                <ul>
       
    78      *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
       
    79      *                thread that created the parent</li>
       
    80      *                <li>ERROR_INVALID_SUBCLASS - if this class is not an
       
    81      *                allowed subclass</li>
       
    82      *                </ul>
       
    83      * 
       
    84      * @see SWT#H_SCROLL
       
    85      * @see SWT#V_SCROLL
       
    86      * @see Widget#checkSubclass
       
    87      * @see Widget#getStyle
       
    88      */
       
    89     public Scrollable(Composite parent, int style) {
       
    90         this(parent, style, 0, null, false);
       
    91     }
       
    92   
       
    93     /**
       
    94      * <p>
       
    95      * <b>IMPORTANT:</b> This constructor is <em>not</em> part of the SWT
       
    96      * public API. It should never be referenced from application code. 
       
    97      * </p>
       
    98      */
       
    99     protected Scrollable(Composite parent, int style, int extraStyle, Object packageProxy, 
       
   100             boolean isExtended) {
       
   101         super(parent, style, extraStyle, packageProxy, isExtended);
       
   102     }
       
   103 
       
   104     int clientHandle() {
       
   105         return handle;
       
   106     }
       
   107 
       
   108     public Point computeSize(int wHint, int hHint, boolean changed) {
       
   109         checkWidget();
       
   110 
       
   111         if (scrollAreaHandle == 0) {
       
   112             return super.computeSize(wHint, hHint, changed);
       
   113         }
       
   114 
       
   115         if (changed) {
       
   116             OS.QWidget_updateGeometry(topHandle);
       
   117         }
       
   118 
       
   119         Point preferredSize = (packageProxy != null ? 
       
   120                 packageProxy.getPreferredClientAreaSize() : getPreferredClientAreaSize_pp());
       
   121         Rectangle trim = computeTrim(0, 0, preferredSize.x, preferredSize.y);
       
   122         Point size = new Point(trim.width, trim.height);
       
   123 
       
   124         if (wHint != SWT.DEFAULT) {
       
   125             size.x = wHint + trim.width - preferredSize.x;
       
   126         }
       
   127         if (hHint != SWT.DEFAULT) {
       
   128             size.y = hHint + trim.height - preferredSize.y;
       
   129         }
       
   130 
       
   131         return size;
       
   132     }
       
   133 
       
   134     /**
       
   135      * Given a desired <em>client area</em> for the receiver (as described by
       
   136      * the arguments), returns the bounding rectangle which would be required to
       
   137      * produce that client area.
       
   138      * <p>
       
   139      * In other words, it returns a rectangle such that, if the receiver's
       
   140      * bounds were set to that rectangle, the area of the receiver which is
       
   141      * capable of displaying data (that is, not covered by the "trimmings")
       
   142      * would be the rectangle described by the arguments (relative to the
       
   143      * receiver's parent).
       
   144      * </p>
       
   145      * 
       
   146      * @param x
       
   147      *            the desired x coordinate of the client area
       
   148      * @param y
       
   149      *            the desired y coordinate of the client area
       
   150      * @param width
       
   151      *            the desired width of the client area
       
   152      * @param height
       
   153      *            the desired height of the client area
       
   154      * @return the required bounds to produce the given client area
       
   155      * 
       
   156      * @exception SWTException
       
   157      *                <ul>
       
   158      *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
       
   159      *                disposed</li>
       
   160      *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
       
   161      *                thread that created the receiver</li>
       
   162      *                </ul>
       
   163      * 
       
   164      * @see #getClientArea
       
   165      */
       
   166     public Rectangle computeTrim(int x, int y, int width, int height) {
       
   167         checkWidget();
       
   168         int border = getBorderWidth();
       
   169         x -= border;
       
   170         y -= border;
       
   171         width += 2 * border;
       
   172         height += 2 * border;
       
   173 
       
   174         ScrollBar vBar = getVerticalBar();
       
   175         if (vBar != null) {
       
   176                      int barWidth = vBar.getSize().x;
       
   177                      width += barWidth;
       
   178         }
       
   179 
       
   180         ScrollBar hBar = getHorizontalBar();
       
   181         if (hBar != null) {
       
   182             height += hBar.getSize().y;
       
   183         }
       
   184 
       
   185         return new Rectangle(x, y, width, height);
       
   186     }
       
   187     
       
   188 
       
   189     final ScrollBar createScrollBar(int style) {
       
   190         if ((style & SWT.H_SCROLL) != 0) {
       
   191             setHBarPolicy(true);
       
   192         } else {
       
   193             setVBarPolicy(true);
       
   194         }
       
   195         return new ScrollBar(this, style);
       
   196     }
       
   197 
       
   198     void createWidget(int index) {
       
   199         super.createWidget(index);
       
   200         // If topHandle wasn't set by a subclass
       
   201         if(topHandle == 0) {
       
   202             // If scrollAreaHandle was set by a subclass then use that as the
       
   203             // topHandle by default
       
   204             if(scrollAreaHandle != 0) {
       
   205                 topHandle = scrollAreaHandle;
       
   206             }
       
   207         }
       
   208         // Same for frameHandle
       
   209         if(frameHandle == 0) {
       
   210             if(scrollAreaHandle != 0) {
       
   211                 frameHandle = scrollAreaHandle;
       
   212             }            
       
   213         }
       
   214         createBars();
       
   215     }
       
   216 
       
   217     private void createBars() {
       
   218         if (scrollAreaHandle != 0) {
       
   219             if (((style & SWT.H_SCROLL) != 0) && (state & WidgetState.EMBEDDED_SCROLLBARS) == 0) {
       
   220                 if (horizontalBar == null) {
       
   221                     horizontalBar = createScrollBar(SWT.H_SCROLL);
       
   222                 }
       
   223             } else {
       
   224                 setHBarPolicy(false);
       
   225             }
       
   226 
       
   227             if (((style & SWT.V_SCROLL) != 0) && (state & WidgetState.EMBEDDED_SCROLLBARS) == 0) {
       
   228                 if (verticalBar == null) {
       
   229                     verticalBar = createScrollBar(SWT.V_SCROLL);
       
   230                 }
       
   231             } else {
       
   232                 setVBarPolicy(false);
       
   233             }
       
   234         }
       
   235     }
       
   236 
       
   237     /**
       
   238      * Returns a rectangle which describes the area of the receiver which is
       
   239      * capable of displaying data (that is, not covered by the "trimmings").
       
   240      * 
       
   241      * @return the client area
       
   242      * 
       
   243      * @exception SWTException
       
   244      *                <ul>
       
   245      *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
       
   246      *                disposed</li>
       
   247      *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
       
   248      *                thread that created the receiver</li>
       
   249      *                </ul>
       
   250      * 
       
   251      * @see #computeTrim
       
   252      */
       
   253     public Rectangle getClientArea() {
       
   254         checkWidget();
       
   255         if(!isVisible()) updateQLayouts();
       
   256 
       
   257         // QWidget::rect() always returns (0,0) as top left. 
       
   258         // It is ok to use (0,0) as the client area top left because native viewport widget   
       
   259         // is the parent widget of the Scrollable's children and viewport does have any trimmings.
       
   260         // E.g. implementations of Layout.layout(Composite, boolean) read the client 
       
   261         // area top left when setting bounds for Composite's children. 
       
   262         Rectangle clientArea = OS.QWidget_rect(handle);
       
   263         
       
   264         // Null size, invisible SortedList gets negative viewPort. Qt layouts suspected.
       
   265         if (clientArea.width < 0) clientArea.width = 0;
       
   266         if (clientArea.height < 0) clientArea.height = 0;
       
   267         
       
   268         return clientArea;
       
   269     }
       
   270 
       
   271     /*
       
   272      * There's a problem that Qt doesn't apply the layouts or size policies when
       
   273      * widgets are not visible. The purpose of this method is to force Qt to
       
   274      * update the layouts e.g. when getClientArea is called before widget is
       
   275      * shown. Without this getClientArea won't return correct values. 
       
   276      */
       
   277     void updateQLayouts() {
       
   278         if(parent != null) parent.updateQLayouts();
       
   279         updateLayoutOfQWidget(topHandle);
       
   280         if(scrollAreaHandle != 0 && scrollAreaHandle != topHandle)
       
   281             updateLayoutOfQWidget(scrollAreaHandle);
       
   282         if(handle != scrollAreaHandle)
       
   283             updateLayoutOfQWidget(handle);
       
   284         
       
   285         // There's no public way to directly make QAbstractScrollArea execute its
       
   286         // layout calculation code. Corner widget functionality can be used to 
       
   287         // invoke it indirectly if there's no corner widget. I.e. this has nothing
       
   288         // to do with corner widget - the purpose is just to call layout calculation 
       
   289         // code by any means available. 
       
   290         if(scrollAreaHandle != 0) {
       
   291             int cornerWidget = OS.QAbstractScrollArea_cornerWidget(scrollAreaHandle);
       
   292             if(cornerWidget == 0) OS.QAbstractScrollArea_setCornerWidget(scrollAreaHandle, 0);
       
   293         }       
       
   294     }
       
   295     
       
   296     void updateLayoutOfQWidget(int handle) {
       
   297         int layout = OS.QWidget_layout(handle);
       
   298         if(layout != 0) {
       
   299             OS.QLayout_activate(layout);
       
   300             OS.QLayout_update(layout);
       
   301         }
       
   302     }
       
   303 
       
   304     /**
       
   305      * Returns the receiver's horizontal scroll bar if it has one, and null if
       
   306      * it does not.
       
   307      * 
       
   308      * @return the horizontal scroll bar (or null)
       
   309      * 
       
   310      * @exception SWTException
       
   311      *                <ul>
       
   312      *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
       
   313      *                disposed</li>
       
   314      *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
       
   315      *                thread that created the receiver</li>
       
   316      *                </ul>
       
   317      */
       
   318     public ScrollBar getHorizontalBar() {
       
   319         checkWidget();
       
   320         return horizontalBar;
       
   321     }
       
   322 
       
   323     /**
       
   324      * Returns the receiver's vertical scroll bar if it has one, and null if it
       
   325      * does not.
       
   326      * 
       
   327      * @return the vertical scroll bar (or null)
       
   328      * 
       
   329      * @exception SWTException
       
   330      *                <ul>
       
   331      *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been
       
   332      *                disposed</li>
       
   333      *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
       
   334      *                thread that created the receiver</li>
       
   335      *                </ul>
       
   336      */
       
   337     public ScrollBar getVerticalBar() {
       
   338         checkWidget();
       
   339         return verticalBar;
       
   340     }
       
   341 
       
   342     /*
       
   343      * Gets the preferred size of the widget excluding trimings.
       
   344      */
       
   345     Point getPreferredClientAreaSize_pp() {
       
   346         /*
       
   347          * Here, the handle is supposed to be a view port's handle. If not,
       
   348          * overwrite this method in the subclass
       
   349          */
       
   350         if (handle == 0)
       
   351             return new Point(WidgetConstant.DEFAULT_WIDTH, WidgetConstant.DEFAULT_HEIGHT);
       
   352         /*
       
   353         /* It seems that next line always returns an invalid size since there is no associated layout for viewport widget.
       
   354         /* So the function ends up with returning a default size
       
   355          */
       
   356         Point size = OS.QWidget_sizeHint(handle);
       
   357         if (size.x < 0)
       
   358             size.x = WidgetConstant.DEFAULT_WIDTH;
       
   359         if (size.y < 0)
       
   360             size.y = WidgetConstant.DEFAULT_HEIGHT;
       
   361         return size;
       
   362     }
       
   363 
       
   364     public void setData(String key, Object value) {
       
   365         super.setData(key, value);
       
   366          
       
   367         if (key.equals(WidgetConstant.SET_EMBEDDED_SCROLLBARS_STATE_KEY)) {
       
   368             if ((state & WidgetState.EMBEDDED_SCROLLBARS) != 0) {
       
   369                 disposeBars();
       
   370                 releaseBars();
       
   371             } else {
       
   372                 createBars();
       
   373             }
       
   374         }
       
   375     }
       
   376     
       
   377     private void disposeBars() {
       
   378         if (horizontalBar != null && !horizontalBar.isDisposed()) {
       
   379             horizontalBar.dispose();
       
   380         }
       
   381         if (verticalBar != null && !verticalBar.isDisposed()) {
       
   382             verticalBar.dispose();
       
   383         }
       
   384     }
       
   385 
       
   386     void releaseChildren_pp(boolean destroy) {
       
   387         releaseBars();
       
   388         super.releaseChildren_pp(destroy);
       
   389     }
       
   390 
       
   391     private void releaseBars() {
       
   392         if (horizontalBar != null) {
       
   393             horizontalBar.release(false);
       
   394             horizontalBar = null;
       
   395         }
       
   396         if (verticalBar != null) {
       
   397             verticalBar.release(false);
       
   398             verticalBar = null;
       
   399         }
       
   400     }
       
   401 
       
   402     void deregister_pp() {
       
   403         super.deregister_pp();
       
   404         display.removeWidget(scrollAreaHandle);
       
   405     }
       
   406 
       
   407     void register_pp() {
       
   408         super.register_pp();
       
   409         display.addWidget(scrollAreaHandle, this);
       
   410     }
       
   411 
       
   412     void releaseHandle_pp() {
       
   413         scrollAreaHandle = 0;
       
   414         super.releaseHandle_pp();
       
   415     }
       
   416 
       
   417     void setOrientation(int handle, int orientation) {
       
   418         checkWidget();
       
   419         int flags = SWT.RIGHT_TO_LEFT | SWT.LEFT_TO_RIGHT;
       
   420         if ((orientation & flags) == 0 || (orientation & flags) == flags)
       
   421             return;
       
   422 
       
   423         style &= ~flags;
       
   424         style |= orientation & flags;
       
   425 
       
   426         OS.QWidget_setLayoutDirection(handle,
       
   427                 orientation == SWT.LEFT_TO_RIGHT ? OS.QT_LEFTTORIGHT
       
   428                         : OS.QT_RIGHTTOLEFT);
       
   429     }
       
   430     
       
   431     void setHBarPolicy(boolean status) {
       
   432         if (status)
       
   433             OS.QAbstractScrollArea_setHorizontalScrollBarPolicy(scrollAreaHandle, 
       
   434                 OS.QT_SCROLLBARALWAYSON);
       
   435         else
       
   436             OS.QAbstractScrollArea_setHorizontalScrollBarPolicy(scrollAreaHandle, 
       
   437                 OS.QT_SCROLLBARALWAYSOFF);
       
   438     }
       
   439     
       
   440     void setVBarPolicy(boolean status) {
       
   441         if (status)
       
   442             OS.QAbstractScrollArea_setVerticalScrollBarPolicy(scrollAreaHandle, 
       
   443                 OS.QT_SCROLLBARALWAYSON);
       
   444         else
       
   445             OS.QAbstractScrollArea_setVerticalScrollBarPolicy(scrollAreaHandle, 
       
   446                 OS.QT_SCROLLBARALWAYSOFF);
       
   447     }
       
   448 
       
   449 }