PageRenderTime 41ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/gui/VariableGridLayout.java

#
Java | 342 lines | 186 code | 53 blank | 103 comment | 40 complexity | a7917a33ce62243540b1099a7207c147 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * VariableGridLayout.java - a grid layout manager with variable cell sizes
  3. * (c) 2001 - Dirk Moebius (dmoebius@gmx.net)
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. package org.gjt.sp.jedit.gui;
  20. import java.awt.*;
  21. /**
  22. * The <code>VariableGridLayout</code> class is a layout manager
  23. * that lays out a container's components in a rectangular grid
  24. * with variable cell sizes.<p>
  25. *
  26. * The container is divided into rectangles, and one component is placed
  27. * in each rectangle. Each row is as large as the largest component in
  28. * that row, and each column is as wide as the widest component in
  29. * that column.<p>
  30. *
  31. * This behavior is basically the same as in
  32. * <code>java.awt.GridLayout</code>, but with different row heights and
  33. * column widths for each row/column.<p>
  34. *
  35. * For example, the following is an applet that lays out six buttons
  36. * into three rows and two columns:<p>
  37. *
  38. * <blockquote><pre>
  39. * import java.awt.*;
  40. * import java.applet.Applet;
  41. * public class ButtonGrid extends Applet {
  42. * public void init() {
  43. * setLayout(new VariableGridLayout(VariableGridLayout.FIXED_NUM_COLUMNS, 2));
  44. * add(new Button("1"));
  45. * add(new Button("2"));
  46. * add(new Button("3"));
  47. * add(new Button("4"));
  48. * add(new Button("5"));
  49. * add(new Button("6"));
  50. * }
  51. * }
  52. * </pre></blockquote><p>
  53. *
  54. * <b>Programmer's remark:</b> VariableGridLayout could be faster, if it would
  55. * reside in the package java.awt, because then it could access some
  56. * package private fields of <code>Container</code> or
  57. * <code>Component</code>. Instead, it has to call
  58. * <code>Component.getSize()</code>,
  59. * which allocates memory on the heap.<p>
  60. *
  61. * <b>Todo:</b>
  62. * <ul>
  63. * <li>Use alignmentX/Y property if the grid cell is larger than the preferred size of the component.
  64. * <li>Ability to span components over more than one cell horizontally
  65. * </ul>
  66. *
  67. * @author Dirk Moebius
  68. * @version 1.0
  69. * @see java.awt.GridLayout
  70. */
  71. public class VariableGridLayout implements LayoutManager2, java.io.Serializable
  72. {
  73. public static final int FIXED_NUM_ROWS = 1;
  74. public static final int FIXED_NUM_COLUMNS = 2;
  75. public VariableGridLayout(int mode, int size, int hgap, int vgap) {
  76. if (mode != FIXED_NUM_ROWS && mode != FIXED_NUM_COLUMNS) {
  77. throw new IllegalArgumentException("illegal mode; value is " + mode);
  78. }
  79. if (size <= 0) {
  80. throw new IllegalArgumentException("size cannot be zero or less; value is " + size);
  81. }
  82. if (hgap < 0) {
  83. throw new IllegalArgumentException("hgap cannot be negative; value is " + hgap);
  84. }
  85. if (vgap < 0) {
  86. throw new IllegalArgumentException("vgap cannot be negative; value is " + vgap);
  87. }
  88. this.mode = mode;
  89. this.size = size;
  90. this.hgap = hgap;
  91. this.vgap = vgap;
  92. }
  93. /**
  94. * Creates a variable grid layout manager with the specified mode
  95. * and zero horizontal and vertical gap.
  96. */
  97. public VariableGridLayout(int mode, int size) {
  98. this(mode, size, 0, 0);
  99. }
  100. /**
  101. * Creates a variable grid layout manager with mode FIXED_NUM_ROWS,
  102. * number of rows == 1 and zero horizontal and vertical gap.
  103. */
  104. public VariableGridLayout() {
  105. this(FIXED_NUM_ROWS, 1, 0, 0);
  106. }
  107. /**
  108. * Not used in this class.
  109. */
  110. public void addLayoutComponent(String name, Component component) { }
  111. /**
  112. * Not used in this class.
  113. */
  114. public void addLayoutComponent(Component component, Object constraints) { }
  115. /**
  116. * Not used in this class.
  117. */
  118. public void removeLayoutComponent(Component component) { }
  119. /**
  120. * Always returns 0.5.
  121. */
  122. public float getLayoutAlignmentX(Container container) {
  123. return 0.5f;
  124. }
  125. /**
  126. * Always returns 0.5.
  127. */
  128. public float getLayoutAlignmentY(Container container) {
  129. return 0.5f;
  130. }
  131. public Dimension preferredLayoutSize(Container parent) {
  132. return getLayoutSize(parent, 2);
  133. }
  134. public Dimension minimumLayoutSize(Container parent) {
  135. return getLayoutSize(parent, 0);
  136. }
  137. public Dimension maximumLayoutSize(Container parent) {
  138. return getLayoutSize(parent, 1);
  139. }
  140. public void layoutContainer(Container parent) {
  141. synchronized (parent.getTreeLock()) {
  142. int ncomponents = parent.getComponentCount();
  143. if (ncomponents == 0) {
  144. return;
  145. }
  146. // Pass 1: compute preferred row heights / column widths
  147. int total_height = 0;
  148. for (int r = 0, i = 0; r < nrows; r++) {
  149. for (int c = 0; c < ncols; c++, i++) {
  150. if (i < ncomponents) {
  151. Dimension d = parent.getComponent(i).getPreferredSize();
  152. row_heights[r] = Math.max(row_heights[r], d.height);
  153. col_widths[c] = Math.max(col_widths[c], d.width);
  154. } else {
  155. break;
  156. }
  157. }
  158. total_height += row_heights[r];
  159. }
  160. int total_width = 0;
  161. for (int c = 0; c < ncols; c++) {
  162. total_width += col_widths[c];
  163. }
  164. // Pass 2: redistribute free space
  165. Dimension parent_size = parent.getSize();
  166. Insets insets = parent.getInsets();
  167. int free_height = parent_size.height - insets.top - insets.bottom - (nrows - 1) * vgap;
  168. int free_width = parent_size.width - insets.left - insets.right - (ncols - 1) * hgap;
  169. if (total_height != free_height) {
  170. double dy = (double)free_height / (double)total_height;
  171. for (int r = 0; r < nrows; r++) {
  172. row_heights[r] = (int) ((double)row_heights[r] * dy);
  173. }
  174. }
  175. if (total_width != free_width) {
  176. double dx = ((double)free_width) / ((double)total_width);
  177. for (int c = 0; c < ncols; c++) {
  178. col_widths[c] = (int) ((double)col_widths[c] * dx);
  179. }
  180. }
  181. // Pass 3: layout components
  182. for (int r = 0, y = insets.top, i = 0; r < nrows; y += row_heights[r] + vgap, r++) {
  183. for (int c = 0, x = insets.left; c < ncols; x += col_widths[c] + hgap, c++, i++) {
  184. if (i < ncomponents) {
  185. parent.getComponent(i).setBounds(x, y, col_widths[c], row_heights[r]);
  186. }
  187. }
  188. }
  189. } // synchronized
  190. }
  191. public void invalidateLayout(Container container) {
  192. int ncomponents = container.getComponentCount();
  193. int old_nrows = nrows;
  194. int old_ncols = ncols;
  195. if (this.mode == FIXED_NUM_ROWS) {
  196. nrows = this.size;
  197. ncols = (ncomponents + nrows - 1) / nrows;
  198. } else {
  199. ncols = this.size;
  200. nrows = (ncomponents + ncols - 1) / ncols;
  201. }
  202. if (old_nrows != nrows) {
  203. row_heights = new int[nrows];
  204. }
  205. if (old_ncols != ncols) {
  206. col_widths = new int[ncols];
  207. }
  208. }
  209. public int getRows() {
  210. return nrows;
  211. }
  212. public int getColumns() {
  213. return ncols;
  214. }
  215. /**
  216. * Returns the string representation of this variable grid layout's values.
  217. * @return a string representation of this variable grid layout.
  218. */
  219. public String toString() {
  220. return getClass().getName() + "[mode=" + mode + ",size=" + size
  221. + ",hgap=" + hgap + ",vgap=" + vgap + "]";
  222. }
  223. /**
  224. * @param which if 0 compute minimum layout size,
  225. * if 1 compute maximum layout size,
  226. * otherwise compute preferred layout size.
  227. */
  228. private Dimension getLayoutSize(Container parent, int which) {
  229. synchronized (parent.getTreeLock()){
  230. int ncomponents = parent.getComponentCount();
  231. int h = 0;
  232. int w = 0;
  233. for (int r = 0, i = 0; r < nrows; r++) {
  234. int row_height = 0;
  235. for (int c = 0; c < ncols; c++, i++) {
  236. if (i < ncomponents) {
  237. switch (which) {
  238. case 0:
  239. row_height = Math.max(row_height, parent.getComponent(i).getMinimumSize().height);
  240. break;
  241. case 1:
  242. row_height = Math.max(row_height, parent.getComponent(i).getMaximumSize().height);
  243. break;
  244. default:
  245. row_height = Math.max(row_height, parent.getComponent(i).getPreferredSize().height);
  246. break;
  247. }
  248. } else {
  249. break;
  250. }
  251. }
  252. h += row_height;
  253. }
  254. for (int c = 0; c < ncols; c++) {
  255. int col_width = 0;
  256. for (int r = 0; r < nrows; r++) {
  257. int i = r * ncols + c;
  258. if (i < ncomponents) {
  259. switch (which) {
  260. case 0:
  261. col_width = Math.max(col_width, parent.getComponent(i).getMinimumSize().width);
  262. break;
  263. case 1:
  264. col_width = Math.max(col_width, parent.getComponent(i).getMaximumSize().width);
  265. break;
  266. default:
  267. col_width = Math.max(col_width, parent.getComponent(i).getPreferredSize().width);
  268. break;
  269. }
  270. } else {
  271. break;
  272. }
  273. }
  274. w += col_width;
  275. }
  276. Insets insets = parent.getInsets();
  277. return new Dimension(w + insets.left + insets.right + ((ncols - 1) * hgap),
  278. h + insets.top + insets.bottom + ((nrows - 1) * vgap));
  279. }
  280. }
  281. private int mode;
  282. private int size;
  283. private int hgap;
  284. private int vgap;
  285. private transient int nrows = -1;
  286. private transient int ncols = -1;
  287. private transient int[] row_heights = null;
  288. private transient int[] col_widths = null;
  289. }