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.

VGridLayout.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui;
  17. import java.util.HashMap;
  18. import java.util.LinkedList;
  19. import java.util.List;
  20. import java.util.Set;
  21. import com.google.gwt.dom.client.DivElement;
  22. import com.google.gwt.dom.client.Document;
  23. import com.google.gwt.dom.client.Element;
  24. import com.google.gwt.dom.client.Style;
  25. import com.google.gwt.dom.client.Style.Position;
  26. import com.google.gwt.dom.client.Style.Unit;
  27. import com.google.gwt.user.client.DOM;
  28. import com.google.gwt.user.client.ui.ComplexPanel;
  29. import com.google.gwt.user.client.ui.Widget;
  30. import com.vaadin.client.ApplicationConnection;
  31. import com.vaadin.client.ComponentConnector;
  32. import com.vaadin.client.ConnectorMap;
  33. import com.vaadin.client.LayoutManager;
  34. import com.vaadin.client.StyleConstants;
  35. import com.vaadin.client.Util;
  36. import com.vaadin.client.VCaption;
  37. import com.vaadin.client.ui.gridlayout.GridLayoutConnector;
  38. import com.vaadin.client.ui.layout.ComponentConnectorLayoutSlot;
  39. import com.vaadin.client.ui.layout.VLayoutSlot;
  40. import com.vaadin.shared.ui.AlignmentInfo;
  41. import com.vaadin.shared.ui.MarginInfo;
  42. import com.vaadin.shared.ui.gridlayout.GridLayoutState.ChildComponentData;
  43. public class VGridLayout extends ComplexPanel {
  44. public static final String CLASSNAME = "v-gridlayout";
  45. /** For internal use only. May be removed or replaced in the future. */
  46. public ApplicationConnection client;
  47. /** For internal use only. May be removed or replaced in the future. */
  48. public HashMap<Widget, Cell> widgetToCell = new HashMap<Widget, Cell>();
  49. /** For internal use only. May be removed or replaced in the future. */
  50. public int[] columnWidths;
  51. /** For internal use only. May be removed or replaced in the future. */
  52. public int[] rowHeights;
  53. /** For internal use only. May be removed or replaced in the future. */
  54. public int[] colExpandRatioArray;
  55. /** For internal use only. May be removed or replaced in the future. */
  56. public int[] rowExpandRatioArray;
  57. int[] minColumnWidths;
  58. private int[] minRowHeights;
  59. /** For internal use only. May be removed or replaced in the future. */
  60. public DivElement spacingMeasureElement;
  61. public Set<Integer> explicitRowRatios;
  62. public Set<Integer> explicitColRatios;
  63. public boolean hideEmptyRowsAndColumns = false;
  64. public VGridLayout() {
  65. super();
  66. setElement(Document.get().createDivElement());
  67. spacingMeasureElement = Document.get().createDivElement();
  68. Style spacingStyle = spacingMeasureElement.getStyle();
  69. spacingStyle.setPosition(Position.ABSOLUTE);
  70. getElement().appendChild(spacingMeasureElement);
  71. setStyleName(CLASSNAME);
  72. addStyleName(StyleConstants.UI_LAYOUT);
  73. }
  74. private GridLayoutConnector getConnector() {
  75. return (GridLayoutConnector) ConnectorMap.get(client)
  76. .getConnector(this);
  77. }
  78. /**
  79. * Returns the column widths measured in pixels
  80. *
  81. * @return
  82. */
  83. protected int[] getColumnWidths() {
  84. return columnWidths;
  85. }
  86. /**
  87. * Returns the row heights measured in pixels
  88. *
  89. * @return
  90. */
  91. protected int[] getRowHeights() {
  92. return rowHeights;
  93. }
  94. /**
  95. * Returns the spacing between the cells horizontally in pixels
  96. *
  97. * @return
  98. */
  99. protected int getHorizontalSpacing() {
  100. return LayoutManager.get(client).getOuterWidth(spacingMeasureElement);
  101. }
  102. /**
  103. * Returns the spacing between the cells vertically in pixels
  104. *
  105. * @return
  106. */
  107. protected int getVerticalSpacing() {
  108. return LayoutManager.get(client).getOuterHeight(spacingMeasureElement);
  109. }
  110. static int[] cloneArray(int[] toBeCloned) {
  111. int[] clone = new int[toBeCloned.length];
  112. for (int i = 0; i < clone.length; i++) {
  113. clone[i] = toBeCloned[i] * 1;
  114. }
  115. return clone;
  116. }
  117. void expandRows() {
  118. if (!isUndefinedHeight()) {
  119. int usedSpace = calcRowUsedSpace();
  120. int[] actualExpandRatio = calcRowExpandRatio();
  121. int availableSpace = LayoutManager.get(client).getInnerHeight(
  122. getElement());
  123. int excessSpace = availableSpace - usedSpace;
  124. int distributed = 0;
  125. if (excessSpace > 0) {
  126. int expandRatioSum = 0;
  127. for (int i = 0; i < rowHeights.length; i++) {
  128. expandRatioSum += actualExpandRatio[i];
  129. }
  130. for (int i = 0; i < rowHeights.length; i++) {
  131. int ew = excessSpace * actualExpandRatio[i]
  132. / expandRatioSum;
  133. rowHeights[i] = minRowHeights[i] + ew;
  134. distributed += ew;
  135. }
  136. excessSpace -= distributed;
  137. int c = 0;
  138. while (excessSpace > 0) {
  139. rowHeights[c % rowHeights.length]++;
  140. excessSpace--;
  141. c++;
  142. }
  143. }
  144. }
  145. }
  146. private int[] calcRowExpandRatio() {
  147. int[] actualExpandRatio = new int[minRowHeights.length];
  148. for (int i = 0; i < minRowHeights.length; i++) {
  149. if (hiddenEmptyRow(i)) {
  150. actualExpandRatio[i] = 0;
  151. } else {
  152. actualExpandRatio[i] = rowExpandRatioArray[i];
  153. }
  154. }
  155. return actualExpandRatio;
  156. }
  157. /**
  158. * Checks if it is ok to hide (or ignore) the given row.
  159. *
  160. * @param rowIndex
  161. * the row to check
  162. * @return true, if the row should be interpreted as non-existant (hides
  163. * extra spacing)
  164. */
  165. private boolean hiddenEmptyRow(int rowIndex) {
  166. return hideEmptyRowsAndColumns && !rowHasComponentsOrRowSpan(rowIndex)
  167. && !explicitRowRatios.contains(rowIndex);
  168. }
  169. /**
  170. * Checks if it is ok to hide (or ignore) the given column.
  171. *
  172. * @param columnIndex
  173. * the column to check
  174. * @return true, if the column should be interpreted as non-existant (hides
  175. * extra spacing)
  176. */
  177. private boolean hiddenEmptyColumn(int columnIndex) {
  178. return hideEmptyRowsAndColumns
  179. && !colHasComponentsOrColSpan(columnIndex)
  180. && !explicitColRatios.contains(columnIndex);
  181. }
  182. private int calcRowUsedSpace() {
  183. int usedSpace = minRowHeights[0];
  184. int verticalSpacing = getVerticalSpacing();
  185. for (int i = 1; i < minRowHeights.length; i++) {
  186. if (minRowHeights[i] > 0 || !hiddenEmptyRow(i)) {
  187. usedSpace += verticalSpacing + minRowHeights[i];
  188. }
  189. }
  190. return usedSpace;
  191. }
  192. void expandColumns() {
  193. if (!isUndefinedWidth()) {
  194. int usedSpace = calcColumnUsedSpace();
  195. int[] actualExpandRatio = calcColumnExpandRatio();
  196. int availableSpace = LayoutManager.get(client).getInnerWidth(
  197. getElement());
  198. int excessSpace = availableSpace - usedSpace;
  199. int distributed = 0;
  200. if (excessSpace > 0) {
  201. int expandRatioSum = 0;
  202. for (int i = 0; i < columnWidths.length; i++) {
  203. expandRatioSum += actualExpandRatio[i];
  204. }
  205. for (int i = 0; i < columnWidths.length; i++) {
  206. int ew = excessSpace * actualExpandRatio[i]
  207. / expandRatioSum;
  208. columnWidths[i] = minColumnWidths[i] + ew;
  209. distributed += ew;
  210. }
  211. excessSpace -= distributed;
  212. int c = 0;
  213. while (excessSpace > 0) {
  214. columnWidths[c % columnWidths.length]++;
  215. excessSpace--;
  216. c++;
  217. }
  218. }
  219. }
  220. }
  221. /**
  222. * Calculates column expand ratio.
  223. */
  224. private int[] calcColumnExpandRatio() {
  225. int[] actualExpandRatio = new int[minColumnWidths.length];
  226. for (int i = 0; i < minColumnWidths.length; i++) {
  227. if (!hiddenEmptyColumn(i)) {
  228. actualExpandRatio[i] = colExpandRatioArray[i];
  229. } else {
  230. actualExpandRatio[i] = 0;
  231. }
  232. }
  233. return actualExpandRatio;
  234. }
  235. /**
  236. * Calculates column used space
  237. */
  238. private int calcColumnUsedSpace() {
  239. int usedSpace = minColumnWidths[0];
  240. int horizontalSpacing = getHorizontalSpacing();
  241. for (int i = 1; i < minColumnWidths.length; i++) {
  242. if (minColumnWidths[i] > 0 || !hiddenEmptyColumn(i)) {
  243. usedSpace += horizontalSpacing + minColumnWidths[i];
  244. }
  245. }
  246. return usedSpace;
  247. }
  248. private boolean rowHasComponentsOrRowSpan(int i) {
  249. for (Cell cell : widgetToCell.values()) {
  250. if (cell.row == i) {
  251. return true;
  252. }
  253. }
  254. for (SpanList l : rowSpans) {
  255. for (Cell cell : l.cells) {
  256. if (cell.row <= i && i < cell.row + cell.rowspan) {
  257. return true;
  258. }
  259. }
  260. }
  261. return false;
  262. }
  263. private boolean colHasComponentsOrColSpan(int i) {
  264. for (Cell cell : widgetToCell.values()) {
  265. if (cell.col == i) {
  266. return true;
  267. }
  268. }
  269. for (SpanList l : colSpans) {
  270. for (Cell cell : l.cells) {
  271. if (cell.col <= i && i < cell.col + cell.colspan) {
  272. return true;
  273. }
  274. }
  275. }
  276. return false;
  277. }
  278. /** For internal use only. May be removed or replaced in the future. */
  279. public void updateHeight() {
  280. // Detect minimum heights & calculate spans
  281. detectRowHeights();
  282. // Expand
  283. expandRows();
  284. // Position
  285. layoutCellsVertically();
  286. }
  287. /** For internal use only. May be removed or replaced in the future. */
  288. public void updateWidth() {
  289. // Detect widths & calculate spans
  290. detectColWidths();
  291. // Expand
  292. expandColumns();
  293. // Position
  294. layoutCellsHorizontally();
  295. }
  296. void layoutCellsVertically() {
  297. int verticalSpacing = getVerticalSpacing();
  298. LayoutManager layoutManager = LayoutManager.get(client);
  299. Element element = getElement();
  300. int paddingTop = layoutManager.getPaddingTop(element);
  301. int paddingBottom = layoutManager.getPaddingBottom(element);
  302. int y = paddingTop;
  303. for (int column = 0; column < cells.length; column++) {
  304. y = paddingTop + 1 - 1; // Ensure IE10 does not optimize this out by
  305. // adding something to evaluate on the RHS
  306. // #11303
  307. for (int row = 0; row < cells[column].length; row++) {
  308. Cell cell = cells[column][row];
  309. if (cell != null) {
  310. int reservedMargin;
  311. if (cell.rowspan + row >= cells[column].length) {
  312. // Make room for layout padding for cells reaching the
  313. // bottom of the layout
  314. reservedMargin = paddingBottom;
  315. } else {
  316. reservedMargin = 0;
  317. }
  318. cell.layoutVertically(y, reservedMargin);
  319. }
  320. if (!hideEmptyRowsAndColumns || rowHasComponentsOrRowSpan(row)
  321. || rowHeights[row] > 0) {
  322. y += rowHeights[row] + verticalSpacing;
  323. }
  324. }
  325. }
  326. if (isUndefinedHeight()) {
  327. int outerHeight = y - verticalSpacing
  328. + layoutManager.getPaddingBottom(element)
  329. + layoutManager.getBorderHeight(element);
  330. element.getStyle().setHeight(outerHeight, Unit.PX);
  331. getConnector().getLayoutManager().reportOuterHeight(getConnector(),
  332. outerHeight);
  333. }
  334. }
  335. void layoutCellsHorizontally() {
  336. LayoutManager layoutManager = LayoutManager.get(client);
  337. Element element = getElement();
  338. int x = layoutManager.getPaddingLeft(element);
  339. int paddingRight = layoutManager.getPaddingRight(element);
  340. int horizontalSpacing = getHorizontalSpacing();
  341. for (int i = 0; i < cells.length; i++) {
  342. for (int j = 0; j < cells[i].length; j++) {
  343. Cell cell = cells[i][j];
  344. if (cell != null) {
  345. int reservedMargin;
  346. // Make room for layout padding for cells reaching the
  347. // right edge of the layout
  348. if (i + cell.colspan >= cells.length) {
  349. reservedMargin = paddingRight;
  350. } else {
  351. reservedMargin = 0;
  352. }
  353. cell.layoutHorizontally(x, reservedMargin);
  354. }
  355. }
  356. if (!hideEmptyRowsAndColumns || colHasComponentsOrColSpan(i)
  357. || columnWidths[i] > 0) {
  358. x += columnWidths[i] + horizontalSpacing;
  359. }
  360. }
  361. if (isUndefinedWidth()) {
  362. int outerWidth = x - horizontalSpacing
  363. + layoutManager.getPaddingRight(element)
  364. + layoutManager.getBorderWidth(element);
  365. element.getStyle().setWidth(outerWidth, Unit.PX);
  366. getConnector().getLayoutManager().reportOuterWidth(getConnector(),
  367. outerWidth);
  368. }
  369. }
  370. private boolean isUndefinedHeight() {
  371. return getConnector().isUndefinedHeight();
  372. }
  373. private boolean isUndefinedWidth() {
  374. return getConnector().isUndefinedWidth();
  375. }
  376. private void detectRowHeights() {
  377. for (int i = 0; i < rowHeights.length; i++) {
  378. rowHeights[i] = 0;
  379. }
  380. // collect min rowheight from non-rowspanned cells
  381. for (int i = 0; i < cells.length; i++) {
  382. for (int j = 0; j < cells[i].length; j++) {
  383. Cell cell = cells[i][j];
  384. if (cell != null) {
  385. if (cell.rowspan == 1) {
  386. if (!cell.hasRelativeHeight()
  387. && rowHeights[j] < cell.getHeight()) {
  388. rowHeights[j] = cell.getHeight();
  389. }
  390. } else {
  391. storeRowSpannedCell(cell);
  392. }
  393. }
  394. }
  395. }
  396. distributeRowSpanHeights();
  397. minRowHeights = cloneArray(rowHeights);
  398. }
  399. private void detectColWidths() {
  400. // collect min colwidths from non-colspanned cells
  401. for (int i = 0; i < columnWidths.length; i++) {
  402. columnWidths[i] = 0;
  403. }
  404. for (int i = 0; i < cells.length; i++) {
  405. for (int j = 0; j < cells[i].length; j++) {
  406. Cell cell = cells[i][j];
  407. if (cell != null) {
  408. if (cell.colspan == 1) {
  409. if (!cell.hasRelativeWidth()
  410. && columnWidths[i] < cell.getWidth()) {
  411. columnWidths[i] = cell.getWidth();
  412. }
  413. } else {
  414. storeColSpannedCell(cell);
  415. }
  416. }
  417. }
  418. }
  419. distributeColSpanWidths();
  420. minColumnWidths = cloneArray(columnWidths);
  421. }
  422. private void storeRowSpannedCell(Cell cell) {
  423. SpanList l = null;
  424. for (SpanList list : rowSpans) {
  425. if (list.span < cell.rowspan) {
  426. continue;
  427. } else {
  428. // insert before this
  429. l = list;
  430. break;
  431. }
  432. }
  433. if (l == null) {
  434. l = new SpanList(cell.rowspan);
  435. rowSpans.add(l);
  436. } else if (l.span != cell.rowspan) {
  437. SpanList newL = new SpanList(cell.rowspan);
  438. rowSpans.add(rowSpans.indexOf(l), newL);
  439. l = newL;
  440. }
  441. l.cells.add(cell);
  442. }
  443. /**
  444. * Iterates colspanned cells, ensures cols have enough space to accommodate
  445. * them
  446. */
  447. void distributeColSpanWidths() {
  448. for (SpanList list : colSpans) {
  449. for (Cell cell : list.cells) {
  450. // cells with relative content may return non 0 here if on
  451. // subsequent renders
  452. int width = cell.hasRelativeWidth() ? 0 : cell.getWidth();
  453. distributeSpanSize(columnWidths, cell.col, cell.colspan,
  454. getHorizontalSpacing(), width, colExpandRatioArray);
  455. }
  456. }
  457. }
  458. /**
  459. * Iterates rowspanned cells, ensures rows have enough space to accommodate
  460. * them
  461. */
  462. private void distributeRowSpanHeights() {
  463. for (SpanList list : rowSpans) {
  464. for (Cell cell : list.cells) {
  465. // cells with relative content may return non 0 here if on
  466. // subsequent renders
  467. int height = cell.hasRelativeHeight() ? 0 : cell.getHeight();
  468. distributeSpanSize(rowHeights, cell.row, cell.rowspan,
  469. getVerticalSpacing(), height, rowExpandRatioArray);
  470. }
  471. }
  472. }
  473. private static void distributeSpanSize(int[] dimensions,
  474. int spanStartIndex, int spanSize, int spacingSize, int size,
  475. int[] expansionRatios) {
  476. int allocated = dimensions[spanStartIndex];
  477. for (int i = 1; i < spanSize; i++) {
  478. allocated += spacingSize + dimensions[spanStartIndex + i];
  479. }
  480. if (allocated < size) {
  481. // dimensions needs to be expanded due spanned cell
  482. int neededExtraSpace = size - allocated;
  483. int allocatedExtraSpace = 0;
  484. // Divide space according to expansion ratios if any span has a
  485. // ratio
  486. int totalExpansion = 0;
  487. for (int i = 0; i < spanSize; i++) {
  488. int itemIndex = spanStartIndex + i;
  489. totalExpansion += expansionRatios[itemIndex];
  490. }
  491. for (int i = 0; i < spanSize; i++) {
  492. int itemIndex = spanStartIndex + i;
  493. int expansion;
  494. if (totalExpansion == 0) {
  495. // Divide equally among all cells if there are no
  496. // expansion ratios
  497. expansion = neededExtraSpace / spanSize;
  498. } else {
  499. expansion = neededExtraSpace * expansionRatios[itemIndex]
  500. / totalExpansion;
  501. }
  502. dimensions[itemIndex] += expansion;
  503. allocatedExtraSpace += expansion;
  504. }
  505. // We might still miss a couple of pixels because of
  506. // rounding errors...
  507. if (neededExtraSpace > allocatedExtraSpace) {
  508. for (int i = 0; i < spanSize; i++) {
  509. // Add one pixel to every cell until we have
  510. // compensated for any rounding error
  511. int itemIndex = spanStartIndex + i;
  512. dimensions[itemIndex] += 1;
  513. allocatedExtraSpace += 1;
  514. if (neededExtraSpace == allocatedExtraSpace) {
  515. break;
  516. }
  517. }
  518. }
  519. }
  520. }
  521. private LinkedList<SpanList> colSpans = new LinkedList<SpanList>();
  522. private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>();
  523. private class SpanList {
  524. final int span;
  525. List<Cell> cells = new LinkedList<Cell>();
  526. public SpanList(int span) {
  527. this.span = span;
  528. }
  529. }
  530. void storeColSpannedCell(Cell cell) {
  531. SpanList l = null;
  532. for (SpanList list : colSpans) {
  533. if (list.span < cell.colspan) {
  534. continue;
  535. } else {
  536. // insert before this
  537. l = list;
  538. break;
  539. }
  540. }
  541. if (l == null) {
  542. l = new SpanList(cell.colspan);
  543. colSpans.add(l);
  544. } else if (l.span != cell.colspan) {
  545. SpanList newL = new SpanList(cell.colspan);
  546. colSpans.add(colSpans.indexOf(l), newL);
  547. l = newL;
  548. }
  549. l.cells.add(cell);
  550. }
  551. Cell[][] cells;
  552. /**
  553. * Private helper class.
  554. */
  555. /** For internal use only. May be removed or replaced in the future. */
  556. public class Cell {
  557. public Cell(int row, int col) {
  558. this.row = row;
  559. this.col = col;
  560. }
  561. public boolean hasRelativeHeight() {
  562. if (slot != null) {
  563. return slot.getChild().isRelativeHeight();
  564. } else {
  565. return true;
  566. }
  567. }
  568. /**
  569. * @return total of spanned cols
  570. */
  571. private int getAvailableWidth() {
  572. int width = columnWidths[col];
  573. for (int i = 1; i < colspan; i++) {
  574. width += getHorizontalSpacing() + columnWidths[col + i];
  575. }
  576. return width;
  577. }
  578. /**
  579. * @return total of spanned rows
  580. */
  581. private int getAvailableHeight() {
  582. int height = rowHeights[row];
  583. for (int i = 1; i < rowspan; i++) {
  584. height += getVerticalSpacing() + rowHeights[row + i];
  585. }
  586. return height;
  587. }
  588. public void layoutHorizontally(int x, int marginRight) {
  589. if (slot != null) {
  590. slot.positionHorizontally(x, getAvailableWidth(), marginRight);
  591. }
  592. }
  593. public void layoutVertically(int y, int marginBottom) {
  594. if (slot != null) {
  595. slot.positionVertically(y, getAvailableHeight(), marginBottom);
  596. }
  597. }
  598. public int getWidth() {
  599. if (slot != null) {
  600. return slot.getUsedWidth();
  601. } else {
  602. return 0;
  603. }
  604. }
  605. public int getHeight() {
  606. if (slot != null) {
  607. return slot.getUsedHeight();
  608. } else {
  609. return 0;
  610. }
  611. }
  612. protected boolean hasRelativeWidth() {
  613. if (slot != null) {
  614. return slot.getChild().isRelativeWidth();
  615. } else {
  616. return true;
  617. }
  618. }
  619. private int row;
  620. private int col;
  621. int colspan = 1;
  622. int rowspan = 1;
  623. private AlignmentInfo alignment;
  624. /** For internal use only. May be removed or replaced in the future. */
  625. public ComponentConnectorLayoutSlot slot;
  626. public void updateCell(ChildComponentData childComponentData) {
  627. if (row != childComponentData.row1
  628. || col != childComponentData.column1) {
  629. // cell has been moved, update matrix
  630. if (col < cells.length && cells.length != 0
  631. && row < cells[0].length && cells[col][row] == this) {
  632. // Remove old reference if still relevant
  633. cells[col][row] = null;
  634. }
  635. row = childComponentData.row1;
  636. col = childComponentData.column1;
  637. cells[col][row] = this;
  638. }
  639. // Set cell width
  640. colspan = 1 + childComponentData.column2
  641. - childComponentData.column1;
  642. // Set cell height
  643. rowspan = 1 + childComponentData.row2 - childComponentData.row1;
  644. setAlignment(new AlignmentInfo(childComponentData.alignment));
  645. }
  646. public void setComponent(ComponentConnector component) {
  647. if (slot == null || slot.getChild() != component) {
  648. slot = new ComponentConnectorLayoutSlot(CLASSNAME, component,
  649. getConnector());
  650. slot.setAlignment(alignment);
  651. if (component.isRelativeWidth()) {
  652. slot.getWrapperElement().getStyle().setWidth(100, Unit.PCT);
  653. }
  654. Element slotWrapper = slot.getWrapperElement();
  655. getElement().appendChild(slotWrapper);
  656. Widget widget = component.getWidget();
  657. insert(widget, slotWrapper, getWidgetCount(), false);
  658. Cell oldCell = widgetToCell.put(widget, this);
  659. if (oldCell != null) {
  660. oldCell.slot.getWrapperElement().removeFromParent();
  661. oldCell.slot = null;
  662. }
  663. }
  664. }
  665. public void setAlignment(AlignmentInfo alignmentInfo) {
  666. alignment = alignmentInfo;
  667. if (slot != null) {
  668. slot.setAlignment(alignmentInfo);
  669. }
  670. }
  671. }
  672. /** For internal use only. May be removed or replaced in the future. */
  673. public Cell getCell(int row, int col) {
  674. return cells[col][row];
  675. }
  676. /**
  677. * Creates a new Cell with the given coordinates.
  678. * <p>
  679. * For internal use only. May be removed or replaced in the future.
  680. *
  681. * @param row
  682. * @param col
  683. * @return
  684. */
  685. public Cell createNewCell(int row, int col) {
  686. Cell cell = new Cell(row, col);
  687. cells[col][row] = cell;
  688. return cell;
  689. }
  690. /**
  691. * Returns the deepest nested child component which contains "element". The
  692. * child component is also returned if "element" is part of its caption.
  693. * <p>
  694. * For internal use only. May be removed or replaced in the future.
  695. *
  696. * @param element
  697. * An element that is a nested sub element of the root element in
  698. * this layout
  699. * @return The Paintable which the element is a part of. Null if the element
  700. * belongs to the layout and not to a child.
  701. * @deprecated As of 7.2, call or override {@link #getComponent(Element)}
  702. * instead
  703. */
  704. @Deprecated
  705. public ComponentConnector getComponent(
  706. com.google.gwt.user.client.Element element) {
  707. return Util.getConnectorForElement(client, this, element);
  708. }
  709. /**
  710. * Returns the deepest nested child component which contains "element". The
  711. * child component is also returned if "element" is part of its caption.
  712. * <p>
  713. * For internal use only. May be removed or replaced in the future.
  714. *
  715. * @param element
  716. * An element that is a nested sub element of the root element in
  717. * this layout
  718. * @return The Paintable which the element is a part of. Null if the element
  719. * belongs to the layout and not to a child.
  720. *
  721. * @since 7.2
  722. */
  723. public ComponentConnector getComponent(Element element) {
  724. return getComponent(DOM.asOld(element));
  725. }
  726. /** For internal use only. May be removed or replaced in the future. */
  727. public void setCaption(Widget widget, VCaption caption) {
  728. VLayoutSlot slot = widgetToCell.get(widget).slot;
  729. if (caption != null) {
  730. // Logical attach.
  731. getChildren().add(caption);
  732. }
  733. // Physical attach if not null, also removes old caption
  734. slot.setCaption(caption);
  735. if (caption != null) {
  736. // Adopt.
  737. adopt(caption);
  738. }
  739. }
  740. private void togglePrefixedStyleName(String name, boolean enabled) {
  741. if (enabled) {
  742. addStyleDependentName(name);
  743. } else {
  744. removeStyleDependentName(name);
  745. }
  746. }
  747. /** For internal use only. May be removed or replaced in the future. */
  748. public void updateMarginStyleNames(MarginInfo marginInfo) {
  749. togglePrefixedStyleName("margin-top", marginInfo.hasTop());
  750. togglePrefixedStyleName("margin-right", marginInfo.hasRight());
  751. togglePrefixedStyleName("margin-bottom", marginInfo.hasBottom());
  752. togglePrefixedStyleName("margin-left", marginInfo.hasLeft());
  753. }
  754. /** For internal use only. May be removed or replaced in the future. */
  755. public void updateSpacingStyleName(boolean spacingEnabled) {
  756. String styleName = getStylePrimaryName();
  757. if (spacingEnabled) {
  758. spacingMeasureElement.addClassName(styleName + "-spacing-on");
  759. spacingMeasureElement.removeClassName(styleName + "-spacing-off");
  760. } else {
  761. spacingMeasureElement.removeClassName(styleName + "-spacing-on");
  762. spacingMeasureElement.addClassName(styleName + "-spacing-off");
  763. }
  764. }
  765. public void setSize(int rows, int cols) {
  766. if (cells == null) {
  767. cells = new Cell[cols][rows];
  768. } else if (cells.length != cols || cells[0].length != rows) {
  769. Cell[][] newCells = new Cell[cols][rows];
  770. for (int i = 0; i < cells.length; i++) {
  771. for (int j = 0; j < cells[i].length; j++) {
  772. if (i < cols && j < rows) {
  773. newCells[i][j] = cells[i][j];
  774. }
  775. }
  776. }
  777. cells = newCells;
  778. }
  779. }
  780. @Override
  781. public boolean remove(Widget w) {
  782. boolean removed = super.remove(w);
  783. if (removed) {
  784. Cell cell = widgetToCell.remove(w);
  785. if (cell != null) {
  786. cell.slot.setCaption(null);
  787. cell.slot.getWrapperElement().removeFromParent();
  788. cell.slot = null;
  789. if (cells.length < cell.col && cells.length != 0
  790. && cells[0].length < cell.row
  791. && cells[cell.col][cell.row] == cell) {
  792. cells[cell.col][cell.row] = null;
  793. }
  794. }
  795. }
  796. return removed;
  797. }
  798. }