MenuLayout.java
001 /*
002  *
003  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
004  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
005  *
006  *  This file is part of GATE (see http://gate.ac.uk/), and is free
007  *  software, licenced under the GNU Library General Public License,
008  *  Version 2, June 1991 (in the distribution as file licence.html,
009  *  and also available at http://gate.ac.uk/gate/licence.html).
010  *
011  *  Valentin Tablan 20 Feb 2003
012  *
013  *  $Id: MenuLayout.java 12006 2009-12-01 17:24:28Z thomas_heitz $
014  */
015 
016 package guk;
017 
018 import java.awt.*;
019 
020 import javax.swing.JPopupMenu;
021 import javax.swing.SwingUtilities;
022 
023 
024 /**
025  * A layout designed to allow Java menus to make better use of the screen
026  * real-estate. It will lay out the menu components in columns going from top
027  * to bottom and from left to right.
028  */
029 public class MenuLayout implements LayoutManager {
030 
031   /**
032    * Adds the specified component to the layout. Not used by this class.
033    @param name the name of the component
034    @param comp the the component to be added
035    */
036   public void addLayoutComponent(String name, Component comp) {}
037 
038   /**
039    * Removes the specified component from the layout. Not used by this class.
040    @param comp the component to remove
041    */
042   public void removeLayoutComponent(Component comp) {}
043 
044   /**
045    * Returns the preferred dimensions for this layout given the components
046    * in the specified target container.
047    @param target the component which needs to be laid out
048    @see Container
049    @see #minimumLayoutSize
050    */
051   public Dimension preferredLayoutSize(Container target) {
052     int membersCnt = target.getComponentCount();
053     Dimension[] componentPrefSizes = new Dimension[membersCnt];
054     //store the sizes
055     for(int i = 0; i < membersCnt; i++){
056       componentPrefSizes[i= target.getComponent(i).getPreferredSize();
057     }
058     Dimension dim = getCompositeSize(target, componentPrefSizes);
059     return dim;
060   }
061 
062   /**
063    * Calculates the size of the target container given the sizes of the
064    * components.
065    * If the doLayout is <b>true</b> it will also ly out the container.
066    * Used by {@link #minimumLayoutSize} and {@link #preferredLayoutSize}.
067    @param target
068    @param componentSizes
069    @return {@link Dimension} value.
070    */
071   protected Dimension getCompositeSize(Container target,
072                                        Dimension[] componentSizes){
073     //find the origin of the popup
074     Point location = new Point(00);
075     if(target.isShowing()){
076       location = target.getLocationOnScreen();
077     }else{
078       if(target instanceof JPopupMenu){
079         Component invoker = ((JPopupMenu)target).getInvoker();
080         if(invoker != nulllocation = invoker.getLocationOnScreen();
081       }
082     }
083 
084     //correct offscreen showing
085     if(location.x < || location.y < 0){
086       location.x = Math.max(0, location.x);
087       location.y = Math.max(0, location.y);
088     }
089     //find the maximum size
090     Toolkit toolkit = Toolkit.getDefaultToolkit();
091     Rectangle contentsBounds = new Rectangle(toolkit.getScreenSize());
092     Insets screenInsets = new Insets(0000);
093     GraphicsConfiguration gc = findGraphicsConfiguration(target);
094     if (gc != null) {
095       contentsBounds = gc.getBounds();
096       screenInsets = toolkit.getScreenInsets(gc);
097     }else{
098     }
099 
100     // take screen insets (e.g. taskbar) into account
101     contentsBounds.width -= screenInsets.left + screenInsets.right;
102     contentsBounds.height -= screenInsets.top + screenInsets.bottom;
103     //take the location into account assuming that the largest side will be used
104     contentsBounds.height = Math.max(location.y,
105                                      contentsBounds.height - location.y);
106 
107     // take component insets into account
108     Insets insets = target.getInsets();
109     contentsBounds.width -= insets.left + insets.right;
110     contentsBounds.height -= insets.top + insets.bottom;
111     Dimension dim = new Dimension(00);
112     int previousColumnsWidth = 0;
113     int previousColumnsHeight = 0;
114     for (int i = 0; i < componentSizes.length; i++) {
115       if ( (dim.height +
116             componentSizes[i].height<= contentsBounds.height) {
117         //we can fit the current component in the current row
118         dim.height += componentSizes[i].height;
119         dim.width = Math.max(dim.width, componentSizes[i].width);
120       }
121       else {
122         //we need to start a new column
123         previousColumnsWidth += dim.width;
124         previousColumnsHeight = Math.max(previousColumnsHeight, dim.height);
125         dim.height = componentSizes[i].height;
126         dim.width = componentSizes[i].width;
127       }
128     }
129 
130     //Now dim contains the sizes for the last column
131     dim.height = Math.max(previousColumnsHeight, dim.height);
132     dim.width += previousColumnsWidth;
133     //add the target insets
134     dim.width += insets.left + insets.right;
135     dim.height += insets.top + insets.bottom;
136     return dim;
137   }
138 
139   /**
140    * Find the graphics configuration for the target popup (useful in case of
141    * multiple screens).
142    @param target the component for which the configuration needs to be found.
143    @return a GraphicsConfiguration value.
144    */
145   protected GraphicsConfiguration findGraphicsConfiguration(Component target){
146     GraphicsConfiguration gc = null;
147     if(!target.isShowing()){
148       if(target instanceof JPopupMenu){
149         Component invoker = ((JPopupMenu)target).getInvoker();
150         if(invoker != nulltarget = invoker;
151       }
152     }
153     if(target.isShowing()){
154       Point position = target.getLocationOnScreen();
155       Toolkit toolkit = Toolkit.getDefaultToolkit();
156       gc = target.getGraphicsConfiguration();
157       GraphicsEnvironment ge =
158           GraphicsEnvironment.getLocalGraphicsEnvironment();
159       GraphicsDevice[] gd = ge.getScreenDevices();
160       for (int i = 0; i < gd.length; i++) {
161         if (gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
162           GraphicsConfiguration dgc =
163               gd[i].getDefaultConfiguration();
164           if (dgc.getBounds().contains(position)) {
165             gc = dgc;
166             break;
167           }
168         }
169       }
170     }
171     return gc;
172   }
173 
174   /**
175    * Returns the minimum dimensions needed to layout the components
176    * contained in the specified target container.
177    @param target the component which needs to be laid out
178    @see #preferredLayoutSize
179    */
180   public Dimension minimumLayoutSize(Container target) {
181     int membersCnt = target.getComponentCount();
182     Dimension[] componentMinSizes = new Dimension[membersCnt];
183     //store the sizes
184     for(int i = 0; i < membersCnt; i++){
185       componentMinSizes[i= target.getComponent(i).getMinimumSize();
186     }
187     return getCompositeSize(target, componentMinSizes);
188   }
189 
190 
191   public void layoutContainer(Container target) {
192     Insets insets = target.getInsets();
193     Rectangle bounds = target.getBounds();
194     //correct off-screen showing
195     if(target.isShowing()){
196       Point locationOnScreen = target.getLocationOnScreen();
197       if(locationOnScreen.x < || locationOnScreen.y < 0){
198         Window parent = SwingUtilities.getWindowAncestor(target);
199         int newx = Math.max(0, locationOnScreen.x);
200         int newy = Math.max(0, locationOnScreen.y);
201         parent.setLocation(newx, newy);
202       }
203     }
204     int maxheight = bounds.height - insets.bottom;
205     int compCnt = target.getComponentCount();
206     int y = insets.top;
207     int x = insets.left;
208     int rowWidth = 0;
209 
210     for (int i = 0; i < compCnt; i++) {
211       Component comp = target.getComponent(i);
212       if (comp.isVisible()) {
213         Dimension d = comp.getPreferredSize();
214         comp.setSize(d);
215         if (y + d.height <= maxheight) {
216           comp.setLocation(x, y);
217           y += d.height;
218           rowWidth = Math.max(rowWidth, d.width);
219         }
220         else {
221           //we need to start a new column
222           x += rowWidth;
223           rowWidth = 0;
224           y = insets.top;
225           comp.setLocation(x, y);
226           y += d.height;
227           rowWidth = Math.max(rowWidth, d.width);
228         }
229       }
230     }
231   }
232 }