android: Update app-specific/MIME type icons
[LibreOffice.git] / slideshow / source / engine / shapes / drawshapesubsetting.cxx
blob13ea0300fa63697977a01614a976160bb15cf5e7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
26 #include <utility>
27 #include <vcl/metaact.hxx>
28 #include <vcl/gdimtf.hxx>
30 #include "drawshapesubsetting.hxx"
31 #include "gdimtftools.hxx"
33 #include <algorithm>
35 using namespace ::com::sun::star;
38 namespace slideshow::internal
42 // Private methods
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
58 MetaAction* pCurrAct;
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
76 // the given index
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
85 // action).
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
99 // action).
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
113 // action).
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;
138 SAL_INFO(
139 "slideshow",
140 "Shape text structure: " << pAct->GetComment()
141 << " at action #" << nActionIndex);
142 ++nActionIndex;
143 break;
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 );
152 [[fallthrough]];
153 default:
154 // comment action and all actions not
155 // explicitly handled here:
156 nActionIndex += getNextActionOffset(pCurrAct);
157 break;
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);
188 ++i;
190 else if (i->getStartIndex() < nExcludedEnd)
192 if (i->getEndIndex() > nExcludedEnd)
194 // Partial overlap; change the node's start
195 i->setStartIndex(nExcludedEnd);
196 ++i;
198 else
200 // Node is fully inside the removed range: erase it
201 i = maCurrentSubsets.erase(i);
204 else
206 // Node is fully outside (after) excluded range
207 ++i;
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
216 // ending).
217 if (!maCurrentSubsets.empty())
218 return;
220 if (maSubset.isEmpty())
222 maCurrentSubsets.emplace_back(0, 0);
223 maCurrentSubsets.emplace_back(maActionClassVector.size(),
224 maActionClassVector.size());
226 else
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);
246 // Public methods
249 DrawShapeSubsetting::DrawShapeSubsetting() :
250 maActionClassVector(),
251 mpMtf(),
252 maSubset(),
253 maSubsetShapes(),
254 maCurrentSubsets(),
255 mbNodeTreeInitialized( false )
259 DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
260 GDIMetaFileSharedPtr rMtf ) :
261 maActionClassVector(),
262 mpMtf(std::move( rMtf )),
263 maSubset( rShapeSubset ),
264 maSubsetShapes(),
265 maCurrentSubsets(),
266 mbNodeTreeInitialized( false )
268 ENSURE_OR_THROW( mpMtf,
269 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
271 initCurrentSubsets();
274 void DrawShapeSubsetting::reset()
276 maActionClassVector.clear();
277 mpMtf.reset();
278 maSubset.reset();
279 maSubsetShapes.clear();
280 maCurrentSubsets.clear();
281 mbNodeTreeInitialized = false;
284 void DrawShapeSubsetting::reset( const ::std::shared_ptr< GDIMetaFile >& rMtf )
286 reset();
287 mpMtf = 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
303 return maSubset;
306 AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
308 SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
310 // subset shape already created for this DocTreeNode?
311 SubsetEntry aEntry;
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?
331 SubsetEntry aEntry;
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++;
346 else
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
363 SubsetEntry aEntry;
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--;
380 SAL_INFO(
381 "slideshow",
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
390 SAL_INFO(
391 "slideshow",
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
404 // in subset shapes)
406 // TODO(P2): This is quite expensive, when
407 // after every subset effect end, we have to scan
408 // the whole shape set
410 updateSubsets();
412 return true;
415 namespace
417 /** Iterate over all action classification entries in the
418 given range, pass each element range found to the
419 given functor.
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
424 information.
426 @tpl FunctorT
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
434 of this element).
435 <pre>
436 bool operator()( IndexClassificator eCurrElemClassification
437 sal_Int32 nCurrElemCount,
438 const IndexClassificatorVector::const_iterator& rCurrElemBegin,
439 const IndexClassificatorVector::const_iterator& rCurrElemEnd );
440 </pre>
441 If the functor returns false, iteration over the
442 shapes is immediately stopped.
444 @param io_pFunctor
445 This functor is called for every shape found.
447 @param rBegin
448 Start of range to iterate over
450 @param rEnd
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.
482 aNext = aCurr;
483 ++aNext;
485 switch( *aCurr )
487 default:
488 ENSURE_OR_THROW( false,
489 "Unexpected type in iterateDocShapes()" );
490 case DrawShapeSubsetting::CLASS_NOOP:
491 // ignore NOOP actions
492 break;
494 case DrawShapeSubsetting::CLASS_SHAPE_START:
495 // regardless of ending action
496 // classifications before: a new shape
497 // always also starts contained elements
498 // anew
499 aLastShapeStart =
500 aLastParaStart =
501 aLastLineStart =
502 aLastSentenceStart =
503 aLastWordStart =
504 aLastCharStart = aCurr;
505 break;
507 case DrawShapeSubsetting::CLASS_SHAPE_END:
508 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
509 nCurrShapeCount,
510 aLastShapeStart,
511 aNext ) )
513 return;
516 ++nCurrShapeCount;
517 [[fallthrough]]; // shape end also ends lines
518 case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
519 if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
520 nCurrParaCount,
521 aLastParaStart,
522 aNext ) )
524 return;
527 ++nCurrParaCount;
528 aLastParaStart = aNext;
529 [[fallthrough]]; // para end also ends line
530 case DrawShapeSubsetting::CLASS_LINE_END:
531 if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
532 nCurrLineCount,
533 aLastLineStart,
534 aNext ) )
536 return;
539 ++nCurrLineCount;
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
550 // character cell.
552 // TODO(F1): Maybe a line should end a
553 // character cell, OTOH?
554 break;
556 [[fallthrough]];
557 case DrawShapeSubsetting::CLASS_SENTENCE_END:
558 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
559 nCurrSentenceCount,
560 aLastSentenceStart,
561 aNext ) )
563 return;
566 ++nCurrSentenceCount;
567 aLastSentenceStart = aNext;
568 [[fallthrough]];
569 case DrawShapeSubsetting::CLASS_WORD_END:
570 if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
571 nCurrWordCount,
572 aLastWordStart,
573 aNext ) )
575 return;
578 ++nCurrWordCount;
579 aLastWordStart = aNext;
580 [[fallthrough]];
581 case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
582 // tdf#113290
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
589 // the next cluster.
590 if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
591 nCurrCharCount - 1,
592 aLastCharStart,
593 aCurr ) )
595 return;
598 ++nCurrCharCount;
599 aLastCharStart = aCurr;
600 break;
603 aCurr = aNext;
607 DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
609 switch( eNodeType )
611 default:
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
629 public:
630 explicit CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
631 meClass( eClass ),
632 mnCurrCount(0)
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 )
642 ++mnCurrCount;
644 return true; // never stop, count all occurrences
647 sal_Int32 getCount() const
649 return mnCurrCount;
652 private:
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
666 // actions
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(),
681 eNodeType );
684 namespace
686 /** This functor finds the nth occurrence of a given
687 action class.
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
696 public:
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 ),
704 meClass( eClass )
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
721 // looking for
724 return true; // keep on truckin'
727 private:
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,
739 rStart),
740 ::std::distance(rBegin,
741 rEnd) );
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,
759 aLastBegin,
760 aLastEnd,
761 eRequestedClass );
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(),
777 nNodeIndex,
778 eNodeType );
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,
792 aParentEnd,
793 eNodeType );
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,
808 aParentEnd,
809 nNodeIndex,
810 eNodeType );
816 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */