package org.apache.poi.hslf.record;
+import org.apache.poi.util.ArrayUtil;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hslf.util.MutableByteArrayOutputStream;
public abstract class RecordContainer extends Record
{
protected Record[] _children;
- private Boolean addingChildRecordLock = new Boolean(true);
+ private Boolean changingChildRecordsLock = new Boolean(true);
/**
* Return any children
*/
public boolean isAnAtom() { return false; }
- /**
- * Add a new child record onto a record's list of children.
- */
- public void appendChildRecord(Record newChild) {
- synchronized(addingChildRecordLock) {
- addChildAt(newChild, _children.length);
- }
- }
+ /* ===============================================================
+ * Internal Move Helpers
+ * ===============================================================
+ */
+
/**
* Finds the location of the given child record
*/
private int findChildLocation(Record child) {
// Synchronized as we don't want things changing
// as we're doing our search
- synchronized(addingChildRecordLock) {
+ synchronized(changingChildRecordsLock) {
for(int i=0; i<_children.length; i++) {
if(_children[i].equals(child)) {
return i;
return -1;
}
+ /**
+ * Adds a child record, at the very end.
+ * @param newChild The child record to add
+ */
+ private void appendChild(Record newChild) {
+ synchronized(changingChildRecordsLock) {
+ // Copy over, and pop the child in at the end
+ Record[] nc = new Record[(_children.length + 1)];
+ System.arraycopy(_children, 0, nc, 0, _children.length);
+ // Switch the arrays
+ nc[_children.length] = newChild;
+ _children = nc;
+ }
+ }
+
/**
* Adds the given new Child Record at the given location,
* shuffling everything from there on down by one
* @param position
*/
private void addChildAt(Record newChild, int position) {
- synchronized(addingChildRecordLock) {
- Record[] newChildren = new Record[_children.length+1];
- // Move over to the new array, shuffling on by one after
- // the addition point
- for(int i=0; i<_children.length; i++) {
- if(i == position) {
- newChildren[i] = newChild;
- }
-
- if(i >= position) {
- newChildren[i+1] = _children[i];
- }
- if(i < position) {
- newChildren[i] = _children[i];
- }
- }
+ synchronized(changingChildRecordsLock) {
+ // Firstly, have the child added in at the end
+ appendChild(newChild);
- // Special case - new record goes at the end
- if(position == _children.length) {
- newChildren[position] = newChild;
- }
+ // Now, have them moved to the right place
+ moveChildRecords( (_children.length-1), position, 1 );
+ }
+ }
+
+ /**
+ * Moves <i>number</i> child records from <i>oldLoc</i>
+ * to <i>newLoc</i>. Caller must have the changingChildRecordsLock
+ * @param oldLoc the current location of the records to move
+ * @param newLoc the new location for the records
+ * @param number the number of records to move
+ */
+ private void moveChildRecords(int oldLoc, int newLoc, int number) {
+ if(oldLoc == newLoc) { return; }
+ if(number == 0) { return; }
- // All done, replace our child list
- _children = newChildren;
+ // Check that we're not asked to move too many
+ if(oldLoc+number > _children.length) {
+ throw new IllegalArgumentException("Asked to move more records than there are!");
+ }
+
+ // Do the move
+ ArrayUtil.arrayMoveWithin(_children, oldLoc, newLoc, number);
+ }
+
+
+ /* ===============================================================
+ * External Move Methods
+ * ===============================================================
+ */
+
+ /**
+ * Add a new child record onto a record's list of children.
+ */
+ public void appendChildRecord(Record newChild) {
+ synchronized(changingChildRecordsLock) {
+ appendChild(newChild);
}
}
* @param after
*/
public void addChildAfter(Record newChild, Record after) {
- synchronized(addingChildRecordLock) {
+ synchronized(changingChildRecordsLock) {
// Decide where we're going to put it
int loc = findChildLocation(after);
if(loc == -1) {
* @param after
*/
public void addChildBefore(Record newChild, Record before) {
- synchronized(addingChildRecordLock) {
+ synchronized(changingChildRecordsLock) {
// Decide where we're going to put it
int loc = findChildLocation(before);
if(loc == -1) {
}
}
+ /**
+ * Moves the given Child Record to before the supplied record
+ */
+ public void moveChildBefore(Record child, Record before) {
+ moveChildrenBefore(child, 1, before);
+ }
+
+ /**
+ * Moves the given Child Records to before the supplied record
+ */
+ public void moveChildrenBefore(Record firstChild, int number, Record before) {
+ if(number < 1) { return; }
+
+ synchronized(changingChildRecordsLock) {
+ // Decide where we're going to put them
+ int newLoc = findChildLocation(before);
+ if(newLoc == -1) {
+ throw new IllegalArgumentException("Asked to move children before another record, but that record wasn't one of our children!");
+ }
+
+ // Figure out where they are now
+ int oldLoc = findChildLocation(firstChild);
+ if(oldLoc == -1) {
+ throw new IllegalArgumentException("Asked to move a record that wasn't a child!");
+ }
+
+ // Actually move
+ moveChildRecords(oldLoc, newLoc, number);
+ }
+ }
+
+ /**
+ * Moves the given Child Records to after the supplied record
+ */
+ public void moveChildrenAfter(Record firstChild, int number, Record after) {
+ if(number < 1) { return; }
+
+ synchronized(changingChildRecordsLock) {
+ // Decide where we're going to put them
+ int newLoc = findChildLocation(after);
+ if(newLoc == -1) {
+ throw new IllegalArgumentException("Asked to move children before another record, but that record wasn't one of our children!");
+ }
+ // We actually want after this though
+ newLoc++;
+
+ // Figure out where they are now
+ int oldLoc = findChildLocation(firstChild);
+ if(oldLoc == -1) {
+ throw new IllegalArgumentException("Asked to move a record that wasn't a child!");
+ }
+
+ // Actually move
+ moveChildRecords(oldLoc, newLoc, number);
+ }
+ }
+
+
+ /* ===============================================================
+ * External Serialisation Methods
+ * ===============================================================
+ */
+
/**
* Write out our header, and our children.
* @param headerA the first byte of the header
--- /dev/null
+
+/* ====================================================================
+ Copyright 2002-2004 Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+
+
+package org.apache.poi.hslf.usermodel;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+import org.apache.poi.hslf.*;
+import org.apache.poi.hslf.model.*;
+
+/**
+ * Tests that SlideShow can re-order slides properly
+ *
+ * @author Nick Burch (nick at torchbox dot com)
+ */
+public class TestReOrderingSlides extends TestCase {
+ // A SlideShow with one slide
+ private HSLFSlideShow hss_one;
+ private SlideShow ss_one;
+
+ // A SlideShow with two slides
+ private HSLFSlideShow hss_two;
+ private SlideShow ss_two;
+
+ // A SlideShow with three slides
+ private HSLFSlideShow hss_three;
+ private SlideShow ss_three;
+
+ /**
+ * Create/open the slideshows
+ */
+ public void setUp() throws Exception {
+ String dirname = System.getProperty("HSLF.testdata.path");
+
+ String filename = dirname + "/Single_Coloured_Page.ppt";
+ hss_one = new HSLFSlideShow(filename);
+ ss_one = new SlideShow(hss_one);
+
+ filename = dirname + "/basic_test_ppt_file.ppt";
+ hss_two = new HSLFSlideShow(filename);
+ ss_two = new SlideShow(hss_two);
+
+ filename = dirname + "/incorrect_slide_order.ppt";
+ hss_three = new HSLFSlideShow(filename);
+ ss_three = new SlideShow(hss_three);
+ }
+
+ /**
+ * Test that we can "re-order" a slideshow with only 1 slide on it
+ */
+ public void testReOrder1() throws Exception {
+ // Has one slide
+ assertEquals(1, ss_one.getSlides().length);
+ Slide s1 = ss_one.getSlides()[0];
+
+ // Check slide 1 is as expected
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(3, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+
+ // Now move it to one
+ ss_one.reorderSlide(1, 1);
+
+ // Write out, and read back in
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ hss_one.write(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ HSLFSlideShow hss_read = new HSLFSlideShow(bais);
+ SlideShow ss_read = new SlideShow(hss_read);
+
+ // Check it still has 1 slide
+ assertEquals(1, ss_read.getSlides().length);
+
+ // And check it's as expected
+ s1 = ss_read.getSlides()[0];
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(3, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+ }
+
+ /**
+ * Test doing a dummy re-order on a slideshow with
+ * two slides in it
+ */
+ public void testReOrder2() throws Exception {
+ // Has two slides
+ assertEquals(2, ss_two.getSlides().length);
+ Slide s1 = ss_two.getSlides()[0];
+ Slide s2 = ss_two.getSlides()[1];
+
+ // Check slide 1 is as expected
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(4, s1._getSheetRefId()); // master has notes
+ assertEquals(1, s1.getSlideNumber());
+ // Check slide 2 is as expected
+ assertEquals(257, s2._getSheetNumber());
+ assertEquals(6, s2._getSheetRefId()); // master and 1 have notes
+ assertEquals(2, s2.getSlideNumber());
+
+ // Don't swap them around
+ ss_two.reorderSlide(2, 2);
+
+ // Write out, and read back in
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ hss_two.write(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ HSLFSlideShow hss_read = new HSLFSlideShow(bais);
+ SlideShow ss_read = new SlideShow(hss_read);
+
+ // Check it still has 2 slides
+ assertEquals(2, ss_read.getSlides().length);
+
+ // And check it's as expected
+ s1 = ss_read.getSlides()[0];
+ s2 = ss_read.getSlides()[1];
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(4, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+ assertEquals(257, s2._getSheetNumber());
+ assertEquals(6, s2._getSheetRefId());
+ assertEquals(2, s2.getSlideNumber());
+ }
+
+ /**
+ * Test re-ordering slides in a slideshow with 2 slides on it
+ */
+ public void testReOrder2swap() throws Exception {
+ // Has two slides
+ assertEquals(2, ss_two.getSlides().length);
+ Slide s1 = ss_two.getSlides()[0];
+ Slide s2 = ss_two.getSlides()[1];
+
+ // Check slide 1 is as expected
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(4, s1._getSheetRefId()); // master has notes
+ assertEquals(1, s1.getSlideNumber());
+ // Check slide 2 is as expected
+ assertEquals(257, s2._getSheetNumber());
+ assertEquals(6, s2._getSheetRefId()); // master and 1 have notes
+ assertEquals(2, s2.getSlideNumber());
+
+ // Swap them around
+ ss_two.reorderSlide(2, 1);
+
+ // Write out, and read back in
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ hss_two.write(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ HSLFSlideShow hss_read = new HSLFSlideShow(bais);
+ SlideShow ss_read = new SlideShow(hss_read);
+
+ // Check it still has 2 slides
+ assertEquals(2, ss_read.getSlides().length);
+
+ // And check it's as expected
+ s1 = ss_read.getSlides()[0];
+ s2 = ss_read.getSlides()[1];
+ assertEquals(257, s1._getSheetNumber());
+ assertEquals(6, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+ assertEquals(256, s2._getSheetNumber());
+ assertEquals(4, s2._getSheetRefId());
+ assertEquals(2, s2.getSlideNumber());
+ }
+
+ /**
+ * Test doing a dummy re-order on a slideshow with
+ * three slides in it
+ */
+ public void testReOrder3() throws Exception {
+ // Has three slides
+ assertEquals(3, ss_three.getSlides().length);
+ Slide s1 = ss_three.getSlides()[0];
+ Slide s2 = ss_three.getSlides()[1];
+ Slide s3 = ss_three.getSlides()[2];
+
+ // Check slide 1 is as expected
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(3, s1._getSheetRefId()); // no notes on master
+ assertEquals(1, s1.getSlideNumber());
+ // Check slide 2 is as expected (was re-ordered from 3)
+ assertEquals(258, s2._getSheetNumber());
+ assertEquals(5, s2._getSheetRefId()); // no notes on slide
+ assertEquals(2, s2.getSlideNumber());
+ // Check slide 3 is as expected (was re-ordered from 2)
+ assertEquals(257, s3._getSheetNumber());
+ assertEquals(4, s3._getSheetRefId()); // no notes on slide
+ assertEquals(3, s3.getSlideNumber());
+
+ // Don't swap them around
+ ss_three.reorderSlide(2, 2);
+
+ // Write out, and read back in
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ hss_three.write(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ HSLFSlideShow hss_read = new HSLFSlideShow(bais);
+ SlideShow ss_read = new SlideShow(hss_read);
+
+ // Check it still has 3 slides
+ assertEquals(3, ss_read.getSlides().length);
+
+ // And check it's as expected
+ s1 = ss_read.getSlides()[0];
+ s2 = ss_read.getSlides()[1];
+ s3 = ss_read.getSlides()[2];
+
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(3, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+ assertEquals(258, s2._getSheetNumber());
+ assertEquals(5, s2._getSheetRefId());
+ assertEquals(2, s2.getSlideNumber());
+ assertEquals(257, s3._getSheetNumber());
+ assertEquals(4, s3._getSheetRefId());
+ assertEquals(3, s3.getSlideNumber());
+ }
+
+ /**
+ * Test re-ordering slides in a slideshow with 3 slides on it
+ */
+ public void testReOrder3swap() throws Exception {
+ // Has three slides
+ assertEquals(3, ss_three.getSlides().length);
+ Slide s1 = ss_three.getSlides()[0];
+ Slide s2 = ss_three.getSlides()[1];
+ Slide s3 = ss_three.getSlides()[2];
+
+ // Check slide 1 is as expected
+ assertEquals(256, s1._getSheetNumber());
+ assertEquals(3, s1._getSheetRefId()); // no notes on master
+ assertEquals(1, s1.getSlideNumber());
+ // Check slide 2 is as expected (was re-ordered from 3)
+ assertEquals(258, s2._getSheetNumber());
+ assertEquals(5, s2._getSheetRefId()); // no notes on slide
+ assertEquals(2, s2.getSlideNumber());
+ // Check slide 3 is as expected (was re-ordered from 2)
+ assertEquals(257, s3._getSheetNumber());
+ assertEquals(4, s3._getSheetRefId()); // no notes on slide
+ assertEquals(3, s3.getSlideNumber());
+
+ // Put 3 in place of 1
+ // (1 -> 2, 2 -> 3)
+ ss_three.reorderSlide(3, 1);
+
+ // Write out, and read back in
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ hss_three.write(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ HSLFSlideShow hss_read = new HSLFSlideShow(bais);
+ SlideShow ss_read = new SlideShow(hss_read);
+
+ // Check it still has 3 slides
+ assertEquals(3, ss_read.getSlides().length);
+
+ // And check it's as expected
+ s1 = ss_read.getSlides()[0];
+ s2 = ss_read.getSlides()[1];
+ s3 = ss_read.getSlides()[2];
+
+ assertEquals(257, s1._getSheetNumber());
+ assertEquals(4, s1._getSheetRefId());
+ assertEquals(1, s1.getSlideNumber());
+ assertEquals(256, s2._getSheetNumber());
+ assertEquals(3, s2._getSheetRefId());
+ assertEquals(2, s2.getSlideNumber());
+ assertEquals(258, s3._getSheetNumber());
+ assertEquals(5, s3._getSheetRefId());
+ assertEquals(3, s3.getSlideNumber());
+ }
+}