split BookmarksTables to internal and user-friendly API

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1148810 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sergey Vladimirov 2011-07-20 15:03:43 +00:00
parent 77277a7acd
commit 2113215046
7 changed files with 349 additions and 66 deletions

View File

@ -38,7 +38,7 @@
<action dev="poi-developers" type="fix">51481 - Fixed autofilters in HSSF to avoid warnings in Excel 2007</action>
<action dev="poi-developers" type="fix">51533 - Avoid exception when changing name of a sheet containing shared formulas</action>
<action dev="poi-developers" type="add">Support for appending images to existing drawings in HSSF</action>
<action dev="poi-developers" type="fix">Added initial support for bookmarks in HWFP</action>
<action dev="poi-developers" type="fix">Added initial support for bookmarks in HWPF</action>
<action dev="poi-developers" type="fix">46250 - Fixed cloning worksheets with images</action>
<action dev="poi-developers" type="fix">51524 - PapBinTable constructor is slow (regression)</action>
<action dev="poi-developers" type="fix">51514 - allow HSSFObjectData to work with both POIFS and NPOIFS</action>

View File

@ -48,6 +48,8 @@ import org.apache.poi.hwpf.model.TextPiece;
import org.apache.poi.hwpf.model.TextPieceTable;
import org.apache.poi.hwpf.model.io.HWPFFileSystem;
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
import org.apache.poi.hwpf.usermodel.Bookmarks;
import org.apache.poi.hwpf.usermodel.BookmarksImpl;
import org.apache.poi.hwpf.usermodel.HWPFList;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.poifs.common.POIFSConstants;
@ -102,9 +104,12 @@ public final class HWPFDocument extends HWPFDocumentCore
/** Holds Office Art objects */
protected ShapesTable _officeArts;
/** Holds the bookmarks */
/** Holds the bookmarks tables */
protected BookmarksTables _bookmarksTables;
/** Holds the bookmarks */
protected Bookmarks _bookmarks;
/** Holds the fields PLCFs */
protected FieldsTables _fieldsTables;
@ -267,6 +272,7 @@ public final class HWPFDocument extends HWPFDocumentCore
}
_bookmarksTables = new BookmarksTables( _tableStream, _fib );
_bookmarks = new BookmarksImpl( _bookmarksTables );
_fieldsTables = new FieldsTables(_tableStream, _fib);
}
@ -444,12 +450,11 @@ public final class HWPFDocument extends HWPFDocumentCore
}
/**
* @return BookmarksTables object, that is able to extract bookmarks
* descriptors from this document
* @return user-friendly interface to access document bookmarks
*/
public BookmarksTables getBookmarksTables()
public Bookmarks getBookmarks()
{
return _bookmarksTables;
return _bookmarks;
}
/**

View File

@ -1,10 +1,25 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.hwpf.model;
import java.io.IOException;
import java.util.Arrays;
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
import org.apache.poi.hwpf.usermodel.Bookmark;
public class BookmarksTables
{
@ -14,67 +29,55 @@ public class BookmarksTables
private String[] names = new String[0];
public BookmarksTables()
{
}
public BookmarksTables( byte[] tableStream, FileInformationBlock fib )
{
read( tableStream, fib );
}
public Bookmark getBookmark( int index )
{
final GenericPropertyNode first = descriptorsFirst.getProperty( index );
return new Bookmark()
{
public int getEnd()
{
int currentIndex = Arrays.asList(
descriptorsFirst.toPropertiesArray() ).indexOf( first );
if ( currentIndex >= descriptorsLim.length() )
return first.getEnd();
GenericPropertyNode lim = descriptorsLim
.getProperty( currentIndex );
return lim.getStart();
}
public String getName()
{
int currentIndex = Arrays.asList(
descriptorsFirst.toPropertiesArray() ).indexOf( first );
if ( currentIndex >= names.length )
return "";
return names[currentIndex];
}
public int getStart()
{
return first.getStart();
}
public void setName( String name )
{
int currentIndex = Arrays.asList(
descriptorsFirst.toPropertiesArray() ).indexOf( first );
if ( currentIndex < names.length )
{
String[] newNames = new String[currentIndex + 1];
System.arraycopy( names, 0, newNames, 0, names.length );
names = newNames;
}
names[currentIndex] = name;
}
};
}
public int getBookmarksCount()
{
return descriptorsFirst.length();
}
public GenericPropertyNode getDescriptorFirst( int index )
throws IndexOutOfBoundsException
{
return descriptorsFirst.getProperty( index );
}
public int getDescriptorFirstIndex( GenericPropertyNode descriptorFirst )
{
// TODO: very non-optimal
return Arrays.asList( descriptorsFirst.toPropertiesArray() ).indexOf(
descriptorFirst );
}
public GenericPropertyNode getDescriptorLim( int index )
throws IndexOutOfBoundsException
{
return descriptorsLim.getProperty( index );
}
public int getDescriptorsFirstCount()
{
return descriptorsFirst.length();
}
public int getDescriptorsLimCount()
{
return descriptorsLim.length();
}
public String getName( int index ) throws ArrayIndexOutOfBoundsException
{
return names[index];
}
public int getNamesCount()
{
return names.length;
}
private void read( byte[] tableStream, FileInformationBlock fib )
{
int namesStart = fib.getFcSttbfbkmk();
@ -97,6 +100,17 @@ public class BookmarksTables
limDescriptorsLength, 0 );
}
public void setName( int index, String name )
{
if ( index < names.length )
{
String[] newNames = new String[index + 1];
System.arraycopy( names, 0, newNames, 0, names.length );
names = newNames;
}
names[index] = name;
}
public void writePlcfBkmkf( FileInformationBlock fib,
HWPFOutputStream tableStream ) throws IOException
{

View File

@ -35,9 +35,10 @@ import org.apache.poi.util.POILogger;
public abstract class PropertyNode<T extends PropertyNode<T>> implements Comparable<T>, Cloneable
{
static final class EndComparator implements Comparator<PropertyNode<?>>
public static final class EndComparator implements
Comparator<PropertyNode<?>>
{
static EndComparator instance = new EndComparator();
public static EndComparator instance = new EndComparator();
public int compare( PropertyNode<?> o1, PropertyNode<?> o2 )
{
@ -48,9 +49,10 @@ public abstract class PropertyNode<T extends PropertyNode<T>> implements Compar
}
}
static final class StartComparator implements Comparator<PropertyNode<?>>
public static final class StartComparator implements
Comparator<PropertyNode<?>>
{
static StartComparator instance = new StartComparator();
public static StartComparator instance = new StartComparator();
public int compare( PropertyNode<?> o1, PropertyNode<?> o2 )
{

View File

@ -0,0 +1,50 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.hwpf.usermodel;
import java.util.List;
import java.util.Map;
/**
* User-friendly interface to access document bookmarks
*
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
*/
public interface Bookmarks
{
/**
* @param index
* bookmark document index
* @return {@link Bookmark} with specified index
* @throws IndexOutOfBoundsException
* if bookmark with specified index not present in document
*/
Bookmark getBookmark( int index ) throws IndexOutOfBoundsException;
/**
* @return count of {@link Bookmark}s in document
*/
int getBookmarksCount();
/**
* @return {@link Map} of bookmarks started in specified range, where key is
* start position and value is sorted {@link List} of
* {@link Bookmark}
*/
Map<Integer, List<Bookmark>> getBookmarksStartedBetween(
int startInclusive, int endExclusive );
}

View File

@ -0,0 +1,189 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.hwpf.usermodel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.poi.hwpf.model.BookmarksTables;
import org.apache.poi.hwpf.model.GenericPropertyNode;
import org.apache.poi.hwpf.model.PropertyNode;
/**
* Implementation of user-friendly interface for document bookmarks
*
* @author Sergey Vladimirov (vlsergey {at} gmail {doc} com)
*/
public class BookmarksImpl implements Bookmarks
{
private final BookmarksTables bookmarksTables;
private Map<Integer, List<GenericPropertyNode>> sortedDescriptors = null;
private int[] sortedStartPositions = null;
public BookmarksImpl( BookmarksTables bookmarksTables )
{
this.bookmarksTables = bookmarksTables;
}
private Bookmark getBookmark( final GenericPropertyNode first )
{
return new Bookmark()
{
public int getEnd()
{
int currentIndex = bookmarksTables
.getDescriptorFirstIndex( first );
try
{
GenericPropertyNode descriptorLim = bookmarksTables
.getDescriptorLim( currentIndex );
return descriptorLim.getStart();
}
catch ( IndexOutOfBoundsException exc )
{
return first.getEnd();
}
}
public String getName()
{
int currentIndex = bookmarksTables
.getDescriptorFirstIndex( first );
try
{
return bookmarksTables.getName( currentIndex );
}
catch ( ArrayIndexOutOfBoundsException exc )
{
return "";
}
}
public int getStart()
{
return first.getStart();
}
public void setName( String name )
{
int currentIndex = bookmarksTables
.getDescriptorFirstIndex( first );
bookmarksTables.setName( currentIndex, name );
}
};
}
public Bookmark getBookmark( int index )
{
final GenericPropertyNode first = bookmarksTables
.getDescriptorFirst( index );
return getBookmark( first );
}
public List<Bookmark> getBookmarksAt( int startCp )
{
updateSortedDescriptors();
List<GenericPropertyNode> nodes = sortedDescriptors.get( Integer
.valueOf( startCp ) );
if ( nodes == null || nodes.isEmpty() )
return Collections.emptyList();
List<Bookmark> result = new ArrayList<Bookmark>( nodes.size() );
for ( GenericPropertyNode node : nodes )
{
result.add( getBookmark( node ) );
}
return Collections.unmodifiableList( result );
}
public int getBookmarksCount()
{
return bookmarksTables.getDescriptorsFirstCount();
}
public Map<Integer, List<Bookmark>> getBookmarksStartedBetween(
int startInclusive, int endExclusive )
{
updateSortedDescriptors();
int startLookupIndex = Arrays.binarySearch( this.sortedStartPositions,
startInclusive );
if ( startLookupIndex < 0 )
startLookupIndex = -( startLookupIndex + 1 );
int endLookupIndex = Arrays.binarySearch( this.sortedStartPositions,
endExclusive );
if ( endLookupIndex < 0 )
endLookupIndex = -( endLookupIndex + 1 );
Map<Integer, List<Bookmark>> result = new LinkedHashMap<Integer, List<Bookmark>>();
for ( int lookupIndex = startLookupIndex; lookupIndex < endLookupIndex; lookupIndex++ )
{
int s = sortedStartPositions[lookupIndex];
List<Bookmark> startedAt = getBookmarksAt( s );
if ( startedAt != null )
result.put( Integer.valueOf( s ), startedAt );
}
return Collections.unmodifiableMap( result );
}
private void updateSortedDescriptors()
{
if ( sortedDescriptors != null )
return;
Map<Integer, List<GenericPropertyNode>> result = new HashMap<Integer, List<GenericPropertyNode>>();
for ( int b = 0; b < bookmarksTables.getDescriptorsFirstCount(); b++ )
{
GenericPropertyNode property = bookmarksTables
.getDescriptorFirst( b );
Integer positionKey = Integer.valueOf( property.getStart() );
List<GenericPropertyNode> atPositionList = result.get( positionKey );
if ( atPositionList == null )
{
atPositionList = new LinkedList<GenericPropertyNode>();
result.put( positionKey, atPositionList );
}
atPositionList.add( property );
}
int counter = 0;
int[] indices = new int[result.size()];
for ( Map.Entry<Integer, List<GenericPropertyNode>> entry : result
.entrySet() )
{
indices[counter++] = entry.getKey().intValue();
List<GenericPropertyNode> updated = new ArrayList<GenericPropertyNode>(
entry.getValue() );
Collections.sort( updated, PropertyNode.EndComparator.instance );
entry.setValue( updated );
}
this.sortedDescriptors = result;
this.sortedStartPositions = indices;
}
}

View File

@ -1,3 +1,19 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.hwpf.model;
import junit.framework.TestCase;
@ -5,17 +21,24 @@ import junit.framework.TestCase;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.HWPFTestDataSamples;
import org.apache.poi.hwpf.usermodel.Bookmark;
import org.apache.poi.hwpf.usermodel.Bookmarks;
/**
* Test cases for {@link BookmarksTables} and default implementation of
* {@link Bookmarks}
*
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
*/
public class TestBookmarksTables extends TestCase
{
public void test()
{
HWPFDocument doc = HWPFTestDataSamples.openSampleFile( "pageref.doc" );
BookmarksTables bookmarksTables = doc.getBookmarksTables();
Bookmarks bookmarks = doc.getBookmarks();
assertEquals( 1, bookmarksTables.getBookmarksCount() );
assertEquals( 1, bookmarks.getBookmarksCount() );
Bookmark bookmark = bookmarksTables.getBookmark( 0 );
Bookmark bookmark = bookmarks.getBookmark( 0 );
assertEquals( "userref", bookmark.getName() );
assertEquals( 27, bookmark.getStart() );
assertEquals( 38, bookmark.getEnd() );