Advertisement
alishaik786

TableLayoutManager.java

Jan 25th, 2012
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.51 KB | None | 0 0
  1. package com.samplecode.startup;
  2.  
  3. import net.rim.device.api.ui.Field;
  4. import net.rim.device.api.ui.Manager;
  5. import net.rim.device.api.ui.XYPoint;
  6. import net.rim.device.api.util.Arrays;
  7.  
  8. /**
  9. * TableFieldManager can be used to create multi column table views. You can
  10. * even embedd table within another table to create complex tabular views.
  11. */
  12. public class TableLayoutManager extends Manager
  13. {
  14. int _columnWidths[];
  15. int _suggestedColumnWidths[];
  16. int _rowHeights[];
  17. int _columnStyles[];
  18.  
  19. /** Let the field use up ALL the space that it needs **/
  20. public static final int USE_PREFERRED_SIZE = 1;
  21. /** let the field use up as much space as it needs UP TO a maximum */
  22. public static final int USE_PREFERRED_WIDTH_WITH_MAXIMUM = 2;
  23. /** the fields should use up the remaining space evenly */
  24. public static final int SPLIT_REMAINING_WIDTH = 4;
  25. /** the column is fixed width **/
  26. public static final int FIXED_WIDTH = 8;
  27.  
  28. private static int BITMASK_USE_PREFERRED = USE_PREFERRED_WIDTH_WITH_MAXIMUM
  29. | USE_PREFERRED_SIZE;
  30.  
  31. public static int DEFAULT_PADDING = 5;
  32. int _rows;
  33. int _columns;
  34. private int _horizPadding;
  35.  
  36. public TableLayoutManager(int columnStyles[], long style)
  37. {
  38. this(columnStyles, null, DEFAULT_PADDING, style);
  39. }
  40.  
  41. /**
  42. * creates a table with the specified column styles
  43. *
  44. * @param columnStyles
  45. * - array of styles for all the columns. The size of this array
  46. * determines the number of columns.
  47. * @param columnWidths
  48. * - array of widths. This is used for the FIXED_WIDTH, and
  49. * USE_PREFERRED_WIDTH_WITH_MAXIMUM styles. the value is ignored
  50. * for the other styles.
  51. * @param horizontalPadding
  52. * - space between columns
  53. * @param style
  54. */
  55. public TableLayoutManager(int columnStyles[], int columnWidths[],
  56. int horizontalPadding, long style)
  57. {
  58. super(style);
  59.  
  60. _horizPadding = horizontalPadding;
  61.  
  62. _columnStyles = columnStyles;
  63. if (_columnStyles == null)
  64. throw new IllegalArgumentException("not column styles");
  65.  
  66. if (columnWidths != null)
  67. {
  68. _suggestedColumnWidths = Arrays.copy(columnWidths, 0,
  69. columnWidths.length);
  70. if (_suggestedColumnWidths.length < _columnStyles.length)
  71. {
  72. int oldLength = _suggestedColumnWidths.length;
  73. int increase = columnStyles.length - oldLength;
  74. _suggestedColumnWidths = Arrays.copy(columnWidths, 0,
  75. columnStyles.length);
  76. Arrays.fill(_suggestedColumnWidths, 0, oldLength, increase);
  77. }
  78. }
  79. else
  80. _suggestedColumnWidths = new int[_columnStyles.length];
  81. }
  82.  
  83. private Field getField(int x, int y)
  84. {
  85. int i = x + (y * _columns);
  86. if (i >= getFieldCount()) return null;
  87. return getField(i);
  88. }
  89.  
  90. private boolean isColumnStyle(int value, int flag)
  91. {
  92. return ((value) & (flag)) > 0;
  93. }
  94.  
  95. /**
  96. * Implements the getPreferredWidth call to return the expected width for
  97. * this manager. The expected width is the Max(Sum (Column Widths))
  98. */
  99. public int getPreferredWidth()
  100. {
  101. int numberFields = getFieldCount();
  102. if (numberFields == 0) return 0;
  103. int rows = numberFields / _columnStyles.length;
  104. int prefferedWidth = 0;
  105.  
  106. int styles[] = _columnStyles;
  107. int[] columnWidths = new int[_columns];
  108.  
  109. Arrays.fill(columnWidths, -1);
  110.  
  111. for (int i = 0; i < _columns; i++)
  112. {
  113. // assign the fixed widths
  114. if (isColumnStyle(styles[i], FIXED_WIDTH))
  115. {
  116. columnWidths[i] = _suggestedColumnWidths[i];
  117. }
  118. else
  119. {
  120. if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED))
  121. {
  122. for (int j = 0; j < rows; j++)
  123. {
  124. Field field = getField(i, j);
  125. if (field != null)
  126. {
  127.  
  128. int actualWidth = getPreferredWidthOfChild(field);
  129. if (isColumnStyle(styles[i],
  130. USE_PREFERRED_WIDTH_WITH_MAXIMUM))
  131. {
  132. actualWidth = Math.min(actualWidth,
  133. _suggestedColumnWidths[i]);
  134. }
  135.  
  136. columnWidths[i] = Math.max(actualWidth,
  137. columnWidths[i]);
  138. }
  139. }
  140. }
  141. }
  142. }
  143. // TODO - this loop can be optimized
  144. for (int n = 0; n < _columns; n++)
  145. {
  146. prefferedWidth += columnWidths[n];
  147. }
  148. return prefferedWidth;
  149. }
  150.  
  151. /**
  152. * implements the preferred height for this layout
  153. */
  154. public int getPreferredHeight()
  155. {
  156. int numberFields = getFieldCount();
  157. if (numberFields == 0) return 0;
  158.  
  159. int rows = numberFields / _columnStyles.length;
  160. int prefferedHeight = 0;
  161.  
  162. int[] rowHeights = new int[rows];
  163. Arrays.fill(rowHeights, -1);
  164.  
  165. for (int i = 0; i < _columns; i++)
  166. {
  167. for (int j = 0; j < rows; j++)
  168. {
  169. Field field = getField(i, j);
  170. if (field != null)
  171. {
  172. int actualHeight = getPreferredHeightOfChild(field);
  173. rowHeights[j] = Math.max(actualHeight, rowHeights[j]);
  174. }
  175. }
  176. }
  177.  
  178. for (int n = 0; n < rows; n++)
  179. {
  180. prefferedHeight += rowHeights[n];
  181. }
  182. return prefferedHeight;
  183. }
  184.  
  185. /**
  186. * Defines how Fields for this manager needs to be handled.
  187. */
  188. protected void sublayout(int layoutWidth, int layoutHeight)
  189. {
  190. int numberFields = getFieldCount();
  191. if (numberFields == 0) return;
  192. _columns = _columnStyles.length;
  193. int styles[] = _columnStyles;
  194. if (isStyle(Field.USE_ALL_WIDTH))
  195. {
  196. boolean found = false;
  197. // if the field should take maximum space, at least the last field
  198. // should be SPLIT_REMAINING_WIDTH
  199. for (int n = 0; n < _columns; n++)
  200. {
  201. if (styles[n] == SPLIT_REMAINING_WIDTH)
  202. {
  203. found = true;
  204. break;
  205. }
  206. }
  207. if (!found)
  208. {
  209. styles[_columns - 1] = SPLIT_REMAINING_WIDTH;
  210. }
  211. }
  212. _rows = numberFields / _columns;
  213. if ((numberFields % _columns) > 0) _rows++;
  214. _columnWidths = new int[_columns]; // arrays that keep track of maximum
  215. // widths
  216. _rowHeights = new int[_rows];
  217.  
  218. // widths and heights are -1 if unassigned, we use this fact to assign
  219. // the column widths
  220. Arrays.fill(_columnWidths, -1);
  221. Arrays.fill(_rowHeights, -1);
  222.  
  223. /*
  224. * there are three types of columns, fixed width, split remaining width,
  225. * and use preferred size step 1) we need to look at the columns that
  226. * are marked as "use preferred size", find the widest element, then
  227. * record that maximum width step 2) as well, we can assign the column
  228. * widths for the columns that are fixed width
  229. */
  230.  
  231. for (int i = 0; i < _columns; i++)
  232. {
  233. // assign the fixed widths
  234. if (isColumnStyle(styles[i], FIXED_WIDTH))
  235. {
  236. _columnWidths[i] = _suggestedColumnWidths[i];
  237. }
  238. else
  239. {
  240. if (isColumnStyle(styles[i], BITMASK_USE_PREFERRED))
  241. {
  242. for (int j = 0; j < _rows; j++)
  243. {
  244. Field field = getField(i, j);
  245. if (field != null)
  246. {
  247. layoutChild(field, Math.max(0, layoutWidth),layoutHeight);
  248. int actualWidth = getPreferredWidthOfChild(field);
  249. int actualHeight = getPreferredHeightOfChild(field);
  250. if (isColumnStyle(styles[i],
  251. USE_PREFERRED_WIDTH_WITH_MAXIMUM))
  252. {
  253. actualWidth = Math.min(actualWidth,
  254. _suggestedColumnWidths[i]);
  255. }
  256.  
  257. _columnWidths[i] = Math.max(actualWidth,
  258. _columnWidths[i]);
  259. _rowHeights[j] = Math.max(actualHeight,
  260. _rowHeights[j]);
  261. }
  262. }
  263. }
  264. }
  265. }
  266.  
  267. /*
  268. * step 3 - find out the total width used up by the fields that have
  269. * known widths
  270. */
  271. int usedColumnWidth = 0;
  272. int numUnassignedColumnWidths = 0;
  273.  
  274. for (int i = 0; i < _columns; i++)
  275. {
  276. if (_columnWidths[i] >= 0)
  277. {
  278. usedColumnWidth += _columnWidths[i]
  279. + ((i < (_columns - 1)) ? _horizPadding : 0);
  280. }
  281. else
  282. {
  283. numUnassignedColumnWidths++;
  284. }
  285. }
  286.  
  287. /*
  288. * assign the remaining space evenly amongst the unassigned columns
  289. */
  290. if (numUnassignedColumnWidths > 0)
  291. {
  292. int remainingWidthToAssign = layoutWidth - usedColumnWidth;
  293. if (remainingWidthToAssign < 0)
  294. {
  295. remainingWidthToAssign = 0;
  296. }
  297.  
  298. int splitRemainingWidth = (remainingWidthToAssign - ((numUnassignedColumnWidths - 1) * _horizPadding))
  299. / numUnassignedColumnWidths;
  300. for (int i = 0; i < _columns; i++)
  301. {
  302. int assignedWidth = Math.min(remainingWidthToAssign,
  303. splitRemainingWidth);
  304. if (_columnWidths[i] < 0)
  305. {
  306. _columnWidths[i] = assignedWidth;
  307. remainingWidthToAssign -= assignedWidth;
  308. }
  309. }
  310. }
  311.  
  312. int currentRow = 0;
  313. int currentColumn = 0;
  314. int y = 0;
  315. for (int n = 0; n < numberFields; n++)
  316. {
  317. Field field = getField(n);
  318.  
  319. if (!isColumnStyle(styles[currentColumn], USE_PREFERRED_SIZE))
  320. { // do
  321. // the others we missed from above
  322. layoutChild(field, Math.max(0, _columnWidths[currentColumn]),
  323. Math.max(0, layoutHeight
  324. - y));
  325. }
  326.  
  327. _rowHeights[currentRow] = Math.max(_rowHeights[currentRow], field
  328. .getExtent().height);
  329. currentColumn++;
  330. if ((n == (numberFields - 1)) || (currentColumn >= _columns))
  331. {
  332. // we are at the end of the row or list, so now go and actually
  333. // do the positioning for each row
  334. int x = 0;
  335. for (int i = 0; i < currentColumn; i++)
  336. {
  337. Field field1 = getField(i, currentRow);
  338. XYPoint offset = calcAlignmentOffset(field1, Math.max(0,
  339. _columnWidths[i]),Math.max(0,_rowHeights[currentRow]));
  340. setPositionChild(field1, x + offset.x,
  341. y + offset.y);
  342. x += _columnWidths[i] + _horizPadding;
  343. }
  344. y += _rowHeights[currentRow];
  345. currentColumn = 0;
  346. currentRow++;
  347. }
  348. }
  349.  
  350. int totalWidth = 0;
  351. if (isStyle(Field.USE_ALL_WIDTH))
  352. {
  353. totalWidth = layoutWidth;
  354. }
  355. else
  356. {
  357. for (int i = 0; i < _columns; i++)
  358. {
  359. totalWidth += _columnWidths[i]
  360. + ((i < (_columns - 1)) ? _horizPadding : 0);
  361. }
  362. }
  363. setExtent(totalWidth, Math.min(y, layoutHeight));
  364. }
  365.  
  366. /**
  367. * Navigation movement to allow for both cell to cell within a columns and
  368. * row movement
  369. */
  370. protected boolean navigationMovement(int dx, int dy, int status, int time)
  371. {
  372. int focusIndex = getFieldWithFocusIndex();
  373. int dirY = (dy > 0) ? 1 : -1;
  374. int absY = Math.abs(dy);
  375.  
  376. for (int y = 0; y < absY; y++)
  377. {
  378. focusIndex += _columns * dirY;
  379. if (focusIndex < 0 || focusIndex >= getFieldCount())
  380. {
  381. return false;
  382. }
  383. else
  384. {
  385. Field f = getField(focusIndex);
  386. if (f.isFocusable())
  387. {
  388. f.setFocus();
  389. }
  390. else
  391. y--; // do it over again
  392. }
  393. }
  394.  
  395. int dirX = (dx > 0) ? 1 : -1;
  396. int absX = Math.abs(dx);
  397. for (int x = 0; x < absX; x++)
  398. {
  399. focusIndex += dirX;
  400. if (focusIndex < 0 || focusIndex >= getFieldCount())
  401. {
  402. return false;
  403. }
  404. else
  405. {
  406. Field f = getField(focusIndex);
  407. if (f.isFocusable())
  408. {
  409. f.setFocus();
  410. }
  411. else
  412. x--; // do it over again
  413. }
  414. }
  415. return true;
  416. }
  417.  
  418. /**
  419. * Calculate the styles and return appropriate XY offset locations within the cell.
  420. * @param field
  421. * @param width
  422. * @param height
  423. * @return
  424. */
  425. private XYPoint calcAlignmentOffset(Field field, int width, int height)
  426. {
  427. XYPoint offset = new XYPoint(0, 0);
  428. long fieldStyle = field.getStyle();
  429. long field_x_style = fieldStyle & Field.FIELD_HALIGN_MASK;
  430.  
  431. if (field_x_style == Field.FIELD_RIGHT)
  432. {
  433. offset.x = width - field.getExtent().width;
  434. }
  435. else if (field_x_style == Field.FIELD_HCENTER)
  436. {
  437. offset.x = (width - field.getExtent().width) / 2;
  438. }
  439.  
  440. long field_y_style = fieldStyle & Field.FIELD_VALIGN_MASK;
  441. if (field_y_style == Field.FIELD_BOTTOM)
  442. {
  443. offset.y = height - field.getExtent().height;
  444. }
  445. else if (field_y_style == Field.FIELD_VCENTER)
  446. {
  447. offset.y = (height - field.getExtent().height) / 2;
  448. }
  449. return offset;
  450. }
  451. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement