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 31KB

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