PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/components/forks/poi/src/loci/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java

http://github.com/openmicroscopy/bioformats
Java | 553 lines | 388 code | 60 blank | 105 comment | 103 complexity | 83318df6e5a62008db05b056a28ec095 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, BSD-2-Clause, MPL-2.0-no-copyleft-exception
  1. /*
  2. * #%L
  3. * Fork of Apache Jakarta POI.
  4. * %%
  5. * Copyright (C) 2008 - 2013 Open Microscopy Environment:
  6. * - Board of Regents of the University of Wisconsin-Madison
  7. * - Glencoe Software, Inc.
  8. * - University of Dundee
  9. * %%
  10. * Licensed under the Apache License, Version 2.0 (the "License");
  11. * you may not use this file except in compliance with the License.
  12. * You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS,
  18. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  19. * See the License for the specific language governing permissions and
  20. * limitations under the License.
  21. * #L%
  22. */
  23. /*
  24. * Licensed to the Apache Software Foundation (ASF) under one or more
  25. * contributor license agreements. See the NOTICE file distributed with
  26. * this work for additional information regarding copyright ownership.
  27. * The ASF licenses this file to You under the Apache License, Version 2.0
  28. * (the "License"); you may not use this file except in compliance with
  29. * the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing, software
  34. * distributed under the License is distributed on an "AS IS" BASIS,
  35. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  36. * See the License for the specific language governing permissions and
  37. * limitations under the License.
  38. */
  39. package loci.poi.hssf.record.aggregates;
  40. import loci.poi.hssf.record.ColumnInfoRecord;
  41. import loci.poi.hssf.record.Record;
  42. import loci.poi.hssf.record.RecordInputStream;
  43. import java.util.ArrayList;
  44. import java.util.Iterator;
  45. import java.util.List;
  46. /**
  47. * @author Glen Stampoultzis
  48. * @version $Id: ColumnInfoRecordsAggregate.java 496526 2007-01-15 22:46:35Z markt $
  49. */
  50. public class ColumnInfoRecordsAggregate
  51. extends Record
  52. {
  53. // int size = 0;
  54. List records = null;
  55. public ColumnInfoRecordsAggregate()
  56. {
  57. records = new ArrayList();
  58. }
  59. /** You never fill an aggregate */
  60. protected void fillFields(RecordInputStream in)
  61. {
  62. }
  63. /** Not required by an aggregate */
  64. protected void validateSid(short id)
  65. {
  66. }
  67. /** It's an aggregate... just made something up */
  68. public short getSid()
  69. {
  70. return -1012;
  71. }
  72. public int getRecordSize()
  73. {
  74. int size = 0;
  75. for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
  76. size += ( (ColumnInfoRecord) iterator.next() ).getRecordSize();
  77. return size;
  78. }
  79. public Iterator getIterator()
  80. {
  81. return records.iterator();
  82. }
  83. /**
  84. * Performs a deep clone of the record
  85. */
  86. public Object clone()
  87. {
  88. ColumnInfoRecordsAggregate rec = new ColumnInfoRecordsAggregate();
  89. for (int k = 0; k < records.size(); k++)
  90. {
  91. ColumnInfoRecord ci = ( ColumnInfoRecord ) records.get(k);
  92. ci=(ColumnInfoRecord) ci.clone();
  93. rec.insertColumn( ci );
  94. }
  95. return rec;
  96. }
  97. /**
  98. * Inserts a column into the aggregate (at the end of the list).
  99. */
  100. public void insertColumn( ColumnInfoRecord col )
  101. {
  102. records.add( col );
  103. }
  104. /**
  105. * Inserts a column into the aggregate (at the position specified
  106. * by <code>idx</code>.
  107. */
  108. public void insertColumn( int idx, ColumnInfoRecord col )
  109. {
  110. records.add( idx, col );
  111. }
  112. public int getNumColumns( )
  113. {
  114. return records.size();
  115. }
  116. /**
  117. * called by the class that is responsible for writing this sucker.
  118. * Subclasses should implement this so that their data is passed back in a
  119. * byte array.
  120. *
  121. * @param offset offset to begin writing at
  122. * @param data byte array containing instance data
  123. * @return number of bytes written
  124. */
  125. public int serialize(int offset, byte [] data)
  126. {
  127. Iterator itr = records.iterator();
  128. int pos = offset;
  129. while (itr.hasNext())
  130. {
  131. pos += (( Record ) itr.next()).serialize(pos, data);
  132. }
  133. return pos - offset;
  134. }
  135. public int findStartOfColumnOutlineGroup(int idx)
  136. {
  137. // Find the start of the group.
  138. ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
  139. int level = columnInfo.getOutlineLevel();
  140. while (idx != 0)
  141. {
  142. ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get( idx - 1 );
  143. if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn())
  144. {
  145. if (prevColumnInfo.getOutlineLevel() < level)
  146. {
  147. break;
  148. }
  149. idx--;
  150. columnInfo = prevColumnInfo;
  151. }
  152. else
  153. {
  154. break;
  155. }
  156. }
  157. return idx;
  158. }
  159. public int findEndOfColumnOutlineGroup(int idx)
  160. {
  161. // Find the end of the group.
  162. ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( idx );
  163. int level = columnInfo.getOutlineLevel();
  164. while (idx < records.size() - 1)
  165. {
  166. ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get( idx + 1 );
  167. if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
  168. {
  169. if (nextColumnInfo.getOutlineLevel() < level)
  170. {
  171. break;
  172. }
  173. idx++;
  174. columnInfo = nextColumnInfo;
  175. }
  176. else
  177. {
  178. break;
  179. }
  180. }
  181. return idx;
  182. }
  183. public ColumnInfoRecord getColInfo(int idx)
  184. {
  185. return (ColumnInfoRecord) records.get( idx );
  186. }
  187. public ColumnInfoRecord writeHidden( ColumnInfoRecord columnInfo, int idx, boolean hidden )
  188. {
  189. int level = columnInfo.getOutlineLevel();
  190. while (idx < records.size())
  191. {
  192. columnInfo.setHidden( hidden );
  193. if (idx + 1 < records.size())
  194. {
  195. ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get( idx + 1 );
  196. if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn())
  197. {
  198. if (nextColumnInfo.getOutlineLevel() < level)
  199. break;
  200. columnInfo = nextColumnInfo;
  201. }
  202. else
  203. {
  204. break;
  205. }
  206. }
  207. idx++;
  208. }
  209. return columnInfo;
  210. }
  211. public boolean isColumnGroupCollapsed( int idx )
  212. {
  213. int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
  214. if (endOfOutlineGroupIdx >= records.size())
  215. return false;
  216. if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
  217. return false;
  218. else
  219. return getColInfo(endOfOutlineGroupIdx+1).getCollapsed();
  220. }
  221. public boolean isColumnGroupHiddenByParent( int idx )
  222. {
  223. // Look out outline details of end
  224. int endLevel;
  225. boolean endHidden;
  226. int endOfOutlineGroupIdx = findEndOfColumnOutlineGroup( idx );
  227. if (endOfOutlineGroupIdx >= records.size())
  228. {
  229. endLevel = 0;
  230. endHidden = false;
  231. }
  232. else if (getColInfo(endOfOutlineGroupIdx).getLastColumn() + 1 != getColInfo(endOfOutlineGroupIdx + 1).getFirstColumn())
  233. {
  234. endLevel = 0;
  235. endHidden = false;
  236. }
  237. else
  238. {
  239. endLevel = getColInfo( endOfOutlineGroupIdx + 1).getOutlineLevel();
  240. endHidden = getColInfo( endOfOutlineGroupIdx + 1).getHidden();
  241. }
  242. // Look out outline details of start
  243. int startLevel;
  244. boolean startHidden;
  245. int startOfOutlineGroupIdx = findStartOfColumnOutlineGroup( idx );
  246. if (startOfOutlineGroupIdx <= 0)
  247. {
  248. startLevel = 0;
  249. startHidden = false;
  250. }
  251. else if (getColInfo(startOfOutlineGroupIdx).getFirstColumn() - 1 != getColInfo(startOfOutlineGroupIdx - 1).getLastColumn())
  252. {
  253. startLevel = 0;
  254. startHidden = false;
  255. }
  256. else
  257. {
  258. startLevel = getColInfo( startOfOutlineGroupIdx - 1).getOutlineLevel();
  259. startHidden = getColInfo( startOfOutlineGroupIdx - 1 ).getHidden();
  260. }
  261. if (endLevel > startLevel)
  262. {
  263. return endHidden;
  264. }
  265. else
  266. {
  267. return startHidden;
  268. }
  269. }
  270. public void collapseColumn( short columnNumber )
  271. {
  272. int idx = findColumnIdx( columnNumber, 0 );
  273. if (idx == -1)
  274. return;
  275. // Find the start of the group.
  276. ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get( findStartOfColumnOutlineGroup( idx ) );
  277. // Hide all the columns until the end of the group
  278. columnInfo = writeHidden( columnInfo, idx, true );
  279. // Write collapse field
  280. setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.TRUE);
  281. }
  282. public void expandColumn( short columnNumber )
  283. {
  284. int idx = findColumnIdx( columnNumber, 0 );
  285. if (idx == -1)
  286. return;
  287. // If it is already exapanded do nothing.
  288. if (!isColumnGroupCollapsed(idx))
  289. return;
  290. // Find the start of the group.
  291. int startIdx = findStartOfColumnOutlineGroup( idx );
  292. ColumnInfoRecord columnInfo = getColInfo( startIdx );
  293. // Find the end of the group.
  294. int endIdx = findEndOfColumnOutlineGroup( idx );
  295. ColumnInfoRecord endColumnInfo = getColInfo( endIdx );
  296. // expand:
  297. // colapsed bit must be unset
  298. // hidden bit gets unset _if_ surrounding groups are expanded you can determine
  299. // this by looking at the hidden bit of the enclosing group. You will have
  300. // to look at the start and the end of the current group to determine which
  301. // is the enclosing group
  302. // hidden bit only is altered for this outline level. ie. don't uncollapse contained groups
  303. if (!isColumnGroupHiddenByParent( idx ))
  304. {
  305. for (int i = startIdx; i <= endIdx; i++)
  306. {
  307. if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel())
  308. getColInfo(i).setHidden( false );
  309. }
  310. }
  311. // Write collapse field
  312. setColumn( (short) ( columnInfo.getLastColumn() + 1 ), null, null, null, null, Boolean.FALSE);
  313. }
  314. /**
  315. * creates the ColumnInfo Record and sets it to a default column/width
  316. * @see loci.poi.hssf.record.ColumnInfoRecord
  317. * @return record containing a ColumnInfoRecord
  318. */
  319. public static Record createColInfo()
  320. {
  321. ColumnInfoRecord retval = new ColumnInfoRecord();
  322. retval.setColumnWidth(( short ) 2275);
  323. // was: retval.setOptions(( short ) 6);
  324. retval.setOptions(( short ) 2);
  325. retval.setXFIndex(( short ) 0x0f);
  326. return retval;
  327. }
  328. public void setColumn(short column, Short xfIndex, Short width, Integer level, Boolean hidden, Boolean collapsed)
  329. {
  330. ColumnInfoRecord ci = null;
  331. int k = 0;
  332. for (k = 0; k < records.size(); k++)
  333. {
  334. ci = ( ColumnInfoRecord ) records.get(k);
  335. if ((ci.getFirstColumn() <= column)
  336. && (column <= ci.getLastColumn()))
  337. {
  338. break;
  339. }
  340. ci = null;
  341. }
  342. if (ci != null)
  343. {
  344. boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
  345. boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
  346. boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
  347. boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
  348. boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
  349. boolean columnChanged = styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
  350. if (!columnChanged)
  351. {
  352. // do nothing...nothing changed.
  353. }
  354. else if ((ci.getFirstColumn() == column)
  355. && (ci.getLastColumn() == column))
  356. { // if its only for this cell then
  357. setColumnInfoFields( ci, xfIndex, width, level, hidden, collapsed );
  358. }
  359. else if ((ci.getFirstColumn() == column)
  360. || (ci.getLastColumn() == column))
  361. {
  362. // okay so the width is different but the first or last column == the column we'return setting
  363. // we'll just divide the info and create a new one
  364. if (ci.getFirstColumn() == column)
  365. {
  366. ci.setFirstColumn(( short ) (column + 1));
  367. }
  368. else
  369. {
  370. ci.setLastColumn(( short ) (column - 1));
  371. }
  372. ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
  373. nci.setFirstColumn(column);
  374. nci.setLastColumn(column);
  375. nci.setOptions(ci.getOptions());
  376. nci.setXFIndex(ci.getXFIndex());
  377. setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
  378. insertColumn(k, nci);
  379. }
  380. else
  381. {
  382. //split to 3 records
  383. short lastcolumn = ci.getLastColumn();
  384. ci.setLastColumn(( short ) (column - 1));
  385. ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
  386. nci.setFirstColumn(column);
  387. nci.setLastColumn(column);
  388. nci.setOptions(ci.getOptions());
  389. nci.setXFIndex(ci.getXFIndex());
  390. setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
  391. insertColumn(++k, nci);
  392. nci = ( ColumnInfoRecord ) createColInfo();
  393. nci.setFirstColumn((short)(column+1));
  394. nci.setLastColumn(lastcolumn);
  395. nci.setOptions(ci.getOptions());
  396. nci.setXFIndex(ci.getXFIndex());
  397. nci.setColumnWidth(ci.getColumnWidth());
  398. insertColumn(++k, nci);
  399. }
  400. }
  401. else
  402. {
  403. // okay so there ISN'T a column info record that cover's this column so lets create one!
  404. ColumnInfoRecord nci = ( ColumnInfoRecord ) createColInfo();
  405. nci.setFirstColumn(column);
  406. nci.setLastColumn(column);
  407. setColumnInfoFields( nci, xfIndex, width, level, hidden, collapsed );
  408. insertColumn(k, nci);
  409. }
  410. }
  411. /**
  412. * Sets all non null fields into the <code>ci</code> parameter.
  413. */
  414. private void setColumnInfoFields( ColumnInfoRecord ci, Short xfStyle, Short width, Integer level, Boolean hidden, Boolean collapsed )
  415. {
  416. if (xfStyle != null)
  417. ci.setXFIndex(xfStyle.shortValue());
  418. if (width != null)
  419. ci.setColumnWidth(width.shortValue());
  420. if (level != null)
  421. ci.setOutlineLevel( level.shortValue() );
  422. if (hidden != null)
  423. ci.setHidden( hidden.booleanValue() );
  424. if (collapsed != null)
  425. ci.setCollapsed( collapsed.booleanValue() );
  426. }
  427. public int findColumnIdx(int column, int fromIdx)
  428. {
  429. if (column < 0)
  430. throw new IllegalArgumentException( "column parameter out of range: " + column );
  431. if (fromIdx < 0)
  432. throw new IllegalArgumentException( "fromIdx parameter out of range: " + fromIdx );
  433. ColumnInfoRecord ci;
  434. for (int k = fromIdx; k < records.size(); k++)
  435. {
  436. ci = ( ColumnInfoRecord ) records.get(k);
  437. if ((ci.getFirstColumn() <= column)
  438. && (column <= ci.getLastColumn()))
  439. {
  440. return k;
  441. }
  442. ci = null;
  443. }
  444. return -1;
  445. }
  446. public void collapseColInfoRecords( int columnIdx )
  447. {
  448. if (columnIdx == 0)
  449. return;
  450. ColumnInfoRecord previousCol = (ColumnInfoRecord) records.get( columnIdx - 1);
  451. ColumnInfoRecord currentCol = (ColumnInfoRecord) records.get( columnIdx );
  452. boolean adjacentColumns = previousCol.getLastColumn() == currentCol.getFirstColumn() - 1;
  453. if (!adjacentColumns)
  454. return;
  455. boolean columnsMatch =
  456. previousCol.getXFIndex() == currentCol.getXFIndex() &&
  457. previousCol.getOptions() == currentCol.getOptions() &&
  458. previousCol.getColumnWidth() == currentCol.getColumnWidth();
  459. if (columnsMatch)
  460. {
  461. previousCol.setLastColumn( currentCol.getLastColumn() );
  462. records.remove( columnIdx );
  463. }
  464. }
  465. /**
  466. * Creates an outline group for the specified columns.
  467. * @param fromColumn group from this column (inclusive)
  468. * @param toColumn group to this column (inclusive)
  469. * @param indent if true the group will be indented by one level,
  470. * if false indenting will be removed by one level.
  471. */
  472. public void groupColumnRange(short fromColumn, short toColumn, boolean indent)
  473. {
  474. // Set the level for each column
  475. int fromIdx = 0;
  476. for (int i = fromColumn; i <= toColumn; i++)
  477. {
  478. int level = 1;
  479. int columnIdx = findColumnIdx( i, Math.max(0,fromIdx) );
  480. if (columnIdx != -1)
  481. {
  482. level = ((ColumnInfoRecord)records.get( columnIdx )).getOutlineLevel();
  483. if (indent) level++; else level--;
  484. level = Math.max(0, level);
  485. level = Math.min(7, level);
  486. fromIdx = columnIdx - 1; // subtract 1 just in case this column is collapsed later.
  487. }
  488. setColumn((short)i, null, null, new Integer(level), null, null);
  489. columnIdx = findColumnIdx( i, Math.max(0, fromIdx ) );
  490. collapseColInfoRecords( columnIdx );
  491. }
  492. }
  493. }