jdk/src/solaris/classes/sun/awt/motif/MScrollPanePeer.java
changeset 1192 715cf9378c53
parent 1051 90cf935adb35
parent 1191 f142c1da78c2
child 1193 41afb8ee8f45
equal deleted inserted replaced
1051:90cf935adb35 1192:715cf9378c53
     1 /*
       
     2  * Copyright 1996-2003 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.awt.motif;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.event.AdjustmentEvent;
       
    30 import java.awt.peer.ScrollPanePeer;
       
    31 
       
    32 import java.util.logging.*;
       
    33 
       
    34 import sun.awt.PeerEvent;
       
    35 
       
    36 class MScrollPanePeer extends MPanelPeer implements ScrollPanePeer {
       
    37 
       
    38     private static final Logger log = Logger.getLogger("sun.awt.motif.MScrollPanePeer");
       
    39 
       
    40     final static int UNIT_INCREMENT = 0;
       
    41     final static int BLOCK_INCREMENT = 1;
       
    42 
       
    43     boolean ignore;
       
    44 
       
    45     native void create(MComponentPeer parent);
       
    46 
       
    47     static {
       
    48         initIDs();
       
    49     }
       
    50 
       
    51     /**
       
    52      * Initialize JNI field and method IDs
       
    53      */
       
    54     private static native void initIDs();
       
    55 
       
    56     MScrollPanePeer(Component target) {
       
    57         init(target);
       
    58         scrollPaneInit();
       
    59     }
       
    60 
       
    61     MScrollPanePeer(Component target, Object arg) {
       
    62         init(target, arg);
       
    63         scrollPaneInit();
       
    64     }
       
    65 
       
    66     void scrollPaneInit() {
       
    67         ignore = false;
       
    68         ScrollPane sp = (ScrollPane)target;
       
    69         Adjustable vadj, hadj;
       
    70         if ((vadj = sp.getVAdjustable()) != null) {
       
    71             pSetIncrement(Adjustable.VERTICAL, UNIT_INCREMENT, vadj.getUnitIncrement());
       
    72         }
       
    73         if ((hadj = sp.getHAdjustable()) != null) {
       
    74             pSetIncrement(Adjustable.HORIZONTAL, UNIT_INCREMENT, hadj.getUnitIncrement());
       
    75         }
       
    76         super.pSetScrollbarBackground(sp.getBackground());
       
    77     }
       
    78 
       
    79     public void setScrollChild(MComponentPeer child) {
       
    80         pSetScrollChild(child);
       
    81     }
       
    82 
       
    83     public void setBackground(Color c) {
       
    84         super.setBackground(c);
       
    85         pSetScrollbarBackground(c);
       
    86     }
       
    87 
       
    88     public void setForeground(Color c) {
       
    89         super.setForeground(c);
       
    90         pSetInnerForeground(c);
       
    91     }
       
    92 
       
    93     native void pSetScrollChild(MComponentPeer child);
       
    94     native void pSetIncrement(int orient, int type, int incr);
       
    95     native int pGetScrollbarSpace(int orient);
       
    96     native int pGetBlockIncrement(int orient);
       
    97     native Insets pInsets(int w, int h, int childw, int childh);
       
    98     native int pGetShadow();
       
    99 
       
   100     public int getHScrollbarHeight() {
       
   101         ScrollPane sp = (ScrollPane)target;
       
   102         if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) {
       
   103             return 0;
       
   104         } else {
       
   105             return pGetScrollbarSpace(Adjustable.HORIZONTAL);
       
   106         }
       
   107     }
       
   108 
       
   109     public int getVScrollbarWidth() {
       
   110         ScrollPane sp = (ScrollPane)target;
       
   111         if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) {
       
   112             return 0;
       
   113         } else {
       
   114             return pGetScrollbarSpace(Adjustable.VERTICAL);
       
   115         }
       
   116     }
       
   117 
       
   118     public Insets insets() {
       
   119         ScrollPane sp = (ScrollPane)target;
       
   120         Dimension d = sp.size();
       
   121         Dimension cd;
       
   122         Component c = getScrollChild();
       
   123         if (c != null) {
       
   124             cd = c.size();
       
   125         } else {
       
   126             cd = new Dimension(0, 0);
       
   127         }
       
   128         return pInsets(d.width, d.height, cd.width, cd.height);
       
   129     }
       
   130 
       
   131     public void setUnitIncrement(Adjustable adj, int u) {
       
   132         ScrollPane sp = (ScrollPane)target;
       
   133         if (sp.getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) {
       
   134             pSetIncrement(adj.getOrientation(), UNIT_INCREMENT, u);
       
   135         }
       
   136     }
       
   137 
       
   138     public void setValue(Adjustable adj, int v) {
       
   139         if (! ignore) {
       
   140             Point p;
       
   141             Component c = getScrollChild();
       
   142             if (c == null) {
       
   143                 return;
       
   144             }
       
   145             p = c.getLocation();
       
   146             switch(adj.getOrientation()) {
       
   147             case Adjustable.VERTICAL:
       
   148                 setScrollPosition(-(p.x), v);
       
   149                 break;
       
   150             case Adjustable.HORIZONTAL:
       
   151                 setScrollPosition(v, -(p.y));
       
   152                 break;
       
   153             }
       
   154         }
       
   155     }
       
   156 
       
   157     public native void setScrollPosition(int x, int y);
       
   158 
       
   159     public void childResized(int w, int h) {
       
   160         // REMIND AIM:  May need to revisit this...
       
   161         if (((ScrollPane)target).getScrollbarDisplayPolicy() != ScrollPane.SCROLLBARS_NEVER) {
       
   162             ScrollPane sp = (ScrollPane)target;
       
   163             Adjustable vAdj = sp.getVAdjustable();
       
   164             Adjustable hAdj = sp.getHAdjustable();
       
   165             pSetIncrement(Scrollbar.VERTICAL, UNIT_INCREMENT, vAdj.getUnitIncrement());
       
   166             pSetIncrement(Scrollbar.HORIZONTAL, UNIT_INCREMENT, hAdj.getUnitIncrement());
       
   167             pSetIncrement(Scrollbar.VERTICAL, BLOCK_INCREMENT, vAdj.getBlockIncrement());
       
   168             pSetIncrement(Scrollbar.HORIZONTAL, BLOCK_INCREMENT, hAdj.getBlockIncrement());
       
   169         }
       
   170 
       
   171     }
       
   172 
       
   173     // NOTE: This method may be called by privileged threads.
       
   174     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
       
   175     private void postScrollEvent(int orient, int type,
       
   176                                  int pos, boolean isAdjusting)
       
   177     {
       
   178         Runnable adjustor = new Adjustor(orient, type, pos, isAdjusting);
       
   179         MToolkit.executeOnEventHandlerThread(new ScrollEvent(target, adjustor));
       
   180     }
       
   181 
       
   182     /**
       
   183      * This is used to change the adjustable on dispatch thread to
       
   184      * represent a change made in the native scrollbar.  Since the
       
   185      * change was reflected immediately at the native level,
       
   186      * notification from the adjustable is temporarily ignored.
       
   187      */
       
   188     class ScrollEvent extends PeerEvent {
       
   189         ScrollEvent(Object source, Runnable runnable) {
       
   190             super(source, runnable, 0L);
       
   191         }
       
   192 
       
   193         public PeerEvent coalesceEvents(PeerEvent newEvent) {
       
   194             if (log.isLoggable(Level.FINEST)) {
       
   195                 log.log(Level.FINEST, "ScrollEvent coalesced " + newEvent);
       
   196             }
       
   197             if (newEvent instanceof ScrollEvent) {
       
   198                 return newEvent;
       
   199             }
       
   200             return null;
       
   201         }
       
   202     }
       
   203 
       
   204     native void setTypedValue(ScrollPaneAdjustable adjustable, int value, int type);
       
   205 
       
   206     /**
       
   207      * Runnable for the ScrollEvent that performs the adjustment.
       
   208      */
       
   209     class Adjustor implements Runnable {
       
   210         int orient;             // selects scrollbar
       
   211         int type;               // adjustment type
       
   212         int pos;                // new position (only used for absolute)
       
   213         boolean isAdjusting;    // isAdjusting status
       
   214 
       
   215         Adjustor(int orient, int type, int pos, boolean isAdjusting) {
       
   216             this.orient = orient;
       
   217             this.type = type;
       
   218             this.pos = pos;
       
   219             this.isAdjusting = isAdjusting;
       
   220         }
       
   221 
       
   222         public void run() {
       
   223             ScrollPane sp = (ScrollPane)MScrollPanePeer.this.target;
       
   224             ScrollPaneAdjustable adj = null;
       
   225 
       
   226             // ScrollPaneAdjustable made public in 1.4, but
       
   227             // get[HV]Adjustable can't be declared to return
       
   228             // ScrollPaneAdjustable because it would break backward
       
   229             // compatibility -- hence the cast
       
   230 
       
   231             if (orient == Adjustable.VERTICAL) {
       
   232                 adj = (ScrollPaneAdjustable)sp.getVAdjustable();
       
   233             } else if (orient == Adjustable.HORIZONTAL) {
       
   234                 adj = (ScrollPaneAdjustable)sp.getHAdjustable();
       
   235             } else {
       
   236                 if (log.isLoggable(Level.FINE)) {
       
   237                     log.log(Level.FINE, "Assertion failed: unknown orient");
       
   238                 }
       
   239             }
       
   240 
       
   241             if (adj == null) {
       
   242                 return;
       
   243             }
       
   244 
       
   245             int newpos = adj.getValue();
       
   246             switch (type) {
       
   247               case AdjustmentEvent.UNIT_DECREMENT:
       
   248                   newpos -= adj.getUnitIncrement();
       
   249                   break;
       
   250               case AdjustmentEvent.UNIT_INCREMENT:
       
   251                   newpos += adj.getUnitIncrement();
       
   252                   break;
       
   253               case AdjustmentEvent.BLOCK_DECREMENT:
       
   254                   newpos -= adj.getBlockIncrement();
       
   255                   break;
       
   256               case AdjustmentEvent.BLOCK_INCREMENT:
       
   257                   newpos += adj.getBlockIncrement();
       
   258                   break;
       
   259               case AdjustmentEvent.TRACK:
       
   260                   newpos = this.pos;
       
   261                   break;
       
   262               default:
       
   263                   if (log.isLoggable(Level.FINE)) {
       
   264                       log.log(Level.FINE, "Assertion failed: unknown type");
       
   265                   }
       
   266                   return;
       
   267             }
       
   268 
       
   269             // keep scroll position in acceptable range
       
   270             newpos = Math.max(adj.getMinimum(), newpos);
       
   271             newpos = Math.min(adj.getMaximum(), newpos);
       
   272 
       
   273             // set value; this will synchronously fire an AdjustmentEvent
       
   274             try {
       
   275                 MScrollPanePeer.this.ignore = true;
       
   276                 adj.setValueIsAdjusting(isAdjusting);
       
   277 
       
   278                 // Fix for 4075484 - consider type information when creating AdjustmentEvent
       
   279                 // We can't just call adj.setValue() because it creates AdjustmentEvent with type=TRACK
       
   280                 // Instead, we call private method setTypedValue of ScrollPaneAdjustable.
       
   281                 // Because ScrollPaneAdjustable is in another package we should call it through native code.
       
   282                 setTypedValue(adj, newpos, type);
       
   283             } finally {
       
   284                 MScrollPanePeer.this.ignore = false;
       
   285             }
       
   286         }
       
   287     } // class Adjustor
       
   288 
       
   289 
       
   290     private Component getScrollChild() {
       
   291         ScrollPane sp = (ScrollPane)target;
       
   292         Component child = null;
       
   293         try {
       
   294             child = sp.getComponent(0);
       
   295         } catch (ArrayIndexOutOfBoundsException e) {
       
   296             // do nothing.  in this case we return null
       
   297         }
       
   298         return child;
       
   299     }
       
   300 
       
   301     final static int    MARGIN = 1;
       
   302     final static int    SCROLLBAR = 16;
       
   303     int hsbSpace;
       
   304     int vsbSpace;
       
   305     int vval;
       
   306     int hval;
       
   307     int vmax;
       
   308     int hmax;
       
   309     /*
       
   310      * Print the native component by rendering the Motif look ourselves.
       
   311      * ToDo(aim): needs to query native motif for more accurate size and
       
   312      * color information.
       
   313      */
       
   314     public void print(Graphics g) {
       
   315         ScrollPane sp = (ScrollPane)target;
       
   316         Dimension d = sp.size();
       
   317         Color bg = sp.getBackground();
       
   318         Color fg = sp.getForeground();
       
   319         Point p = sp.getScrollPosition();
       
   320         Component c = getScrollChild();
       
   321         Dimension cd;
       
   322         if (c != null) {
       
   323             cd = c.size();
       
   324         } else {
       
   325             cd = new Dimension(0, 0);
       
   326         }
       
   327         int sbDisplay = sp.getScrollbarDisplayPolicy();
       
   328         int vvis, hvis, vmin, hmin, vmax, hmax, vval, hval;
       
   329 
       
   330         switch (sbDisplay) {
       
   331           case ScrollPane.SCROLLBARS_NEVER:
       
   332             hsbSpace = vsbSpace = 0;
       
   333             break;
       
   334           case ScrollPane.SCROLLBARS_ALWAYS:
       
   335             hsbSpace = vsbSpace = SCROLLBAR;
       
   336             break;
       
   337           case ScrollPane.SCROLLBARS_AS_NEEDED:
       
   338             hsbSpace = (cd.width <= (d.width - 2*MARGIN)? 0 : SCROLLBAR);
       
   339             vsbSpace = (cd.height <= (d.height - 2*MARGIN)? 0 : SCROLLBAR);
       
   340 
       
   341             if (hsbSpace == 0 && vsbSpace != 0) {
       
   342                 hsbSpace = (cd.width <= (d.width - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR);
       
   343             }
       
   344             if (vsbSpace == 0 && hsbSpace != 0) {
       
   345                 vsbSpace = (cd.height <= (d.height - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR);
       
   346             }
       
   347         }
       
   348 
       
   349         vvis = hvis = vmin = hmin = vmax = hmax = vval = hval = 0;
       
   350 
       
   351         if (vsbSpace > 0) {
       
   352             vmin = 0;
       
   353             vvis = d.height - (2*MARGIN) - hsbSpace;
       
   354             vmax = Math.max(cd.height - vvis, 0);
       
   355             vval = p.y;
       
   356         }
       
   357         if (hsbSpace > 0) {
       
   358             hmin = 0;
       
   359             hvis = d.width - (2*MARGIN) - vsbSpace;
       
   360             hmax = Math.max(cd.width - hvis, 0);
       
   361             hval = p.x;
       
   362         }
       
   363 
       
   364         // need to be careful to add the margins back in here because
       
   365         // we're drawing the margin border, after all!
       
   366         int w = d.width - vsbSpace;
       
   367         int h = d.height - hsbSpace;
       
   368 
       
   369         g.setColor(bg);
       
   370         g.fillRect(0, 0, d.width, d.height);
       
   371 
       
   372         if (hsbSpace > 0) {
       
   373             int sbw = d.width - vsbSpace;
       
   374             g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3);
       
   375             Graphics ng = g.create();
       
   376             try {
       
   377                 ng.translate(0, d.height - (SCROLLBAR - 2));
       
   378                 drawScrollbar(ng, bg, SCROLLBAR - 2, sbw,
       
   379                                hmin, hmax, hval, hvis, true);
       
   380             } finally {
       
   381                 ng.dispose();
       
   382             }
       
   383         }
       
   384         if (vsbSpace > 0) {
       
   385             int sbh = d.height - hsbSpace;
       
   386             g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1);
       
   387             Graphics ng = g.create();
       
   388             try {
       
   389                 ng.translate(d.width - (SCROLLBAR - 2), 0);
       
   390                 drawScrollbar(ng, bg, SCROLLBAR - 2, sbh,
       
   391                                vmin, vmax, vval, vvis, false);
       
   392             } finally {
       
   393                 ng.dispose();
       
   394             }
       
   395         }
       
   396 
       
   397         draw3DRect(g, bg, 0, 0, w - 1, h - 1, false);
       
   398 
       
   399         target.print(g);
       
   400         sp.printComponents(g);
       
   401     }
       
   402 
       
   403     /**
       
   404      * @see ContainerPeer#restack
       
   405      */
       
   406     public void restack() {
       
   407         // Since ScrollPane can only have one child its restacking does nothing.
       
   408         // Also, it is dangerous, since SP child is actually not a child of SP widget
       
   409         // but the child of SP content widget.
       
   410     }
       
   411 }