merge the formfield patch from ooo-build
[ooovba.git] / slideshow / source / engine / shapes / drawshapesubsetting.cxx
blob45a066df08962652a8c0eabe29b72a1c91a36c36
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: drawshapesubsetting.cxx,v $
10 * $Revision: 1.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 // must be first
35 #include <canvas/debug.hxx>
36 #include <tools/diagnose_ex.h>
37 #include <canvas/verbosetrace.hxx>
39 #include <rtl/math.hxx>
40 #include <rtl/logfile.hxx>
42 #include <vcl/metaact.hxx>
43 #include <vcl/gdimtf.hxx>
44 #include <basegfx/numeric/ftools.hxx>
46 #include "drawshapesubsetting.hxx"
47 #include "drawshape.hxx"
49 #include <boost/bind.hpp>
51 #include <algorithm>
52 #include <functional>
53 #include <limits>
55 using namespace ::com::sun::star;
58 namespace slideshow
60 namespace internal
63 //////////////////////////////////////////////////////////////////////
65 // Private methods
67 //////////////////////////////////////////////////////////////////////
69 void DrawShapeSubsetting::ensureInitializedNodeTree() const
71 ENSURE_OR_THROW( mpMtf,
72 "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
74 if( mbNodeTreeInitialized )
75 return; // done, already initialized.
77 // init doctree vector
78 maActionClassVector.clear();
79 maActionClassVector.reserve( mpMtf->GetActionCount() );
81 // search metafile for text output
82 MetaAction* pCurrAct;
84 sal_Int32 nActionIndex(0);
85 sal_Int32 nLastTextActionIndex(0);
86 for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
88 // check for one of our special text doctree comments
89 switch( pCurrAct->GetType() )
91 case META_COMMENT_ACTION:
93 MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
95 // skip comment if not a special XTEXT comment
96 if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT", 5 ) == COMPARE_EQUAL )
98 // fill classification vector with NOOPs,
99 // then insert corresponding classes at
100 // the given index
101 maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
103 if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOC" ) == COMPARE_EQUAL )
105 // special, because can happen
106 // in-between of portions - set
107 // character-end classificator at
108 // given index (relative to last text
109 // action).
110 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
112 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
113 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
115 maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
117 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOW" ) == COMPARE_EQUAL )
119 // special, because can happen
120 // in-between of portions - set
121 // word-end classificator at given
122 // index (relative to last text
123 // action).
124 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
126 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
127 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
129 maActionClassVector[ nIndex ] = CLASS_WORD_END;
131 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOS" ) == COMPARE_EQUAL )
133 // special, because can happen
134 // in-between of portions - set
135 // sentence-end classificator at given
136 // index (relative to last text
137 // action).
138 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
140 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
141 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
143 maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
145 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOL" ) == COMPARE_EQUAL )
147 maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
149 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_EOP" ) == COMPARE_EQUAL )
151 maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
153 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_END" ) == COMPARE_EQUAL )
155 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
157 else if( pAct->GetComment().CompareIgnoreCaseToAscii( "XTEXT_PAINTSHAPE_BEGIN" ) == COMPARE_EQUAL )
159 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
162 ++nActionIndex;
163 break;
165 case META_TEXT_ACTION:
166 case META_TEXTARRAY_ACTION:
167 case META_STRETCHTEXT_ACTION:
168 nLastTextActionIndex = nActionIndex;
169 // fallthrough intended
170 default:
171 // comment action and all actions not
172 // explicitely handled here:
173 nActionIndex += getNextActionOffset(pCurrAct);
174 break;
178 mbNodeTreeInitialized = true;
181 void DrawShapeSubsetting::updateSubsetBounds( const SubsetEntry& rSubsetEntry )
183 // TODO(F1): This removes too much from non-contiguous subsets
184 mnMinSubsetActionIndex = ::std::min(
185 mnMinSubsetActionIndex,
186 rSubsetEntry.mnStartActionIndex );
187 mnMaxSubsetActionIndex = ::std::max(
188 mnMaxSubsetActionIndex,
189 rSubsetEntry.mnEndActionIndex );
192 void DrawShapeSubsetting::updateSubsets()
194 maCurrentSubsets.clear();
196 if( !maSubsetShapes.empty() )
198 if( maSubset.isEmpty() )
200 // non-subsetted node, with some child subsets
201 // that subtract from it
202 maCurrentSubsets.push_back( DocTreeNode( 0,
203 mnMinSubsetActionIndex,
204 DocTreeNode::NODETYPE_INVALID ) );
205 maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
206 maActionClassVector.size(),
207 DocTreeNode::NODETYPE_INVALID ) );
209 else
211 // subsetted node, from which some further child
212 // subsets subtract content
213 maCurrentSubsets.push_back( DocTreeNode( maSubset.getStartIndex(),
214 mnMinSubsetActionIndex,
215 DocTreeNode::NODETYPE_INVALID ) );
216 maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
217 maSubset.getEndIndex(),
218 DocTreeNode::NODETYPE_INVALID ) );
221 else
223 // no further child subsets, simply add our subset (if any)
224 if( !maSubset.isEmpty() )
226 // subsetted node, without any subset children
227 maCurrentSubsets.push_back( maSubset );
232 //////////////////////////////////////////////////////////////////////
234 // Public methods
236 //////////////////////////////////////////////////////////////////////
238 DrawShapeSubsetting::DrawShapeSubsetting() :
239 maActionClassVector(),
240 mpMtf(),
241 maSubset(),
242 maSubsetShapes(),
243 mnMinSubsetActionIndex( SAL_MAX_INT32 ),
244 mnMaxSubsetActionIndex(0),
245 maCurrentSubsets(),
246 mbNodeTreeInitialized( false )
250 DrawShapeSubsetting::DrawShapeSubsetting( const GDIMetaFileSharedPtr& rMtf ) :
251 maActionClassVector(),
252 mpMtf( rMtf ),
253 maSubset(),
254 maSubsetShapes(),
255 mnMinSubsetActionIndex( SAL_MAX_INT32 ),
256 mnMaxSubsetActionIndex(0),
257 maCurrentSubsets(),
258 mbNodeTreeInitialized( false )
260 ENSURE_OR_THROW( mpMtf,
261 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
263 initCurrentSubsets();
266 DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
267 const GDIMetaFileSharedPtr& rMtf ) :
268 maActionClassVector(),
269 mpMtf( rMtf ),
270 maSubset( rShapeSubset ),
271 maSubsetShapes(),
272 mnMinSubsetActionIndex( SAL_MAX_INT32 ),
273 mnMaxSubsetActionIndex(0),
274 maCurrentSubsets(),
275 mbNodeTreeInitialized( false )
277 ENSURE_OR_THROW( mpMtf,
278 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
280 initCurrentSubsets();
283 void DrawShapeSubsetting::reset()
285 maActionClassVector.clear();
286 mpMtf.reset();
287 maSubset.reset();
288 maSubsetShapes.clear();
289 mnMinSubsetActionIndex = SAL_MAX_INT32;
290 mnMaxSubsetActionIndex = 0;
291 maCurrentSubsets.clear();
292 mbNodeTreeInitialized = false;
295 void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
297 reset();
298 mpMtf = rMtf;
300 initCurrentSubsets();
303 void DrawShapeSubsetting::reset( const DocTreeNode& rShapeSubset,
304 const ::boost::shared_ptr< GDIMetaFile >& rMtf )
306 reset();
307 mpMtf = rMtf;
308 maSubset = rShapeSubset;
310 initCurrentSubsets();
313 void DrawShapeSubsetting::initCurrentSubsets()
315 // only add subset to vector, if it's not empty - that's
316 // because the vector's content is later literally used
317 // for e.g. painting.
318 if( !maSubset.isEmpty() )
319 maCurrentSubsets.push_back( maSubset );
322 DocTreeNode DrawShapeSubsetting::getSubsetNode() const
324 return maSubset;
327 bool DrawShapeSubsetting::hasSubsetShapes() const
329 return !maSubsetShapes.empty();
332 AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
334 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
336 // subset shape already created for this DocTreeNode?
337 SubsetEntry aEntry;
339 aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
340 aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
342 ShapeSet::const_iterator aIter;
343 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
345 // already created, return found entry
346 return aIter->mpShape;
349 return AttributableShapeSharedPtr();
352 void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
354 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
356 // subset shape already created for this DocTreeNode?
357 SubsetEntry aEntry;
358 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
360 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
361 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
363 ShapeSet::const_iterator aIter;
364 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
366 // already created, increment use count and return
368 // safe cast, since set order does not depend on
369 // mnSubsetQueriedCount
370 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
372 else
374 // not yet created, init entry
375 aEntry.mnSubsetQueriedCount = 1;
376 aEntry.mpShape = rShape;
378 maSubsetShapes.insert( aEntry );
380 // update cached subset borders
381 updateSubsetBounds( aEntry );
382 updateSubsets();
386 bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
388 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
390 // lookup subset shape
391 SubsetEntry aEntry;
392 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
394 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
395 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
397 ShapeSet::iterator aIter;
398 if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
399 return false; // not found, subset was never queried
401 // last client of the subset revoking?
402 if( aIter->mnSubsetQueriedCount > 1 )
404 // no, still clients out there. Just decrement use count
405 // safe cast, since order does not depend on mnSubsetQueriedCount
406 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
408 VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, revoked subset has refcount %d",
409 this,
410 maSubsetShapes.size(),
411 aIter->mnSubsetQueriedCount );
413 return false; // not the last client
416 VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, cleared subset has range [%d,%d]",
417 this,
418 maSubsetShapes.size(),
419 aEntry.mnStartActionIndex,
420 aEntry.mnEndActionIndex );
422 // yes, remove from set
423 maSubsetShapes.erase( aIter );
426 // update currently active subset for _our_ shape (the
427 // part of this shape that is visible, i.e. not displayed
428 // in subset shapes)
429 // ======================================================
431 // init bounds
432 mnMinSubsetActionIndex = SAL_MAX_INT32;
433 mnMaxSubsetActionIndex = 0;
435 // TODO(P2): This is quite expensive, when
436 // after every subset effect end, we have to scan
437 // the whole shape set
439 // determine new subset range
440 ::std::for_each( maSubsetShapes.begin(),
441 maSubsetShapes.end(),
442 ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
443 this,
444 _1 ) );
446 updateSubsets();
448 return true;
451 namespace
453 /** Iterate over all action classification entries in the
454 given range, pass each element range found to the
455 given functor.
457 This method extracts, for each of the different action
458 classifications, the count and the ranges for each of
459 them, and calls the provided functor with that
460 information.
462 @tpl FunctorT
463 This is the functor's operator() calling signature,
464 with eCurrElemClassification denoting the current
465 classification type the functor is called for,
466 nCurrElemCount the running total of elements visited
467 for the given class (starting from 0), and
468 rCurrElemBegin/rCurrElemEnd the range of the current
469 element (i.e. the iterators from the start to the end
470 of this element).
471 <pre>
472 bool operator()( IndexClassificator eCurrElemClassification
473 sal_Int32 nCurrElemCount,
474 const IndexClassificatorVector::const_iterator& rCurrElemBegin,
475 const IndexClassificatorVector::const_iterator& rCurrElemEnd );
476 </pre>
477 If the functor returns false, iteration over the
478 shapes is immediately stopped.
480 @param io_pFunctor
481 This functor is called for every shape found.
483 @param rBegin
484 Start of range to iterate over
486 @param rEnd
487 End of range to iterate over
489 @return the number of shapes found in the metafile
491 template< typename FunctorT > void iterateActionClassifications(
492 FunctorT& io_rFunctor,
493 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
494 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
496 sal_Int32 nCurrShapeCount( 0 );
497 sal_Int32 nCurrParaCount( 0 );
498 sal_Int32 nCurrLineCount( 0 );
499 sal_Int32 nCurrSentenceCount( 0 );
500 sal_Int32 nCurrWordCount( 0 );
501 sal_Int32 nCurrCharCount( 0 );
503 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
504 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
505 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
506 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
507 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
508 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
510 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
511 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
512 while( aCurr != rEnd )
514 // aNext will hold an iterator to the next element
515 // (or the past-the-end iterator, if aCurr
516 // references the last element). Used to pass a
517 // valid half-open range to the functors.
518 aNext = aCurr;
519 ++aNext;
521 switch( *aCurr )
523 default:
524 ENSURE_OR_THROW( false,
525 "Unexpected type in iterateDocShapes()" );
526 case DrawShapeSubsetting::CLASS_NOOP:
527 // ignore NOOP actions
528 break;
530 case DrawShapeSubsetting::CLASS_SHAPE_START:
531 // regardless of ending action
532 // classifications before: a new shape
533 // always also starts contained elements
534 // anew
535 aLastShapeStart =
536 aLastParaStart =
537 aLastLineStart =
538 aLastSentenceStart =
539 aLastWordStart =
540 aLastCharStart = aCurr;
541 break;
543 case DrawShapeSubsetting::CLASS_SHAPE_END:
544 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
545 nCurrShapeCount,
546 aLastShapeStart,
547 aNext ) )
549 return;
552 ++nCurrShapeCount;
553 // FALLTHROUGH intended: shape end also
554 // ends lines
555 case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
556 if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
557 nCurrParaCount,
558 aLastParaStart,
559 aNext ) )
561 return;
564 ++nCurrParaCount;
565 aLastParaStart = aNext;
566 // FALLTHROUGH intended: para end also
567 // ends line
568 case DrawShapeSubsetting::CLASS_LINE_END:
569 if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
570 nCurrLineCount,
571 aLastLineStart,
572 aNext ) )
574 return;
577 ++nCurrLineCount;
578 aLastLineStart = aNext;
580 if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
582 // DON'T fall through here, as a line
583 // does NOT end neither a sentence,
584 // nor a word. OTOH, all parent
585 // structures (paragraph and shape),
586 // which itself fall through to this
587 // code, DO end word, sentence and
588 // character cell.
590 // TODO(F1): Maybe a line should end a
591 // character cell, OTOH?
592 break;
594 // FALLTHROUGH intended
595 case DrawShapeSubsetting::CLASS_SENTENCE_END:
596 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
597 nCurrSentenceCount,
598 aLastSentenceStart,
599 aNext ) )
601 return;
604 ++nCurrSentenceCount;
605 aLastSentenceStart = aNext;
606 // FALLTHROUGH intended
607 case DrawShapeSubsetting::CLASS_WORD_END:
608 if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
609 nCurrWordCount,
610 aLastWordStart,
611 aNext ) )
613 return;
616 ++nCurrWordCount;
617 aLastWordStart = aNext;
618 // FALLTHROUGH intended
619 case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
620 if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
621 nCurrCharCount,
622 aLastCharStart,
623 aNext ) )
625 return;
628 ++nCurrCharCount;
629 aLastCharStart = aNext;
630 break;
633 aCurr = aNext;
637 DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
639 switch( eNodeType )
641 case DocTreeNode::NODETYPE_INVALID:
642 // FALLTHROUGH intended
643 default:
644 OSL_ENSURE(false,
645 "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
646 return DrawShapeSubsetting::CLASS_NOOP;
648 case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
649 // FALLTHROUGH intended
650 case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
651 return DrawShapeSubsetting::CLASS_SHAPE_END;
653 case DocTreeNode::NODETYPE_FORMATTING_LINE:
654 return DrawShapeSubsetting::CLASS_LINE_END;
656 case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
657 return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
659 case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
660 return DrawShapeSubsetting::CLASS_SENTENCE_END;
662 case DocTreeNode::NODETYPE_LOGICAL_WORD:
663 return DrawShapeSubsetting::CLASS_WORD_END;
665 case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
666 return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
670 /// Counts number of class occurences
671 class CountClassFunctor
673 public:
674 CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
675 meClass( eClass ),
676 mnCurrCount(0)
680 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
681 sal_Int32 /*nCurrElemCount*/,
682 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
683 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
685 if( eCurrElemClassification == meClass )
686 ++mnCurrCount;
688 return true; // never stop, count all occurences
691 sal_Int32 getCount() const
693 return mnCurrCount;
696 private:
697 DrawShapeSubsetting::IndexClassificator meClass;
698 sal_Int32 mnCurrCount;
702 sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
703 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
704 DocTreeNode::NodeType eNodeType ) const
706 const IndexClassificator eRequestedClass(
707 mapDocTreeNode( eNodeType ) );
709 // create a counting functor for the requested class of
710 // actions
711 CountClassFunctor aFunctor( eRequestedClass );
713 // count all occurences in the given range
714 iterateActionClassifications( aFunctor, rBegin, rEnd );
716 return aFunctor.getCount();
719 sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
721 ensureInitializedNodeTree();
723 return implGetNumberOfTreeNodes( maActionClassVector.begin(),
724 maActionClassVector.end(),
725 eNodeType );
728 namespace
730 /** This functor finds the nth occurrence of a given
731 action class.
733 The operator() compares the given index value with the
734 requested index, as given on the functor's
735 constructor. Then, the operator() returns false,
736 denoting that the requested action is found.
738 class FindNthElementFunctor
740 public:
741 FindNthElementFunctor( sal_Int32 nNodeIndex,
742 DrawShapeSubsetting::IndexClassificator eClass ) :
743 mnNodeIndex( nNodeIndex ),
744 meClass( eClass )
748 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
749 sal_Int32 nCurrElemCount,
750 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
751 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
753 if( eCurrElemClassification == meClass &&
754 nCurrElemCount == mnNodeIndex )
756 maLastBegin = rCurrElemBegin;
757 maLastEnd = rCurrElemEnd;
759 return false; // abort iteration, we've
760 // already found what we've been
761 // looking for
764 return true; // keep on truckin'
767 DrawShapeSubsetting::IndexClassificatorVector::const_iterator getBeginElement() const
769 return maLastBegin;
772 DrawShapeSubsetting::IndexClassificatorVector::const_iterator getEndElement() const
774 return maLastEnd;
777 private:
778 sal_Int32 mnNodeIndex;
779 DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastBegin;
780 DrawShapeSubsetting::IndexClassificatorVector::const_iterator maLastEnd;
781 DrawShapeSubsetting::IndexClassificator meClass;
784 DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
785 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
786 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
787 DocTreeNode::NodeType eNodeType )
789 return DocTreeNode( ::std::distance(rBegin,
790 rStart),
791 ::std::distance(rBegin,
792 rEnd),
793 eNodeType );
797 DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
798 const IndexClassificatorVector::const_iterator& rEnd,
799 sal_Int32 nNodeIndex,
800 DocTreeNode::NodeType eNodeType ) const
802 const IndexClassificator eRequestedClass(
803 mapDocTreeNode( eNodeType ) );
805 // create a nth element functor for the requested class of
806 // actions, and nNodeIndex as the target index
807 FindNthElementFunctor aFunctor( nNodeIndex,
808 eRequestedClass );
810 // find given index in the given range
811 iterateActionClassifications( aFunctor, rBegin, rEnd );
813 return makeTreeNode( maActionClassVector.begin(),
814 aFunctor.getBeginElement(),
815 aFunctor.getEndElement(),
816 eNodeType );
819 DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex,
820 DocTreeNode::NodeType eNodeType ) const
822 ensureInitializedNodeTree();
824 return implGetTreeNode( maActionClassVector.begin(),
825 maActionClassVector.end(),
826 nNodeIndex,
827 eNodeType );
830 sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode& rParentNode,
831 DocTreeNode::NodeType eNodeType ) const
833 ensureInitializedNodeTree();
835 // convert from vector indices to vector iterators
836 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
837 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
838 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
840 return implGetNumberOfTreeNodes( aParentBegin,
841 aParentEnd,
842 eNodeType );
845 DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode& rParentNode,
846 sal_Int32 nNodeIndex,
847 DocTreeNode::NodeType eNodeType ) const
849 ensureInitializedNodeTree();
851 // convert from vector indices to vector iterators
852 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
853 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
854 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
856 return implGetTreeNode( aParentBegin,
857 aParentEnd,
858 nNodeIndex,
859 eNodeType );
862 const VectorOfDocTreeNodes& DrawShapeSubsetting::getActiveSubsets() const
864 return maCurrentSubsets;