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 a {@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(0, 0);
075 if(target.isShowing()){
076 location = target.getLocationOnScreen();
077 }else{
078 if(target instanceof JPopupMenu){
079 Component invoker = ((JPopupMenu)target).getInvoker();
080 if(invoker != null) location = invoker.getLocationOnScreen();
081 }
082 }
083
084 //correct offscreen showing
085 if(location.x < 0 || 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(0, 0, 0, 0);
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(0, 0);
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 != null) target = 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 < 0 || 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 }
|