| /* ==================================================================== |
| 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 class BookmarkImpl implements Bookmark |
| { |
| private final GenericPropertyNode first; |
| |
| private BookmarkImpl( GenericPropertyNode first ) |
| { |
| this.first = first; |
| } |
| |
| @Override |
| public boolean equals( Object obj ) |
| { |
| if ( this == obj ) |
| return true; |
| if ( obj == null ) |
| return false; |
| if ( getClass() != obj.getClass() ) |
| return false; |
| BookmarkImpl other = (BookmarkImpl) obj; |
| if ( first == null ) |
| { |
| if ( other.first != null ) |
| return false; |
| } |
| else if ( !first.equals( other.first ) ) |
| return false; |
| return true; |
| } |
| |
| 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(); |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| return 31 + ( first == null ? 0 : first.hashCode() ); |
| } |
| |
| public void setName( String name ) |
| { |
| int currentIndex = bookmarksTables.getDescriptorFirstIndex( first ); |
| bookmarksTables.setName( currentIndex, name ); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "Bookmark [" + getStart() + "; " + getEnd() + "): name: " |
| + getName(); |
| } |
| |
| } |
| |
| private final BookmarksTables bookmarksTables; |
| |
| private Map<Integer, List<GenericPropertyNode>> sortedDescriptors = null; |
| |
| private int[] sortedStartPositions = null; |
| |
| public BookmarksImpl( BookmarksTables bookmarksTables ) |
| { |
| this.bookmarksTables = bookmarksTables; |
| reset(); |
| } |
| |
| void afterDelete( int startCp, int length ) |
| { |
| bookmarksTables.afterDelete( startCp, length ); |
| reset(); |
| } |
| |
| void afterInsert( int startCp, int length ) |
| { |
| bookmarksTables.afterInsert( startCp, length ); |
| reset(); |
| } |
| |
| private Bookmark getBookmark( final GenericPropertyNode first ) |
| { |
| return new BookmarkImpl( first ); |
| } |
| |
| 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]; |
| if ( s < startInclusive ) |
| continue; |
| if ( s >= endExclusive ) |
| break; |
| |
| List<Bookmark> startedAt = getBookmarksAt( s ); |
| if ( startedAt != null ) |
| result.put( Integer.valueOf( s ), startedAt ); |
| } |
| |
| return Collections.unmodifiableMap( result ); |
| } |
| |
| public void remove( int index ) |
| { |
| bookmarksTables.remove( index ); |
| } |
| |
| private void reset() |
| { |
| sortedDescriptors = null; |
| sortedStartPositions = null; |
| } |
| |
| 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 ); |
| } |
| Arrays.sort( indices ); |
| |
| this.sortedDescriptors = result; |
| this.sortedStartPositions = indices; |
| } |
| } |