1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <o3tl/safeint.hxx>
23 #include <comphelper/diagnose_ex.hxx>
25 #include <sal/log.hxx>
27 #include <vcl/metaact.hxx>
28 #include <vcl/gdimtf.hxx>
30 #include "drawshapesubsetting.hxx"
31 #include "gdimtftools.hxx"
35 using namespace ::com::sun::star
;
38 namespace slideshow::internal
45 void DrawShapeSubsetting::ensureInitializedNodeTree() const
47 ENSURE_OR_THROW( mpMtf
,
48 "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
50 if( mbNodeTreeInitialized
)
51 return; // done, already initialized.
53 // init doctree vector
54 maActionClassVector
.clear();
55 maActionClassVector
.reserve( mpMtf
->GetActionSize() );
57 // search metafile for text output
60 sal_Int32
nActionIndex(0);
61 sal_Int32
nLastTextActionIndex(0);
62 for( pCurrAct
= mpMtf
->FirstAction(); pCurrAct
; pCurrAct
= mpMtf
->NextAction() )
64 // check for one of our special text doctree comments
65 switch( pCurrAct
->GetType() )
67 case MetaActionType::COMMENT
:
69 MetaCommentAction
* pAct
= static_cast<MetaCommentAction
*>(pCurrAct
);
71 // skip comment if not a special XTEXT... comment
72 if( pAct
->GetComment().matchIgnoreAsciiCase( "XTEXT" ) )
74 // fill classification vector with NOOPs,
75 // then insert corresponding classes at
77 maActionClassVector
.resize( nActionIndex
+1, CLASS_NOOP
);
79 if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_EOC") )
81 // special, because can happen
82 // in-between of portions - set
83 // character-end classificator at
84 // given index (relative to last text
86 const sal_Int32
nIndex( nLastTextActionIndex
+ pAct
->GetValue() );
88 ENSURE_OR_THROW( o3tl::make_unsigned(nIndex
) < maActionClassVector
.size(),
89 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
91 maActionClassVector
[ nIndex
] = CLASS_CHARACTER_CELL_END
;
93 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_EOW") )
95 // special, because can happen
96 // in-between of portions - set
97 // word-end classificator at given
98 // index (relative to last text
100 const sal_Int32
nIndex( nLastTextActionIndex
+ pAct
->GetValue() );
102 ENSURE_OR_THROW( o3tl::make_unsigned(nIndex
) < maActionClassVector
.size(),
103 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
105 maActionClassVector
[ nIndex
] = CLASS_WORD_END
;
107 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_EOS") )
109 // special, because can happen
110 // in-between of portions - set
111 // sentence-end classificator at given
112 // index (relative to last text
114 const sal_Int32
nIndex( nLastTextActionIndex
+ pAct
->GetValue() );
116 ENSURE_OR_THROW( o3tl::make_unsigned(nIndex
) < maActionClassVector
.size(),
117 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
119 maActionClassVector
[ nIndex
] = CLASS_SENTENCE_END
;
121 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_EOL") )
123 maActionClassVector
[ nActionIndex
] = CLASS_LINE_END
;
125 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_EOP") )
127 maActionClassVector
[ nActionIndex
] = CLASS_PARAGRAPH_END
;
129 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_END") )
131 maActionClassVector
[ nActionIndex
] = CLASS_SHAPE_END
;
133 else if( pAct
->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_BEGIN") )
135 maActionClassVector
[ nActionIndex
] = CLASS_SHAPE_START
;
140 "Shape text structure: " << pAct
->GetComment()
141 << " at action #" << nActionIndex
);
145 case MetaActionType::TEXT
:
146 case MetaActionType::TEXTARRAY
:
147 case MetaActionType::STRETCHTEXT
:
148 nLastTextActionIndex
= nActionIndex
;
149 SAL_INFO("slideshow.verbose", "Shape text \"" <<
150 (static_cast<MetaTextAction
*>(pCurrAct
))->GetText() <<
151 "\" at action #" << nActionIndex
);
154 // comment action and all actions not
155 // explicitly handled here:
156 nActionIndex
+= getNextActionOffset(pCurrAct
);
161 mbNodeTreeInitialized
= true;
164 void DrawShapeSubsetting::excludeSubset(sal_Int32 nExcludedStart
, sal_Int32 nExcludedEnd
)
166 // If current subsets are empty, fill it with initial range
167 initCurrentSubsets();
168 if (maCurrentSubsets
.empty())
170 // Non-subsetting mode (not a subset of anything; child subsets subtract content)
171 maCurrentSubsets
.emplace_back(0, maActionClassVector
.size());
174 slideshow::internal::VectorOfDocTreeNodes aNodesToAppend
;
175 for (auto i
= maCurrentSubsets
.begin(); i
!= maCurrentSubsets
.end();)
177 if (i
->getStartIndex() < nExcludedStart
)
179 if (i
->getEndIndex() > nExcludedStart
)
181 // Some overlap -> append new node (if required), and correct this node's end
182 if (i
->getEndIndex() > nExcludedEnd
)
184 aNodesToAppend
.emplace_back(nExcludedEnd
, i
->getEndIndex());
186 i
->setEndIndex(nExcludedStart
);
190 else if (i
->getStartIndex() < nExcludedEnd
)
192 if (i
->getEndIndex() > nExcludedEnd
)
194 // Partial overlap; change the node's start
195 i
->setStartIndex(nExcludedEnd
);
200 // Node is fully inside the removed range: erase it
201 i
= maCurrentSubsets
.erase(i
);
206 // Node is fully outside (after) excluded range
211 maCurrentSubsets
.insert(maCurrentSubsets
.end(), aNodesToAppend
.begin(),
212 aNodesToAppend
.end());
213 // Excluding subsets must not leave an absolutely empty maCurrentSubsets, because it
214 // would mean "non-subsetting" mode unconditionally, with whole object added to subsets.
215 // So to indicate a subset with all parts excluded, add two empty subsets (starting and
217 if (!maCurrentSubsets
.empty())
220 if (maSubset
.isEmpty())
222 maCurrentSubsets
.emplace_back(0, 0);
223 maCurrentSubsets
.emplace_back(maActionClassVector
.size(),
224 maActionClassVector
.size());
228 maCurrentSubsets
.emplace_back(maSubset
.getStartIndex(),
229 maSubset
.getStartIndex());
230 maCurrentSubsets
.emplace_back(maSubset
.getEndIndex(), maSubset
.getEndIndex());
234 void DrawShapeSubsetting::updateSubsets()
236 maCurrentSubsets
.clear();
237 initCurrentSubsets();
239 for (const auto& rSubsetShape
: maSubsetShapes
)
241 excludeSubset(rSubsetShape
.mnStartActionIndex
, rSubsetShape
.mnEndActionIndex
);
249 DrawShapeSubsetting::DrawShapeSubsetting() :
250 maActionClassVector(),
255 mbNodeTreeInitialized( false )
259 DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode
& rShapeSubset
,
260 GDIMetaFileSharedPtr rMtf
) :
261 maActionClassVector(),
262 mpMtf(std::move( rMtf
)),
263 maSubset( rShapeSubset
),
266 mbNodeTreeInitialized( false )
268 ENSURE_OR_THROW( mpMtf
,
269 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
271 initCurrentSubsets();
274 void DrawShapeSubsetting::reset()
276 maActionClassVector
.clear();
279 maSubsetShapes
.clear();
280 maCurrentSubsets
.clear();
281 mbNodeTreeInitialized
= false;
284 void DrawShapeSubsetting::reset( const ::std::shared_ptr
< GDIMetaFile
>& rMtf
)
289 initCurrentSubsets();
292 void DrawShapeSubsetting::initCurrentSubsets()
294 // only add subset to vector, if vector is empty, and subset is not empty - that's
295 // because the vector's content is later literally used
296 // for e.g. painting.
297 if (maCurrentSubsets
.empty() && !maSubset
.isEmpty())
298 maCurrentSubsets
.push_back( maSubset
);
301 const DocTreeNode
& DrawShapeSubsetting::getSubsetNode() const
306 AttributableShapeSharedPtr
DrawShapeSubsetting::getSubsetShape( const DocTreeNode
& rTreeNode
) const
308 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
310 // subset shape already created for this DocTreeNode?
313 aEntry
.mnStartActionIndex
= rTreeNode
.getStartIndex();
314 aEntry
.mnEndActionIndex
= rTreeNode
.getEndIndex();
316 ShapeSet::const_iterator aIter
;
317 if( (aIter
=maSubsetShapes
.find( aEntry
)) != maSubsetShapes
.end() )
319 // already created, return found entry
320 return aIter
->mpShape
;
323 return AttributableShapeSharedPtr();
326 void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr
& rShape
)
328 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
330 // subset shape already created for this DocTreeNode?
332 const DocTreeNode
& rEffectiveSubset( rShape
->getSubsetNode() );
334 aEntry
.mnStartActionIndex
= rEffectiveSubset
.getStartIndex();
335 aEntry
.mnEndActionIndex
= rEffectiveSubset
.getEndIndex();
337 ShapeSet::const_iterator aIter
;
338 if( (aIter
=maSubsetShapes
.find( aEntry
)) != maSubsetShapes
.end() )
340 // already created, increment use count and return
342 // safe cast, since set order does not depend on
343 // mnSubsetQueriedCount
344 const_cast<SubsetEntry
&>(*aIter
).mnSubsetQueriedCount
++;
348 // not yet created, init entry
349 aEntry
.mnSubsetQueriedCount
= 1;
350 aEntry
.mpShape
= rShape
;
352 maSubsetShapes
.insert( aEntry
);
354 excludeSubset(aEntry
.mnStartActionIndex
, aEntry
.mnEndActionIndex
);
358 bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr
& rShape
)
360 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
362 // lookup subset shape
364 const DocTreeNode
& rEffectiveSubset( rShape
->getSubsetNode() );
366 aEntry
.mnStartActionIndex
= rEffectiveSubset
.getStartIndex();
367 aEntry
.mnEndActionIndex
= rEffectiveSubset
.getEndIndex();
369 ShapeSet::iterator aIter
;
370 if( (aIter
=maSubsetShapes
.find( aEntry
)) == maSubsetShapes
.end() )
371 return false; // not found, subset was never queried
373 // last client of the subset revoking?
374 if( aIter
->mnSubsetQueriedCount
> 1 )
376 // no, still clients out there. Just decrement use count
377 // safe cast, since order does not depend on mnSubsetQueriedCount
378 const_cast<SubsetEntry
&>(*aIter
).mnSubsetQueriedCount
--;
382 "Subset summary: shape " << this << ", "
383 << maSubsetShapes
.size()
384 << " open subsets, revoked subset has refcount "
385 << aIter
->mnSubsetQueriedCount
);
387 return false; // not the last client
392 "Subset summary: shape " << this << ", "
393 << maSubsetShapes
.size()
394 << " open subsets, cleared subset has range ["
395 << aEntry
.mnStartActionIndex
<< ","
396 << aEntry
.mnEndActionIndex
<< "]");
398 // yes, remove from set
399 maSubsetShapes
.erase( aIter
);
402 // update currently active subset for _our_ shape (the
403 // part of this shape that is visible, i.e. not displayed
406 // TODO(P2): This is quite expensive, when
407 // after every subset effect end, we have to scan
408 // the whole shape set
417 /** Iterate over all action classification entries in the
418 given range, pass each element range found to the
421 This method extracts, for each of the different action
422 classifications, the count and the ranges for each of
423 them, and calls the provided functor with that
427 This is the functor's operator() calling signature,
428 with eCurrElemClassification denoting the current
429 classification type the functor is called for,
430 nCurrElemCount the running total of elements visited
431 for the given class (starting from 0), and
432 rCurrElemBegin/rCurrElemEnd the range of the current
433 element (i.e. the iterators from the start to the end
436 bool operator()( IndexClassificator eCurrElemClassification
437 sal_Int32 nCurrElemCount,
438 const IndexClassificatorVector::const_iterator& rCurrElemBegin,
439 const IndexClassificatorVector::const_iterator& rCurrElemEnd );
441 If the functor returns false, iteration over the
442 shapes is immediately stopped.
445 This functor is called for every shape found.
448 Start of range to iterate over
451 End of range to iterate over
453 @return the number of shapes found in the metafile
455 template< typename FunctorT
> void iterateActionClassifications(
456 FunctorT
& io_rFunctor
,
457 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rBegin
,
458 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rEnd
)
460 sal_Int32
nCurrShapeCount( 0 );
461 sal_Int32
nCurrParaCount( 0 );
462 sal_Int32
nCurrLineCount( 0 );
463 sal_Int32
nCurrSentenceCount( 0 );
464 sal_Int32
nCurrWordCount( 0 );
465 sal_Int32
nCurrCharCount( 0 );
467 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastShapeStart(rBegin
);
468 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastParaStart(rBegin
);
469 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastLineStart(rBegin
);
470 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastSentenceStart(rBegin
);
471 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastWordStart(rBegin
);
472 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastCharStart(rBegin
);
474 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext
;
475 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aCurr( rBegin
);
476 while( aCurr
!= rEnd
)
478 // aNext will hold an iterator to the next element
479 // (or the past-the-end iterator, if aCurr
480 // references the last element). Used to pass a
481 // valid half-open range to the functors.
488 ENSURE_OR_THROW( false,
489 "Unexpected type in iterateDocShapes()" );
490 case DrawShapeSubsetting::CLASS_NOOP
:
491 // ignore NOOP actions
494 case DrawShapeSubsetting::CLASS_SHAPE_START
:
495 // regardless of ending action
496 // classifications before: a new shape
497 // always also starts contained elements
504 aLastCharStart
= aCurr
;
507 case DrawShapeSubsetting::CLASS_SHAPE_END
:
508 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END
,
517 [[fallthrough
]]; // shape end also ends lines
518 case DrawShapeSubsetting::CLASS_PARAGRAPH_END
:
519 if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END
,
528 aLastParaStart
= aNext
;
529 [[fallthrough
]]; // para end also ends line
530 case DrawShapeSubsetting::CLASS_LINE_END
:
531 if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END
,
540 aLastLineStart
= aNext
;
542 if( *aCurr
== DrawShapeSubsetting::CLASS_LINE_END
)
544 // DON'T fall through here, as a line
545 // does NOT end neither a sentence,
546 // nor a word. OTOH, all parent
547 // structures (paragraph and shape),
548 // which itself fall through to this
549 // code, DO end word, sentence and
552 // TODO(F1): Maybe a line should end a
553 // character cell, OTOH?
557 case DrawShapeSubsetting::CLASS_SENTENCE_END
:
558 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END
,
566 ++nCurrSentenceCount
;
567 aLastSentenceStart
= aNext
;
569 case DrawShapeSubsetting::CLASS_WORD_END
:
570 if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END
,
579 aLastWordStart
= aNext
;
581 case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END
:
583 // This is a special case since a character cell
584 // (AKA grapheme cluster) can have multiple
585 // characters, so if we passed nCurrCharCount to
586 // io_rFunctor() it would stop at the first
587 // character in the cluster, so we subtract one
588 // so that it matches when we reach the start of
590 if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END
,
599 aLastCharStart
= aCurr
;
607 DrawShapeSubsetting::IndexClassificator
mapDocTreeNode( DocTreeNode::NodeType eNodeType
)
612 SAL_WARN( "slideshow", "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
613 return DrawShapeSubsetting::CLASS_NOOP
;
615 case DocTreeNode::NodeType::LogicalParagraph
:
616 return DrawShapeSubsetting::CLASS_PARAGRAPH_END
;
618 case DocTreeNode::NodeType::LogicalWord
:
619 return DrawShapeSubsetting::CLASS_WORD_END
;
621 case DocTreeNode::NodeType::LogicalCharacterCell
:
622 return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END
;
626 /// Counts number of class occurrences
627 class CountClassFunctor
630 explicit CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass
) :
636 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification
,
637 sal_Int32
/*nCurrElemCount*/,
638 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& /*rCurrElemBegin*/,
639 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& /*rCurrElemEnd*/ )
641 if( eCurrElemClassification
== meClass
)
644 return true; // never stop, count all occurrences
647 sal_Int32
getCount() const
653 DrawShapeSubsetting::IndexClassificator meClass
;
654 sal_Int32 mnCurrCount
;
658 sal_Int32
DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rBegin
,
659 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rEnd
,
660 DocTreeNode::NodeType eNodeType
)
662 const IndexClassificator
eRequestedClass(
663 mapDocTreeNode( eNodeType
) );
665 // create a counting functor for the requested class of
667 CountClassFunctor
aFunctor( eRequestedClass
);
669 // count all occurrences in the given range
670 iterateActionClassifications( aFunctor
, rBegin
, rEnd
);
672 return aFunctor
.getCount();
675 sal_Int32
DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType
) const
677 ensureInitializedNodeTree();
679 return implGetNumberOfTreeNodes( maActionClassVector
.begin(),
680 maActionClassVector
.end(),
686 /** This functor finds the nth occurrence of a given
689 The operator() compares the given index value with the
690 requested index, as given on the functor's
691 constructor. Then, the operator() returns false,
692 denoting that the requested action is found.
694 class FindNthElementFunctor
697 FindNthElementFunctor( sal_Int32 nNodeIndex
,
698 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rLastBegin
,
699 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rLastEnd
,
700 DrawShapeSubsetting::IndexClassificator eClass
) :
701 mnNodeIndex( nNodeIndex
),
702 mrLastBegin( rLastBegin
),
703 mrLastEnd( rLastEnd
),
708 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification
,
709 sal_Int32 nCurrElemCount
,
710 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rCurrElemBegin
,
711 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rCurrElemEnd
)
713 if( eCurrElemClassification
== meClass
&&
714 nCurrElemCount
== mnNodeIndex
)
716 mrLastBegin
= rCurrElemBegin
;
717 mrLastEnd
= rCurrElemEnd
;
719 return false; // abort iteration, we've
720 // already found what we've been
724 return true; // keep on truckin'
728 sal_Int32 mnNodeIndex
;
729 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& mrLastBegin
;
730 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& mrLastEnd
;
731 DrawShapeSubsetting::IndexClassificator meClass
;
734 DocTreeNode
makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rBegin
,
735 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rStart
,
736 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
& rEnd
)
738 return DocTreeNode( ::std::distance(rBegin
,
740 ::std::distance(rBegin
,
745 DocTreeNode
DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator
& rBegin
,
746 const IndexClassificatorVector::const_iterator
& rEnd
,
747 sal_Int32 nNodeIndex
,
748 DocTreeNode::NodeType eNodeType
) const
750 const IndexClassificator
eRequestedClass(
751 mapDocTreeNode( eNodeType
) );
753 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastBegin(rEnd
);
754 DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aLastEnd(rEnd
);
756 // create a nth element functor for the requested class of
757 // actions, and nNodeIndex as the target index
758 FindNthElementFunctor
aFunctor( nNodeIndex
,
763 // find given index in the given range
764 iterateActionClassifications( aFunctor
, rBegin
, rEnd
);
766 return makeTreeNode( maActionClassVector
.begin(),
767 aLastBegin
, aLastEnd
);
770 DocTreeNode
DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex
,
771 DocTreeNode::NodeType eNodeType
) const
773 ensureInitializedNodeTree();
775 return implGetTreeNode( maActionClassVector
.begin(),
776 maActionClassVector
.end(),
781 sal_Int32
DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode
& rParentNode
,
782 DocTreeNode::NodeType eNodeType
) const
784 ensureInitializedNodeTree();
786 // convert from vector indices to vector iterators
787 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aBegin( maActionClassVector
.begin() );
788 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aParentBegin( aBegin
+ rParentNode
.getStartIndex() );
789 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aParentEnd( aBegin
+ rParentNode
.getEndIndex() );
791 return implGetNumberOfTreeNodes( aParentBegin
,
796 DocTreeNode
DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode
& rParentNode
,
797 sal_Int32 nNodeIndex
,
798 DocTreeNode::NodeType eNodeType
) const
800 ensureInitializedNodeTree();
802 // convert from vector indices to vector iterators
803 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aBegin( maActionClassVector
.begin() );
804 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aParentBegin( aBegin
+ rParentNode
.getStartIndex() );
805 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator
aParentEnd( aBegin
+ rParentNode
.getEndIndex() );
807 return implGetTreeNode( aParentBegin
,
816 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */