Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / slideshow / source / engine / shapes / drawshapesubsetting.cxx
blob59a22b1fb75f011644bc260cc86331c4578f6871
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 .
21 // must be first
22 #include <canvas/debug.hxx>
23 #include <tools/diagnose_ex.h>
24 #include <canvas/verbosetrace.hxx>
26 #include <rtl/math.hxx>
27 #include <rtl/logfile.hxx>
29 #include <vcl/metaact.hxx>
30 #include <vcl/gdimtf.hxx>
31 #include <basegfx/numeric/ftools.hxx>
33 #include "drawshapesubsetting.hxx"
34 #include "drawshape.hxx"
36 #include <boost/bind.hpp>
38 #include <algorithm>
39 #include <functional>
40 #include <limits>
42 using namespace ::com::sun::star;
45 namespace slideshow
47 namespace internal
50 //////////////////////////////////////////////////////////////////////
52 // Private methods
54 //////////////////////////////////////////////////////////////////////
56 void DrawShapeSubsetting::ensureInitializedNodeTree() const
58 ENSURE_OR_THROW( mpMtf,
59 "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
61 if( mbNodeTreeInitialized )
62 return; // done, already initialized.
64 // init doctree vector
65 maActionClassVector.clear();
66 maActionClassVector.reserve( mpMtf->GetActionSize() );
68 // search metafile for text output
69 MetaAction* pCurrAct;
71 sal_Int32 nActionIndex(0);
72 sal_Int32 nLastTextActionIndex(0);
73 for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
75 // check for one of our special text doctree comments
76 switch( pCurrAct->GetType() )
78 case META_COMMENT_ACTION:
80 MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
82 // skip comment if not a special XTEXT... comment
83 if( pAct->GetComment().matchIgnoreAsciiCase(
84 rtl::OString(RTL_CONSTASCII_STRINGPARAM("XTEXT")),
85 0) )
87 // fill classification vector with NOOPs,
88 // then insert corresponding classes at
89 // the given index
90 maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
92 if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOC")) )
94 // special, because can happen
95 // in-between of portions - set
96 // character-end classificator at
97 // given index (relative to last text
98 // action).
99 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
101 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
102 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
104 maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
106 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOW")) )
108 // special, because can happen
109 // in-between of portions - set
110 // word-end classificator at given
111 // index (relative to last text
112 // action).
113 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
115 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
116 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
118 maActionClassVector[ nIndex ] = CLASS_WORD_END;
120 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM( "XTEXT_EOS" )) )
122 // special, because can happen
123 // in-between of portions - set
124 // sentence-end classificator at given
125 // index (relative to last text
126 // action).
127 const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
129 ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
130 "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
132 maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
134 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOL")) )
136 maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
138 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_EOP")) )
140 maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
142 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_END")) )
144 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
146 else if( pAct->GetComment().equalsIgnoreAsciiCaseL(RTL_CONSTASCII_STRINGPARAM("XTEXT_PAINTSHAPE_BEGIN")) )
148 maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
151 VERBOSE_TRACE( "Shape text structure: %s at action #%d",
152 pAct->GetComment().getStr(), nActionIndex );
153 ++nActionIndex;
154 break;
156 case META_TEXT_ACTION:
157 case META_TEXTARRAY_ACTION:
158 case META_STRETCHTEXT_ACTION:
159 nLastTextActionIndex = nActionIndex;
160 #if OSL_DEBUG_LEVEL > 1
162 MetaTextAction* pText = static_cast<MetaTextAction*>(pCurrAct);
163 VERBOSE_TRACE( "Shape text \"%s\" at action #%d",
164 rtl::OUStringToOString(pText->GetText(),
165 RTL_TEXTENCODING_ISO_8859_1).getStr(),
166 nActionIndex );
168 #endif
169 // fallthrough intended
170 default:
171 // comment action and all actions not
172 // explicitly 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 DocTreeNode& rShapeSubset,
251 const GDIMetaFileSharedPtr& rMtf ) :
252 maActionClassVector(),
253 mpMtf( rMtf ),
254 maSubset( rShapeSubset ),
255 maSubsetShapes(),
256 mnMinSubsetActionIndex( SAL_MAX_INT32 ),
257 mnMaxSubsetActionIndex(0),
258 maCurrentSubsets(),
259 mbNodeTreeInitialized( false )
261 ENSURE_OR_THROW( mpMtf,
262 "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
264 initCurrentSubsets();
267 void DrawShapeSubsetting::reset()
269 maActionClassVector.clear();
270 mpMtf.reset();
271 maSubset.reset();
272 maSubsetShapes.clear();
273 mnMinSubsetActionIndex = SAL_MAX_INT32;
274 mnMaxSubsetActionIndex = 0;
275 maCurrentSubsets.clear();
276 mbNodeTreeInitialized = false;
279 void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
281 reset();
282 mpMtf = rMtf;
284 initCurrentSubsets();
287 void DrawShapeSubsetting::initCurrentSubsets()
289 // only add subset to vector, if it's not empty - that's
290 // because the vector's content is later literally used
291 // for e.g. painting.
292 if( !maSubset.isEmpty() )
293 maCurrentSubsets.push_back( maSubset );
296 DocTreeNode DrawShapeSubsetting::getSubsetNode() const
298 return maSubset;
301 AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
303 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
305 // subset shape already created for this DocTreeNode?
306 SubsetEntry aEntry;
308 aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
309 aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
311 ShapeSet::const_iterator aIter;
312 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
314 // already created, return found entry
315 return aIter->mpShape;
318 return AttributableShapeSharedPtr();
321 void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
323 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
325 // subset shape already created for this DocTreeNode?
326 SubsetEntry aEntry;
327 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
329 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
330 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
332 ShapeSet::const_iterator aIter;
333 if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
335 // already created, increment use count and return
337 // safe cast, since set order does not depend on
338 // mnSubsetQueriedCount
339 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
341 else
343 // not yet created, init entry
344 aEntry.mnSubsetQueriedCount = 1;
345 aEntry.mpShape = rShape;
347 maSubsetShapes.insert( aEntry );
349 // update cached subset borders
350 updateSubsetBounds( aEntry );
351 updateSubsets();
355 bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
357 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
359 // lookup subset shape
360 SubsetEntry aEntry;
361 const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
363 aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
364 aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
366 ShapeSet::iterator aIter;
367 if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
368 return false; // not found, subset was never queried
370 // last client of the subset revoking?
371 if( aIter->mnSubsetQueriedCount > 1 )
373 // no, still clients out there. Just decrement use count
374 // safe cast, since order does not depend on mnSubsetQueriedCount
375 const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
377 VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, revoked subset has refcount %d",
378 this,
379 maSubsetShapes.size(),
380 aIter->mnSubsetQueriedCount );
382 return false; // not the last client
385 VERBOSE_TRACE( "Subset summary: shape 0x%X, %d open subsets, cleared subset has range [%d,%d]",
386 this,
387 maSubsetShapes.size(),
388 aEntry.mnStartActionIndex,
389 aEntry.mnEndActionIndex );
391 // yes, remove from set
392 maSubsetShapes.erase( aIter );
395 // update currently active subset for _our_ shape (the
396 // part of this shape that is visible, i.e. not displayed
397 // in subset shapes)
398 // ======================================================
400 // init bounds
401 mnMinSubsetActionIndex = SAL_MAX_INT32;
402 mnMaxSubsetActionIndex = 0;
404 // TODO(P2): This is quite expensive, when
405 // after every subset effect end, we have to scan
406 // the whole shape set
408 // determine new subset range
409 ::std::for_each( maSubsetShapes.begin(),
410 maSubsetShapes.end(),
411 ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
412 this,
413 _1 ) );
415 updateSubsets();
417 return true;
420 namespace
422 /** Iterate over all action classification entries in the
423 given range, pass each element range found to the
424 given functor.
426 This method extracts, for each of the different action
427 classifications, the count and the ranges for each of
428 them, and calls the provided functor with that
429 information.
431 @tpl FunctorT
432 This is the functor's operator() calling signature,
433 with eCurrElemClassification denoting the current
434 classification type the functor is called for,
435 nCurrElemCount the running total of elements visited
436 for the given class (starting from 0), and
437 rCurrElemBegin/rCurrElemEnd the range of the current
438 element (i.e. the iterators from the start to the end
439 of this element).
440 <pre>
441 bool operator()( IndexClassificator eCurrElemClassification
442 sal_Int32 nCurrElemCount,
443 const IndexClassificatorVector::const_iterator& rCurrElemBegin,
444 const IndexClassificatorVector::const_iterator& rCurrElemEnd );
445 </pre>
446 If the functor returns false, iteration over the
447 shapes is immediately stopped.
449 @param io_pFunctor
450 This functor is called for every shape found.
452 @param rBegin
453 Start of range to iterate over
455 @param rEnd
456 End of range to iterate over
458 @return the number of shapes found in the metafile
460 template< typename FunctorT > void iterateActionClassifications(
461 FunctorT& io_rFunctor,
462 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
463 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
465 sal_Int32 nCurrShapeCount( 0 );
466 sal_Int32 nCurrParaCount( 0 );
467 sal_Int32 nCurrLineCount( 0 );
468 sal_Int32 nCurrSentenceCount( 0 );
469 sal_Int32 nCurrWordCount( 0 );
470 sal_Int32 nCurrCharCount( 0 );
472 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
473 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
474 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
475 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
476 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
477 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
479 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
480 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
481 while( aCurr != rEnd )
483 // aNext will hold an iterator to the next element
484 // (or the past-the-end iterator, if aCurr
485 // references the last element). Used to pass a
486 // valid half-open range to the functors.
487 aNext = aCurr;
488 ++aNext;
490 switch( *aCurr )
492 default:
493 ENSURE_OR_THROW( false,
494 "Unexpected type in iterateDocShapes()" );
495 case DrawShapeSubsetting::CLASS_NOOP:
496 // ignore NOOP actions
497 break;
499 case DrawShapeSubsetting::CLASS_SHAPE_START:
500 // regardless of ending action
501 // classifications before: a new shape
502 // always also starts contained elements
503 // anew
504 aLastShapeStart =
505 aLastParaStart =
506 aLastLineStart =
507 aLastSentenceStart =
508 aLastWordStart =
509 aLastCharStart = aCurr;
510 break;
512 case DrawShapeSubsetting::CLASS_SHAPE_END:
513 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
514 nCurrShapeCount,
515 aLastShapeStart,
516 aNext ) )
518 return;
521 ++nCurrShapeCount;
522 // FALLTHROUGH intended: shape end also
523 // ends lines
524 case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
525 if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
526 nCurrParaCount,
527 aLastParaStart,
528 aNext ) )
530 return;
533 ++nCurrParaCount;
534 aLastParaStart = aNext;
535 // FALLTHROUGH intended: para end also
536 // ends line
537 case DrawShapeSubsetting::CLASS_LINE_END:
538 if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
539 nCurrLineCount,
540 aLastLineStart,
541 aNext ) )
543 return;
546 ++nCurrLineCount;
547 aLastLineStart = aNext;
549 if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
551 // DON'T fall through here, as a line
552 // does NOT end neither a sentence,
553 // nor a word. OTOH, all parent
554 // structures (paragraph and shape),
555 // which itself fall through to this
556 // code, DO end word, sentence and
557 // character cell.
559 // TODO(F1): Maybe a line should end a
560 // character cell, OTOH?
561 break;
563 // FALLTHROUGH intended
564 case DrawShapeSubsetting::CLASS_SENTENCE_END:
565 if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
566 nCurrSentenceCount,
567 aLastSentenceStart,
568 aNext ) )
570 return;
573 ++nCurrSentenceCount;
574 aLastSentenceStart = aNext;
575 // FALLTHROUGH intended
576 case DrawShapeSubsetting::CLASS_WORD_END:
577 if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
578 nCurrWordCount,
579 aLastWordStart,
580 aNext ) )
582 return;
585 ++nCurrWordCount;
586 aLastWordStart = aNext;
587 // FALLTHROUGH intended
588 case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
589 if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
590 nCurrCharCount,
591 aLastCharStart,
592 aNext ) )
594 return;
597 ++nCurrCharCount;
598 aLastCharStart = aNext;
599 break;
602 aCurr = aNext;
606 DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
608 switch( eNodeType )
610 case DocTreeNode::NODETYPE_INVALID:
611 // FALLTHROUGH intended
612 default:
613 OSL_FAIL("DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
614 return DrawShapeSubsetting::CLASS_NOOP;
616 case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
617 // FALLTHROUGH intended
618 case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
619 return DrawShapeSubsetting::CLASS_SHAPE_END;
621 case DocTreeNode::NODETYPE_FORMATTING_LINE:
622 return DrawShapeSubsetting::CLASS_LINE_END;
624 case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
625 return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
627 case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
628 return DrawShapeSubsetting::CLASS_SENTENCE_END;
630 case DocTreeNode::NODETYPE_LOGICAL_WORD:
631 return DrawShapeSubsetting::CLASS_WORD_END;
633 case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
634 return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
638 /// Counts number of class occurrences
639 class CountClassFunctor
641 public:
642 CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
643 meClass( eClass ),
644 mnCurrCount(0)
648 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
649 sal_Int32 /*nCurrElemCount*/,
650 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
651 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
653 if( eCurrElemClassification == meClass )
654 ++mnCurrCount;
656 return true; // never stop, count all occurrences
659 sal_Int32 getCount() const
661 return mnCurrCount;
664 private:
665 DrawShapeSubsetting::IndexClassificator meClass;
666 sal_Int32 mnCurrCount;
670 sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
671 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
672 DocTreeNode::NodeType eNodeType ) const
674 const IndexClassificator eRequestedClass(
675 mapDocTreeNode( eNodeType ) );
677 // create a counting functor for the requested class of
678 // actions
679 CountClassFunctor aFunctor( eRequestedClass );
681 // count all occurrences in the given range
682 iterateActionClassifications( aFunctor, rBegin, rEnd );
684 return aFunctor.getCount();
687 sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
689 ensureInitializedNodeTree();
691 return implGetNumberOfTreeNodes( maActionClassVector.begin(),
692 maActionClassVector.end(),
693 eNodeType );
696 namespace
698 /** This functor finds the nth occurrence of a given
699 action class.
701 The operator() compares the given index value with the
702 requested index, as given on the functor's
703 constructor. Then, the operator() returns false,
704 denoting that the requested action is found.
706 class FindNthElementFunctor
708 public:
709 FindNthElementFunctor( sal_Int32 nNodeIndex,
710 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastBegin,
711 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastEnd,
712 DrawShapeSubsetting::IndexClassificator eClass ) :
713 mnNodeIndex( nNodeIndex ),
714 mrLastBegin( rLastBegin ),
715 mrLastEnd( rLastEnd ),
716 meClass( eClass )
720 bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
721 sal_Int32 nCurrElemCount,
722 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
723 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
725 if( eCurrElemClassification == meClass &&
726 nCurrElemCount == mnNodeIndex )
728 mrLastBegin = rCurrElemBegin;
729 mrLastEnd = rCurrElemEnd;
731 return false; // abort iteration, we've
732 // already found what we've been
733 // looking for
736 return true; // keep on truckin'
739 private:
740 sal_Int32 mnNodeIndex;
741 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastBegin;
742 DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastEnd;
743 DrawShapeSubsetting::IndexClassificator meClass;
746 DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
747 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
748 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
749 DocTreeNode::NodeType eNodeType )
751 return DocTreeNode( ::std::distance(rBegin,
752 rStart),
753 ::std::distance(rBegin,
754 rEnd),
755 eNodeType );
759 DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
760 const IndexClassificatorVector::const_iterator& rEnd,
761 sal_Int32 nNodeIndex,
762 DocTreeNode::NodeType eNodeType ) const
764 const IndexClassificator eRequestedClass(
765 mapDocTreeNode( eNodeType ) );
767 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastBegin(rEnd);
768 DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastEnd(rEnd);
770 // create a nth element functor for the requested class of
771 // actions, and nNodeIndex as the target index
772 FindNthElementFunctor aFunctor( nNodeIndex,
773 aLastBegin,
774 aLastEnd,
775 eRequestedClass );
777 // find given index in the given range
778 iterateActionClassifications( aFunctor, rBegin, rEnd );
780 return makeTreeNode( maActionClassVector.begin(),
781 aLastBegin, aLastEnd,
782 eNodeType );
785 DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex,
786 DocTreeNode::NodeType eNodeType ) const
788 ensureInitializedNodeTree();
790 return implGetTreeNode( maActionClassVector.begin(),
791 maActionClassVector.end(),
792 nNodeIndex,
793 eNodeType );
796 sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode& rParentNode,
797 DocTreeNode::NodeType eNodeType ) const
799 ensureInitializedNodeTree();
801 // convert from vector indices to vector iterators
802 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
803 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
804 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
806 return implGetNumberOfTreeNodes( aParentBegin,
807 aParentEnd,
808 eNodeType );
811 DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode& rParentNode,
812 sal_Int32 nNodeIndex,
813 DocTreeNode::NodeType eNodeType ) const
815 ensureInitializedNodeTree();
817 // convert from vector indices to vector iterators
818 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
819 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
820 const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
822 return implGetTreeNode( aParentBegin,
823 aParentEnd,
824 nNodeIndex,
825 eNodeType );
828 const VectorOfDocTreeNodes& DrawShapeSubsetting::getActiveSubsets() const
830 return maCurrentSubsets;
836 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */