PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ppt/scratchpad/src/org/apache/poi/hslf/model/Sheet.java

https://github.com/minstrelsy/POI-Android
Java | 464 lines | 267 code | 58 blank | 139 comment | 71 complexity | 004c81d0c6f4e85beee2c12f2cad27b2 MD5 | raw file
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hslf.model;
  16. import net.pbdavey.awt.Graphics2D;
  17. import org.apache.poi.ddf.*;
  18. import org.apache.poi.hslf.record.*;
  19. import org.apache.poi.hslf.usermodel.SlideShow;
  20. import java.util.ArrayList;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import and.awt.*;
  24. /**
  25. * This class defines the common format of "Sheets" in a powerpoint
  26. * document. Such sheets could be Slides, Notes, Master etc
  27. *
  28. * @author Nick Burch
  29. * @author Yegor Kozlov
  30. */
  31. public abstract class Sheet {
  32. /**
  33. * The <code>SlideShow</code> we belong to
  34. */
  35. private SlideShow _slideShow;
  36. /**
  37. * Sheet background
  38. */
  39. private Background _background;
  40. /**
  41. * Record container that holds sheet data.
  42. * For slides it is org.apache.poi.hslf.record.Slide,
  43. * for notes it is org.apache.poi.hslf.record.Notes,
  44. * for slide masters it is org.apache.poi.hslf.record.SlideMaster, etc.
  45. */
  46. private SheetContainer _container;
  47. private int _sheetNo;
  48. public Sheet(SheetContainer container, int sheetNo) {
  49. _container = container;
  50. _sheetNo = sheetNo;
  51. }
  52. /**
  53. * Returns an array of all the TextRuns in the sheet.
  54. */
  55. public abstract TextRun[] getTextRuns();
  56. /**
  57. * Returns the (internal, RefID based) sheet number, as used
  58. * to in PersistPtr stuff.
  59. */
  60. public int _getSheetRefId() {
  61. return _container.getSheetId();
  62. }
  63. /**
  64. * Returns the (internal, SlideIdentifier based) sheet number, as used
  65. * to reference this sheet from other records.
  66. */
  67. public int _getSheetNumber() {
  68. return _sheetNo;
  69. }
  70. /**
  71. * Fetch the PPDrawing from the underlying record
  72. */
  73. protected PPDrawing getPPDrawing() {
  74. return _container.getPPDrawing();
  75. }
  76. /**
  77. * Fetch the SlideShow we're attached to
  78. */
  79. public SlideShow getSlideShow() {
  80. return _slideShow;
  81. }
  82. /**
  83. * Return record container for this sheet
  84. */
  85. public SheetContainer getSheetContainer() {
  86. return _container;
  87. }
  88. /**
  89. * Set the SlideShow we're attached to.
  90. * Also passes it on to our child RichTextRuns
  91. */
  92. public void setSlideShow(SlideShow ss) {
  93. _slideShow = ss;
  94. TextRun[] trs = getTextRuns();
  95. if (trs != null) {
  96. for (int i = 0; i < trs.length; i++) {
  97. trs[i].supplySlideShow(_slideShow);
  98. }
  99. }
  100. }
  101. /**
  102. * For a given PPDrawing, grab all the TextRuns
  103. */
  104. public static TextRun[] findTextRuns(PPDrawing ppdrawing) {
  105. final List<TextRun> runsV = new ArrayList<TextRun>();
  106. EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
  107. for (int i = 0; i < wrappers.length; i++) {
  108. int s1 = runsV.size();
  109. // propagate parents to parent-aware records
  110. RecordContainer.handleParentAwareRecords(wrappers[i]);
  111. findTextRuns(wrappers[i].getChildRecords(), runsV);
  112. int s2 = runsV.size();
  113. if (s2 != s1){
  114. TextRun t = runsV.get(runsV.size()-1);
  115. t.setShapeId(wrappers[i].getShapeId());
  116. }
  117. }
  118. return runsV.toArray(new TextRun[runsV.size()]);
  119. }
  120. /**
  121. * Scans through the supplied record array, looking for
  122. * a TextHeaderAtom followed by one of a TextBytesAtom or
  123. * a TextCharsAtom. Builds up TextRuns from these
  124. *
  125. * @param records the records to build from
  126. * @param found vector to add any found to
  127. */
  128. protected static void findTextRuns(Record[] records, List<TextRun> found) {
  129. // Look for a TextHeaderAtom
  130. for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) {
  131. if (records[i] instanceof TextHeaderAtom) {
  132. TextRun trun = null;
  133. TextHeaderAtom tha = (TextHeaderAtom) records[i];
  134. StyleTextPropAtom stpa = null;
  135. // Look for a subsequent StyleTextPropAtom
  136. if (i < (records.length - 2)) {
  137. if (records[i + 2] instanceof StyleTextPropAtom) {
  138. stpa = (StyleTextPropAtom) records[i + 2];
  139. }
  140. }
  141. // See what follows the TextHeaderAtom
  142. if (records[i + 1] instanceof TextCharsAtom) {
  143. TextCharsAtom tca = (TextCharsAtom) records[i + 1];
  144. trun = new TextRun(tha, tca, stpa);
  145. } else if (records[i + 1] instanceof TextBytesAtom) {
  146. try {
  147. TextBytesAtom tba = (TextBytesAtom) records[i + 1];
  148. trun = new TextRun(tha, tba, stpa);
  149. } catch (Exception e) {
  150. e.printStackTrace();
  151. }
  152. } else if (records[i + 1].getRecordType() == 4001l) {
  153. // StyleTextPropAtom - Safe to ignore
  154. } else if (records[i + 1].getRecordType() == 4010l) {
  155. // TextSpecInfoAtom - Safe to ignore
  156. } else {
  157. System.err.println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + records[i + 1].getRecordType());
  158. }
  159. if (trun != null) {
  160. ArrayList lst = new ArrayList();
  161. for (int j = i; j < records.length; j++) {
  162. if(j > i && records[j] instanceof TextHeaderAtom) break;
  163. lst.add(records[j]);
  164. }
  165. Record[] recs = new Record[lst.size()];
  166. lst.toArray(recs);
  167. trun._records = recs;
  168. trun.setIndex(slwtIndex);
  169. found.add(trun);
  170. i++;
  171. } else {
  172. // Not a valid one, so skip on to next and look again
  173. }
  174. slwtIndex++;
  175. }
  176. }
  177. }
  178. /**
  179. * Returns all shapes contained in this Sheet
  180. *
  181. * @return all shapes contained in this Sheet (Slide or Notes)
  182. */
  183. public Shape[] getShapes() {
  184. PPDrawing ppdrawing = getPPDrawing();
  185. EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
  186. EscherContainerRecord spgr = null;
  187. for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
  188. EscherRecord rec = it.next();
  189. if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
  190. spgr = (EscherContainerRecord) rec;
  191. break;
  192. }
  193. }
  194. if (spgr == null) {
  195. throw new IllegalStateException("spgr not found");
  196. }
  197. List<Shape> shapes = new ArrayList<Shape>();
  198. Iterator<EscherRecord> it = spgr.getChildIterator();
  199. if (it.hasNext()) {
  200. // skip first item
  201. it.next();
  202. }
  203. for (; it.hasNext();) {
  204. EscherContainerRecord sp = (EscherContainerRecord) it.next();
  205. Shape sh = ShapeFactory.createShape(sp, null);
  206. sh.setSheet(this);
  207. shapes.add(sh);
  208. }
  209. return shapes.toArray(new Shape[shapes.size()]);
  210. }
  211. /**
  212. * Add a new Shape to this Slide
  213. *
  214. * @param shape - the Shape to add
  215. */
  216. public void addShape(Shape shape) {
  217. PPDrawing ppdrawing = getPPDrawing();
  218. EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
  219. EscherContainerRecord spgr = (EscherContainerRecord) Shape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
  220. spgr.addChildRecord(shape.getSpContainer());
  221. shape.setSheet(this);
  222. shape.setShapeId(allocateShapeId());
  223. shape.afterInsert(this);
  224. }
  225. /**
  226. * Allocates new shape id for the new drawing group id.
  227. *
  228. * @return a new shape id.
  229. */
  230. public int allocateShapeId()
  231. {
  232. EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
  233. EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord();
  234. dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
  235. // Add to existing cluster if space available
  236. for (int i = 0; i < dgg.getFileIdClusters().length; i++)
  237. {
  238. EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
  239. if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
  240. {
  241. int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
  242. c.incrementShapeId();
  243. dg.setNumShapes( dg.getNumShapes() + 1 );
  244. dg.setLastMSOSPID( result );
  245. if (result >= dgg.getShapeIdMax())
  246. dgg.setShapeIdMax( result + 1 );
  247. return result;
  248. }
  249. }
  250. // Create new cluster
  251. dgg.addCluster( dg.getDrawingGroupId(), 0, false );
  252. dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
  253. dg.setNumShapes( dg.getNumShapes() + 1 );
  254. int result = (1024 * dgg.getFileIdClusters().length);
  255. dg.setLastMSOSPID( result );
  256. if (result >= dgg.getShapeIdMax())
  257. dgg.setShapeIdMax( result + 1 );
  258. return result;
  259. }
  260. /**
  261. * Removes the specified shape from this sheet.
  262. *
  263. * @param shape shape to be removed from this sheet, if present.
  264. * @return <tt>true</tt> if the shape was deleted.
  265. */
  266. public boolean removeShape(Shape shape) {
  267. PPDrawing ppdrawing = getPPDrawing();
  268. EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
  269. EscherContainerRecord spgr = null;
  270. for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
  271. EscherRecord rec = it.next();
  272. if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
  273. spgr = (EscherContainerRecord) rec;
  274. break;
  275. }
  276. }
  277. if(spgr == null) {
  278. return false;
  279. }
  280. List<EscherRecord> lst = spgr.getChildRecords();
  281. boolean result = lst.remove(shape.getSpContainer());
  282. spgr.setChildRecords(lst);
  283. return result;
  284. }
  285. /**
  286. * Called by SlideShow ater a new sheet is created
  287. */
  288. public void onCreate(){
  289. }
  290. /**
  291. * Return the master sheet .
  292. */
  293. public abstract MasterSheet getMasterSheet();
  294. /**
  295. * Color scheme for this sheet.
  296. */
  297. public ColorSchemeAtom getColorScheme() {
  298. return _container.getColorScheme();
  299. }
  300. /**
  301. * Returns the background shape for this sheet.
  302. *
  303. * @return the background shape for this sheet.
  304. */
  305. public Background getBackground() {
  306. if (_background == null) {
  307. PPDrawing ppdrawing = getPPDrawing();
  308. EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
  309. EscherContainerRecord spContainer = null;
  310. for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
  311. EscherRecord rec = it.next();
  312. if (rec.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
  313. spContainer = (EscherContainerRecord) rec;
  314. break;
  315. }
  316. }
  317. _background = new Background(spContainer, null);
  318. _background.setSheet(this);
  319. }
  320. return _background;
  321. }
  322. public void draw(Graphics2D graphics){
  323. }
  324. /**
  325. * Subclasses should call this method and update the array of text runs
  326. * when a text shape is added
  327. *
  328. * @param shape
  329. */
  330. protected void onAddTextShape(TextShape shape) {
  331. }
  332. /**
  333. * Return placeholder by text type
  334. *
  335. * @param type type of text, See {@link org.apache.poi.hslf.record.TextHeaderAtom}
  336. * @return <code>TextShape</code> or <code>null</code>
  337. */
  338. public TextShape getPlaceholderByTextType(int type){
  339. Shape[] shape = getShapes();
  340. for (int i = 0; i < shape.length; i++) {
  341. if(shape[i] instanceof TextShape){
  342. TextShape tx = (TextShape)shape[i];
  343. TextRun run = tx.getTextRun();
  344. if(run != null && run.getRunType() == type){
  345. return tx;
  346. }
  347. }
  348. }
  349. return null;
  350. }
  351. /**
  352. * Search text placeholer by its type
  353. *
  354. * @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom}
  355. * @return <code>TextShape</code> or <code>null</code>
  356. */
  357. public TextShape getPlaceholder(int type){
  358. Shape[] shape = getShapes();
  359. for (int i = 0; i < shape.length; i++) {
  360. if(shape[i] instanceof TextShape){
  361. TextShape tx = (TextShape)shape[i];
  362. int placeholderId = 0;
  363. OEPlaceholderAtom oep = tx.getPlaceholderAtom();
  364. if(oep != null) {
  365. placeholderId = oep.getPlaceholderId();
  366. } else {
  367. //special case for files saved in Office 2007
  368. RoundTripHFPlaceholder12 hldr = (RoundTripHFPlaceholder12)tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
  369. if(hldr != null) placeholderId = hldr.getPlaceholderId();
  370. }
  371. if(placeholderId == type){
  372. return tx;
  373. }
  374. }
  375. }
  376. return null;
  377. }
  378. /**
  379. * Return programmable tag associated with this sheet, e.g. <code>___PPT12</code>.
  380. *
  381. * @return programmable tag associated with this sheet.
  382. */
  383. public String getProgrammableTag(){
  384. String tag = null;
  385. RecordContainer progTags = (RecordContainer)
  386. getSheetContainer().findFirstOfType(
  387. RecordTypes.ProgTags.typeID
  388. );
  389. if(progTags != null) {
  390. RecordContainer progBinaryTag = (RecordContainer)
  391. progTags.findFirstOfType(
  392. RecordTypes.ProgBinaryTag.typeID
  393. );
  394. if(progBinaryTag != null) {
  395. CString binaryTag = (CString)
  396. progBinaryTag.findFirstOfType(
  397. RecordTypes.CString.typeID
  398. );
  399. if(binaryTag != null) tag = binaryTag.getText();
  400. }
  401. }
  402. return tag;
  403. }
  404. }