You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GridLayout.java 27KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. /* *************************************************************************
  2. IT Mill Toolkit
  3. Development of Browser User Interfaces Made Easy
  4. Copyright (C) 2000-2007 IT Mill Ltd
  5. *************************************************************************
  6. This product is distributed under commercial license that can be found
  7. from the product package on license.pdf. Use of this product might
  8. require purchasing a commercial license from IT Mill Ltd. For guidelines
  9. on usage, see licensing-guidelines.html
  10. *************************************************************************
  11. For more information, contact:
  12. IT Mill Ltd phone: +358 2 4802 7180
  13. Ruukinkatu 2-4 fax: +358 2 4802 7181
  14. 20540, Turku email: info@itmill.com
  15. Finland company www: www.itmill.com
  16. Primary source for information and releases: www.itmill.com
  17. ********************************************************************** */
  18. package com.itmill.toolkit.ui;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.Iterator;
  22. import java.util.LinkedList;
  23. import java.util.Map;
  24. import com.itmill.toolkit.terminal.PaintException;
  25. import com.itmill.toolkit.terminal.PaintTarget;
  26. import com.itmill.toolkit.terminal.Sizeable;
  27. /**
  28. * <p>
  29. * A container that consists of components with certain coordinates (cell
  30. * position) on a grid. It also maintains cursor for adding component in left to
  31. * right, top to bottom order.
  32. * </p>
  33. *
  34. * <p>
  35. * Each component in a <code>GridLayout</code> uses a certain
  36. * {@link GridLayout.Area area} (column1,row1,column2,row2) from the grid. One
  37. * should not add components that would overlap with the existing components
  38. * because in such case an {@link OverlapsException} is thrown. Adding component
  39. * with cursor automatically extends the grid by increasing the grid height.
  40. * </p>
  41. *
  42. * @author IT Mill Ltd.
  43. * @version
  44. * @VERSION@
  45. * @since 3.0
  46. */
  47. public class GridLayout extends AbstractLayout {
  48. /**
  49. * Initial grid columns.
  50. */
  51. private int cols = 0;
  52. /**
  53. * Initial grid rows.
  54. */
  55. private int rows = 0;
  56. /**
  57. * Cursor X position: this is where the next component with unspecified x,y
  58. * is inserted
  59. */
  60. private int cursorX = 0;
  61. /**
  62. * Cursor Y position: this is where the next component with unspecified x,y
  63. * is inserted
  64. */
  65. private int cursorY = 0;
  66. /**
  67. * Contains all items that are placed on the grid. These are components with
  68. * grid area definition.
  69. */
  70. private LinkedList areas = new LinkedList();
  71. /**
  72. * Mapping from components to their respective areas.
  73. */
  74. private LinkedList components = new LinkedList();
  75. /**
  76. * Mapping from components to alignments (horizontal + vertical).
  77. */
  78. private Map componentToAlignment = new HashMap();
  79. /**
  80. * Contained component should be aligned horizontally to the left.
  81. */
  82. private int ALIGNMENT_LEFT = 1;
  83. /**
  84. * Contained component should be aligned horizontally to the right.
  85. */
  86. private int ALIGNMENT_RIGHT = 2;
  87. /**
  88. * Contained component should be aligned vertically to the top.
  89. */
  90. private int ALIGNMENT_TOP = 4;
  91. /**
  92. * Contained component should be aligned vertically to the bottom.
  93. */
  94. private int ALIGNMENT_BOTTOM = 8;
  95. /**
  96. * Contained component should be horizontally aligned to center.
  97. */
  98. private int HORIZONTAL_ALIGNMENT_CENTER = 16;
  99. /**
  100. * Contained component should be vertically aligned to center.
  101. */
  102. private int VERTICAL_ALIGNMENT_CENTER = 32;
  103. /**
  104. * Is spacing between contained components enabled. Defaults to false.
  105. */
  106. private boolean spacing = false;
  107. /**
  108. * Constructor for grid of given size (number of cells). Note that grid's
  109. * final size depends on the items that are added into the grid. Grid grows
  110. * if you add components outside the grid's area.
  111. *
  112. * @param columns
  113. * Number of columns in the grid.
  114. * @param rows
  115. * Number of rows in the grid.
  116. */
  117. public GridLayout(int columns, int rows) {
  118. setColumns(columns);
  119. setRows(rows);
  120. }
  121. /**
  122. * Constructs an empty grid layout that is extended as needed.
  123. */
  124. public GridLayout() {
  125. this(1, 1);
  126. }
  127. /**
  128. * <p>
  129. * Adds a component with a specified area to the grid. The area the new
  130. * component should take is defined by specifying the upper left corner
  131. * (column1, row1) and the lower right corner (column2, row2) of the area.
  132. * </p>
  133. *
  134. * <p>
  135. * If the new component overlaps with any of the existing components already
  136. * present in the grid the operation will fail and an
  137. * {@link OverlapsException} is thrown.
  138. * </p>
  139. *
  140. * @param c
  141. * the component to be added.
  142. * @param column1
  143. * the column of the upper left corner of the area <code>c</code>
  144. * is supposed to occupy.
  145. * @param row1
  146. * the row of the upper left corner of the area <code>c</code>
  147. * is supposed to occupy.
  148. * @param column2
  149. * the column of the lower right corner of the area
  150. * <code>c</code> is supposed to occupy.
  151. * @param row2
  152. * the row of the lower right corner of the area <code>c</code>
  153. * is supposed to occupy.
  154. * @throws OverlapsException
  155. * if the new component overlaps with any of the components
  156. * already in the grid.
  157. * @throws OutOfBoundsException
  158. * if the cells are outside of the grid area.
  159. */
  160. public void addComponent(Component component, int column1, int row1,
  161. int column2, int row2) throws OverlapsException,
  162. OutOfBoundsException {
  163. if (component == null)
  164. throw new NullPointerException("Component must not be null");
  165. // Checks that the component does not already exist in the container
  166. if (components.contains(component))
  167. throw new IllegalArgumentException(
  168. "Component is already in the container");
  169. // Creates the area
  170. Area area = new Area(component, column1, row1, column2, row2);
  171. // Checks the validity of the coordinates
  172. if (column2 < column1 || row2 < row1)
  173. throw new IllegalArgumentException(
  174. "Illegal coordinates for the component");
  175. if (column1 < 0 || row1 < 0 || column2 >= cols || row2 >= rows)
  176. throw new OutOfBoundsException(area);
  177. // Checks that newItem does not overlap with existing items
  178. checkExistingOverlaps(area);
  179. // Inserts the component to right place at the list
  180. // Respect top-down, left-right ordering
  181. component.setParent(this);
  182. Iterator i = areas.iterator();
  183. int index = 0;
  184. boolean done = false;
  185. while (!done && i.hasNext()) {
  186. Area existingArea = (Area) i.next();
  187. if ((existingArea.row1 >= row1 && existingArea.column1 > column1)
  188. || existingArea.row1 > row1) {
  189. areas.add(index, area);
  190. components.add(index, component);
  191. done = true;
  192. }
  193. index++;
  194. }
  195. if (!done) {
  196. areas.addLast(area);
  197. components.addLast(component);
  198. }
  199. super.addComponent(component);
  200. requestRepaint();
  201. }
  202. /**
  203. * Tests if the given area overlaps with any of the items already on the
  204. * grid.
  205. *
  206. * @param area
  207. * the Area to be checked for overlapping.
  208. * @throws OverlapsException
  209. * if <code>area</code> overlaps with any existing area.
  210. */
  211. private void checkExistingOverlaps(Area area) throws OverlapsException {
  212. for (Iterator i = areas.iterator(); i.hasNext();) {
  213. Area existingArea = (Area) i.next();
  214. if (existingArea.overlaps(area))
  215. // Component not added, overlaps with existing component
  216. throw new OverlapsException(existingArea);
  217. }
  218. }
  219. /**
  220. * Adds the component into this container to cells column1,row1 (NortWest
  221. * corner of the area.) End coordinates (SouthEast corner of the area) are
  222. * the same as column1,row1. Component width and height is 1.
  223. *
  224. * @param c
  225. * the component to be added.
  226. * @param column
  227. * the column index.
  228. * @param row
  229. * the row index.
  230. */
  231. public void addComponent(Component c, int column, int row) {
  232. this.addComponent(c, column, row, column, row);
  233. }
  234. /**
  235. * Force the next component to be added to the beginning of the next line.
  236. * By calling this function user can ensure that no more components are
  237. * added to the right of the previous component.
  238. *
  239. * @see #space()
  240. */
  241. public void newLine() {
  242. cursorX = 0;
  243. cursorY++;
  244. }
  245. /**
  246. * Moves the cursor forwards by one. If the cursor goes out of the right
  247. * grid border, move it to next line.
  248. *
  249. * @see #newLine()
  250. */
  251. public void space() {
  252. cursorX++;
  253. if (cursorX >= cols) {
  254. cursorX = 0;
  255. cursorY++;
  256. }
  257. }
  258. /**
  259. * Adds the component into this container to the cursor position. If the
  260. * cursor position is already occupied, the cursor is moved forwards to find
  261. * free position. If the cursor goes out from the bottom of the grid, the
  262. * grid is automatically extended.
  263. *
  264. * @param c
  265. * the component to be added.
  266. */
  267. public void addComponent(Component component) {
  268. // Finds first available place from the grid
  269. Area area;
  270. boolean done = false;
  271. while (!done)
  272. try {
  273. area = new Area(component, cursorX, cursorY, cursorX, cursorY);
  274. checkExistingOverlaps(area);
  275. done = true;
  276. } catch (OverlapsException ignored) {
  277. space();
  278. }
  279. // Extends the grid if needed
  280. cols = cursorX >= cols ? cursorX + 1 : cols;
  281. rows = cursorY >= rows ? cursorY + 1 : rows;
  282. addComponent(component, cursorX, cursorY);
  283. }
  284. /**
  285. * Removes the given component from this container.
  286. *
  287. * @param c
  288. * the component to be removed.
  289. */
  290. public void removeComponent(Component component) {
  291. // Check that the component is contained in the container
  292. if (component == null || !components.contains(component))
  293. return;
  294. super.removeComponent(component);
  295. Area area = null;
  296. for (Iterator i = areas.iterator(); area == null && i.hasNext();) {
  297. Area a = (Area) i.next();
  298. if (a.getComponent() == component)
  299. area = a;
  300. }
  301. components.remove(component);
  302. if (area != null)
  303. areas.remove(area);
  304. componentToAlignment.remove(component);
  305. requestRepaint();
  306. }
  307. /**
  308. * Removes the component specified with it's cell index.
  309. *
  310. * @param column
  311. * the Component's column.
  312. * @param row
  313. * the Component's row.
  314. */
  315. public void removeComponent(int column, int row) {
  316. // Finds the area
  317. for (Iterator i = areas.iterator(); i.hasNext();) {
  318. Area area = (Area) i.next();
  319. if (area.getColumn1() == column && area.getRow1() == row) {
  320. removeComponent(area.getComponent());
  321. return;
  322. }
  323. }
  324. }
  325. /**
  326. * Gets an Iterator to the component container contents. Using the Iterator
  327. * it's possible to step through the contents of the container.
  328. *
  329. * @return the Iterator of the components inside the container.
  330. */
  331. public Iterator getComponentIterator() {
  332. return Collections.unmodifiableCollection(components).iterator();
  333. }
  334. /**
  335. * Paints the contents of this component.
  336. *
  337. * @param target
  338. * the Paint Event.
  339. * @throws PaintException
  340. * if the paint operation failed.
  341. */
  342. public void paintContent(PaintTarget target) throws PaintException {
  343. super.paintContent(target);
  344. // TODO refactor attribute names in future release.
  345. target.addAttribute("rows", rows);
  346. target.addAttribute("cols", cols);
  347. if (this.spacing)
  348. target.addAttribute("spacing", this.spacing);
  349. // Area iterator
  350. Iterator areaiterator = areas.iterator();
  351. // Current item to be processed (fetch first item)
  352. Area area = areaiterator.hasNext() ? (Area) areaiterator.next() : null;
  353. // Collects rowspan related information here
  354. HashMap cellUsed = new HashMap();
  355. // Empty cell collector
  356. int emptyCells = 0;
  357. // Iterates every applicable row
  358. for (int cury = 0; cury < rows; cury++) {
  359. target.startTag("gr");
  360. // Iterates every applicable column
  361. for (int curx = 0; curx < cols; curx++) {
  362. // Checks if current item is located at curx,cury
  363. if (area != null && (area.row1 == cury)
  364. && (area.column1 == curx)) {
  365. // First check if empty cell needs to be rendered
  366. if (emptyCells > 0) {
  367. target.startTag("gc");
  368. target.addAttribute("x", curx - emptyCells);
  369. target.addAttribute("y", cury);
  370. if (emptyCells > 1) {
  371. target.addAttribute("w", emptyCells);
  372. }
  373. target.endTag("gc");
  374. emptyCells = 0;
  375. }
  376. // Now proceed rendering current item
  377. int cols = (area.column2 - area.column1) + 1;
  378. int rows = (area.row2 - area.row1) + 1;
  379. target.startTag("gc");
  380. target.addAttribute("x", curx);
  381. target.addAttribute("y", cury);
  382. if (cols > 1) {
  383. target.addAttribute("w", cols);
  384. }
  385. if (rows > 1) {
  386. target.addAttribute("h", rows);
  387. }
  388. area.getComponent().paint(target);
  389. target.endTag("gc");
  390. // Fetch next item
  391. if (areaiterator.hasNext()) {
  392. area = (Area) areaiterator.next();
  393. } else {
  394. area = null;
  395. }
  396. // Updates the cellUsed if rowspan needed
  397. if (rows > 1) {
  398. int spannedx = curx;
  399. for (int j = 1; j <= cols; j++) {
  400. cellUsed.put(new Integer(spannedx), new Integer(
  401. cury + rows - 1));
  402. spannedx++;
  403. }
  404. }
  405. // Skips the current item's spanned columns
  406. if (cols > 1) {
  407. curx += cols - 1;
  408. }
  409. } else {
  410. // Checks against cellUsed, render space or ignore cell
  411. if (cellUsed.containsKey(new Integer(curx))) {
  412. // Current column contains already an item,
  413. // check if rowspan affects at current x,y position
  414. int rowspanDepth = ((Integer) cellUsed.get(new Integer(
  415. curx))).intValue();
  416. if (rowspanDepth >= cury) {
  417. // ignore cell
  418. // Check if empty cell needs to be rendered
  419. if (emptyCells > 0) {
  420. target.startTag("gc");
  421. target.addAttribute("x", curx - emptyCells);
  422. target.addAttribute("y", cury);
  423. if (emptyCells > 1) {
  424. target.addAttribute("w", emptyCells);
  425. }
  426. target.endTag("gc");
  427. emptyCells = 0;
  428. }
  429. } else {
  430. // empty cell is needed
  431. emptyCells++;
  432. // Removes the cellUsed key as it has become
  433. // obsolete
  434. cellUsed.remove(new Integer(curx));
  435. }
  436. } else {
  437. // empty cell is needed
  438. emptyCells++;
  439. }
  440. }
  441. } // iterates every column
  442. // Last column handled of current row
  443. // Checks if empty cell needs to be rendered
  444. if (emptyCells > 0) {
  445. target.startTag("gc");
  446. target.addAttribute("x", cols - emptyCells);
  447. target.addAttribute("y", cury);
  448. if (emptyCells > 1) {
  449. target.addAttribute("w", emptyCells);
  450. }
  451. target.endTag("gc");
  452. emptyCells = 0;
  453. }
  454. target.endTag("gr");
  455. } // iterates every row
  456. // Last row handled
  457. }
  458. /**
  459. * Gets the components UIDL tag.
  460. *
  461. * @return the Component UIDL tag as string.
  462. * @see com.itmill.toolkit.ui.AbstractComponent#getTag()
  463. */
  464. public String getTag() {
  465. return "gridlayout";
  466. }
  467. /**
  468. * This class defines an area on a grid. An Area is defined by the cells of
  469. * its upper left corner (column1,row1) and lower right corner
  470. * (column2,row2).
  471. *
  472. * @author IT Mill Ltd.
  473. * @version
  474. * @VERSION@
  475. * @since 3.0
  476. */
  477. public class Area {
  478. /**
  479. * The column of the upper left corner cell of the area.
  480. */
  481. private int column1;
  482. /**
  483. * The row of the upper left corner cell of the area.
  484. */
  485. private int row1;
  486. /**
  487. * The column of the lower right corner cell of the area.
  488. */
  489. private int column2;
  490. /**
  491. * The row of the lower right corner cell of the area.
  492. */
  493. private int row2;
  494. /**
  495. * Component painted on the area.
  496. */
  497. private Component component;
  498. /**
  499. * <p>
  500. * Construct a new area on a grid.
  501. * </p>
  502. *
  503. * @param component
  504. * the component connected to the area.
  505. * @param column1
  506. * The column of the upper left corner cell of the area
  507. * <code>c</code> is supposed to occupy.
  508. * @param row1
  509. * The row of the upper left corner cell of the area
  510. * <code>c</code> is supposed to occupy.
  511. * @param column2
  512. * The column of the lower right corner cell of the area
  513. * <code>c</code> is supposed to occupy.
  514. * @param row2
  515. * The row of the lower right corner cell of the area
  516. * <code>c</code> is supposed to occupy.
  517. * @throws OverlapsException
  518. * if the new component overlaps with any of the components
  519. * already in the grid
  520. */
  521. public Area(Component component, int column1, int row1, int column2,
  522. int row2) {
  523. this.column1 = column1;
  524. this.row1 = row1;
  525. this.column2 = column2;
  526. this.row2 = row2;
  527. this.component = component;
  528. }
  529. /**
  530. * Tests if the given Area overlaps with an another Area.
  531. *
  532. * @param other
  533. * the Another Area that's to be tested for overlap with this
  534. * area.
  535. * @return <code>true</code> if <code>other</code> overlaps with
  536. * this area, <code>false</code> if it doesn't.
  537. */
  538. public boolean overlaps(Area other) {
  539. return column1 <= other.getColumn2() && row1 <= other.getRow2()
  540. && column2 >= other.getColumn1() && row2 >= other.getRow1();
  541. }
  542. /**
  543. * Gets the component connected to the area.
  544. *
  545. * @return the Component.
  546. */
  547. public Component getComponent() {
  548. return component;
  549. }
  550. /**
  551. * Sets the component connected to the area.
  552. *
  553. * <p>
  554. * This function only sets the value in the datastructure and does not
  555. * send any events or set parents.
  556. * </p>
  557. *
  558. * @param newComponent
  559. * the new connected overriding the existing one.
  560. */
  561. protected void setComponent(Component newComponent) {
  562. component = newComponent;
  563. }
  564. /**
  565. * @deprecated Use getColumn1() instead.
  566. *
  567. * @see com.itmill.toolkit.ui.GridLayout#getColumn1()
  568. */
  569. public int getX1() {
  570. return getColumn1();
  571. }
  572. /**
  573. * Gets the column of the top-left corner cell.
  574. *
  575. * @return the column of the top-left corner cell.
  576. */
  577. public int getColumn1() {
  578. return column1;
  579. }
  580. /**
  581. * @deprecated Use getColumn2() instead.
  582. *
  583. * @see com.itmill.toolkit.ui.GridLayout#getColumn2()
  584. */
  585. public int getX2() {
  586. return getColumn2();
  587. }
  588. /**
  589. * Gets the column of the bottom-right corner cell.
  590. *
  591. * @return the column of the bottom-right corner cell.
  592. */
  593. public int getColumn2() {
  594. return column2;
  595. }
  596. /**
  597. * @deprecated Use getRow1() instead.
  598. *
  599. * @see com.itmill.toolkit.ui.GridLayout#getRow1()
  600. */
  601. public int getY1() {
  602. return getRow1();
  603. }
  604. /**
  605. * Gets the row of the top-left corner cell.
  606. *
  607. * @return the row of the top-left corner cell.
  608. */
  609. public int getRow1() {
  610. return row1;
  611. }
  612. /**
  613. * @deprecated Use getRow2() instead.
  614. *
  615. * @see com.itmill.toolkit.ui.GridLayout#getRow2()
  616. */
  617. public int getY2() {
  618. return getRow2();
  619. }
  620. /**
  621. * Gets the row of the bottom-right corner cell.
  622. *
  623. * @return the row of the bottom-right corner cell.
  624. */
  625. public int getRow2() {
  626. return row2;
  627. }
  628. }
  629. /**
  630. * An <code>Exception</code> object which is thrown when two Items occupy
  631. * the same space on a grid.
  632. *
  633. * @author IT Mill Ltd.
  634. * @version
  635. * @VERSION@
  636. * @since 3.0
  637. */
  638. public class OverlapsException extends java.lang.RuntimeException {
  639. /**
  640. * Serial generated by eclipse.
  641. */
  642. private static final long serialVersionUID = 3978144339870101561L;
  643. private Area existingArea;
  644. /**
  645. * Constructs an <code>OverlapsException</code>.
  646. *
  647. * @param existingArea
  648. */
  649. public OverlapsException(Area existingArea) {
  650. this.existingArea = existingArea;
  651. }
  652. /**
  653. * Gets the area .
  654. *
  655. * @return the existing area.
  656. */
  657. public Area getArea() {
  658. return existingArea;
  659. }
  660. }
  661. /**
  662. * An <code>Exception</code> object which is thrown when an area exceeds
  663. * the bounds of the grid.
  664. *
  665. * @author IT Mill Ltd.
  666. * @version
  667. * @VERSION@
  668. * @since 3.0
  669. */
  670. public class OutOfBoundsException extends java.lang.RuntimeException {
  671. /**
  672. * Serial generated by eclipse.
  673. */
  674. private static final long serialVersionUID = 3618985589664592694L;
  675. private Area areaOutOfBounds;
  676. /**
  677. * Constructs an <code>OoutOfBoundsException</code> with the specified
  678. * detail message.
  679. *
  680. * @param areaOutOfBounds
  681. */
  682. public OutOfBoundsException(Area areaOutOfBounds) {
  683. this.areaOutOfBounds = areaOutOfBounds;
  684. }
  685. /**
  686. * Gets the area that is out of bounds.
  687. *
  688. * @return the area out of Bound.
  689. */
  690. public Area getArea() {
  691. return areaOutOfBounds;
  692. }
  693. }
  694. /**
  695. * Sets the width of the layout.
  696. * <p>
  697. * <strong>NOTE:</strong> The behaviour of this methdod has changed in
  698. * version 5.0. Now this method won't set the number of columns in the grid
  699. * like it used to (use {@link #setColumns()} for that). Instead, it sets
  700. * the actual visual width of the layout in pixels or in another unit
  701. * specified in {@link Sizeable}.UNIT_SYMBOLS.
  702. * </p>
  703. */
  704. public void setWidth(int width) {
  705. super.setWidth(width);
  706. }
  707. /**
  708. * Gets the width of the layout.
  709. * <p>
  710. * <strong>NOTE:</strong> The behaviour of this methdod has changed in
  711. * version 5.0. Now this method won't return the number of columns in the
  712. * grid like it used to (use {@link #getColumns()} for that). Instead, it
  713. * returns the actual visual width of the layout in pixels or in another
  714. * unit specified in {@link Sizeable}.UNIT_SYMBOLS.
  715. * </p>
  716. */
  717. public int getWidth() {
  718. return super.getWidth();
  719. }
  720. /**
  721. * Sets the number of columns in the grid. The column count can not be
  722. * reduced if there are any areas that would be outside of the shrunk grid.
  723. *
  724. * @param columns
  725. * the new number of columns in the grid.
  726. */
  727. public void setColumns(int columns) {
  728. // The the param
  729. if (columns < 1)
  730. throw new IllegalArgumentException(
  731. "The number of columns and rows in the grid must be at least 1");
  732. // In case of no change
  733. if (this.cols == columns)
  734. return;
  735. // Checks for overlaps
  736. if (this.cols > columns)
  737. for (Iterator i = areas.iterator(); i.hasNext();) {
  738. Area area = (Area) i.next();
  739. if (area.column2 >= columns)
  740. throw new OutOfBoundsException(area);
  741. }
  742. this.cols = columns;
  743. requestRepaint();
  744. }
  745. /**
  746. * Get the number of columns in the grid.
  747. *
  748. * @return the number of columns in the grid.
  749. */
  750. public final int getColumns() {
  751. return this.cols;
  752. }
  753. /**
  754. * Set the height of the layout.
  755. * <p>
  756. * <strong>NOTE:</strong> The behaviour of this methdod has changed in
  757. * version 5.0. Now this method won't set the number of rows in the grid
  758. * like it used to (use {@link #setRows()} for that). Instead, it sets the
  759. * actual visual height of the layout in pixels or in another unit specified
  760. * in {@link Sizeable}.UNIT_SYMBOLS.
  761. * </p>
  762. */
  763. public void setHeight(int height) {
  764. super.setHeight(height);
  765. }
  766. /**
  767. * Gets the height of the layout.
  768. * <p>
  769. * <strong>NOTE:</strong> The behaviour of this methdod has changed in
  770. * version 5.0. Now this method won't return the number of rows in the grid
  771. * like it used to (use {@link #getRows()} for that). Instead, it returns
  772. * the actual visual height of the layout in pixels or in another unit
  773. * specified in {@link Sizeable}.UNIT_SYMBOLS.
  774. * </p>
  775. */
  776. public int getHeight() {
  777. return super.getHeight();
  778. }
  779. /**
  780. * Sets the number of rows in the grid. The number of rows can not be
  781. * reduced if there are any areas that would be outside of the shrunk grid.
  782. *
  783. * @param rows
  784. * the new number of rows in the grid.
  785. */
  786. public void setRows(int rows) {
  787. // The the param
  788. if (rows < 1)
  789. throw new IllegalArgumentException(
  790. "The number of columns and rows in the grid must be at least 1");
  791. // In case of no change
  792. if (this.rows == rows)
  793. return;
  794. // Checks for overlaps
  795. if (this.rows > rows)
  796. for (Iterator i = areas.iterator(); i.hasNext();) {
  797. Area area = (Area) i.next();
  798. if (area.row2 >= rows)
  799. throw new OutOfBoundsException(area);
  800. }
  801. this.rows = rows;
  802. requestRepaint();
  803. }
  804. /**
  805. * Get the number of rows in the grid.
  806. *
  807. * @return the number of rows in the grid.
  808. */
  809. public final int getRows() {
  810. return this.rows;
  811. }
  812. /**
  813. * Gets the current cursor x-position. The cursor position points the
  814. * position for the next component that is added without specifying its
  815. * coordinates (grid cell). When the cursor position is occupied, the next
  816. * component will be added to first free position after the cursor.
  817. *
  818. * @return the grid column the Cursor is on.
  819. */
  820. public int getCursorX() {
  821. return cursorX;
  822. }
  823. /**
  824. * Gets the current cursor y-position. The cursor position points the
  825. * position for the next component that is added without specifying its
  826. * coordinates (grid cell). When the cursor position is occupied, the next
  827. * component will be added to first free position after the cursor.
  828. *
  829. * @return the grid row the Cursor is on.
  830. */
  831. public int getCursorY() {
  832. return cursorY;
  833. }
  834. /* Documented in superclass */
  835. public void replaceComponent(Component oldComponent, Component newComponent) {
  836. // Gets the locations
  837. Area oldLocation = null;
  838. Area newLocation = null;
  839. for (Iterator i = areas.iterator(); i.hasNext();) {
  840. Area location = (Area) i.next();
  841. Component component = (Component) location.getComponent();
  842. if (component == oldComponent)
  843. oldLocation = location;
  844. if (component == newComponent)
  845. newLocation = location;
  846. }
  847. if (oldLocation == null)
  848. addComponent(newComponent);
  849. else if (newLocation == null) {
  850. removeComponent(oldComponent);
  851. addComponent(newComponent, oldLocation.getColumn1(), oldLocation
  852. .getRow1(), oldLocation.getColumn2(), oldLocation.getRow2());
  853. } else {
  854. oldLocation.setComponent(newComponent);
  855. newLocation.setComponent(oldComponent);
  856. requestRepaint();
  857. }
  858. }
  859. /*
  860. * Removes all components from this container.
  861. *
  862. * @see com.itmill.toolkit.ui.ComponentContainer#removeAllComponents()
  863. */
  864. public void removeAllComponents() {
  865. super.removeAllComponents();
  866. this.componentToAlignment = new HashMap();
  867. this.cursorX = 0;
  868. this.cursorY = 0;
  869. }
  870. /**
  871. * Set alignment for one contained component in this layout.
  872. *
  873. * @param childComponent
  874. * the component to align within it's layout cell.
  875. * @param horizontalAlignment
  876. * the horizontal alignment for the child component (left,
  877. * center, right).
  878. * @param verticalAlignment
  879. * the vertical alignment for the child component (top, center,
  880. * bottom).
  881. */
  882. public void setComponentAlignment(Component childComponent,
  883. int horizontalAlignment, int verticalAlignment) {
  884. componentToAlignment.put(childComponent, new Integer(
  885. horizontalAlignment + verticalAlignment));
  886. }
  887. /**
  888. * Enable spacing between child components within this layout.
  889. *
  890. * <p>
  891. * <strong>NOTE:</strong> This will only affect spaces between components,
  892. * not also all around spacing of the layout (i.e. do not mix this with HTML
  893. * Table elements cellspacing-attribute). Use {@link #setMargin(boolean)} to
  894. * add extra space around the layout.
  895. * </p>
  896. *
  897. * @param enabled
  898. */
  899. public void setSpacing(boolean enabled) {
  900. this.spacing = enabled;
  901. }
  902. }