Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : // must be first
22 : #include <canvas/debug.hxx>
23 : #include <tools/diagnose_ex.h>
24 : #include <canvas/verbosetrace.hxx>
25 :
26 : #include <rtl/math.hxx>
27 :
28 : #include <vcl/metaact.hxx>
29 : #include <vcl/gdimtf.hxx>
30 : #include <basegfx/numeric/ftools.hxx>
31 :
32 : #include "drawshapesubsetting.hxx"
33 : #include "drawshape.hxx"
34 :
35 : #include <boost/bind.hpp>
36 :
37 : #include <algorithm>
38 : #include <functional>
39 : #include <limits>
40 :
41 : using namespace ::com::sun::star;
42 :
43 :
44 : namespace slideshow
45 : {
46 : namespace internal
47 : {
48 :
49 :
50 :
51 : // Private methods
52 :
53 :
54 :
55 0 : void DrawShapeSubsetting::ensureInitializedNodeTree() const
56 : {
57 0 : ENSURE_OR_THROW( mpMtf,
58 : "DrawShapeSubsetting::ensureInitializedNodeTree(): Invalid mtf" );
59 :
60 0 : if( mbNodeTreeInitialized )
61 0 : return; // done, already initialized.
62 :
63 : // init doctree vector
64 0 : maActionClassVector.clear();
65 0 : maActionClassVector.reserve( mpMtf->GetActionSize() );
66 :
67 : // search metafile for text output
68 : MetaAction* pCurrAct;
69 :
70 0 : sal_Int32 nActionIndex(0);
71 0 : sal_Int32 nLastTextActionIndex(0);
72 0 : for( pCurrAct = mpMtf->FirstAction(); pCurrAct; pCurrAct = mpMtf->NextAction() )
73 : {
74 : // check for one of our special text doctree comments
75 0 : switch( pCurrAct->GetType() )
76 : {
77 : case MetaActionType::COMMENT:
78 : {
79 0 : MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
80 :
81 : // skip comment if not a special XTEXT... comment
82 0 : if( pAct->GetComment().matchIgnoreAsciiCase( OString("XTEXT"), 0 ) )
83 : {
84 : // fill classification vector with NOOPs,
85 : // then insert corresponding classes at
86 : // the given index
87 0 : maActionClassVector.resize( nActionIndex+1, CLASS_NOOP );
88 :
89 0 : if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOC") )
90 : {
91 : // special, because can happen
92 : // in-between of portions - set
93 : // character-end classificator at
94 : // given index (relative to last text
95 : // action).
96 0 : const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
97 :
98 0 : ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
99 : "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
100 :
101 0 : maActionClassVector[ nIndex ] = CLASS_CHARACTER_CELL_END;
102 : }
103 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOW") )
104 : {
105 : // special, because can happen
106 : // in-between of portions - set
107 : // word-end classificator at given
108 : // index (relative to last text
109 : // action).
110 0 : const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
111 :
112 0 : ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
113 : "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
114 :
115 0 : maActionClassVector[ nIndex ] = CLASS_WORD_END;
116 : }
117 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOS") )
118 : {
119 : // special, because can happen
120 : // in-between of portions - set
121 : // sentence-end classificator at given
122 : // index (relative to last text
123 : // action).
124 0 : const sal_Int32 nIndex( nLastTextActionIndex + pAct->GetValue() );
125 :
126 0 : ENSURE_OR_THROW( static_cast< ::std::size_t >(nIndex) < maActionClassVector.size(),
127 : "DrawShapeSubsetting::ensureInitializedNodeTree(): sentence index out of range" );
128 :
129 0 : maActionClassVector[ nIndex ] = CLASS_SENTENCE_END;
130 : }
131 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOL") )
132 : {
133 0 : maActionClassVector[ nActionIndex ] = CLASS_LINE_END;
134 : }
135 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_EOP") )
136 : {
137 0 : maActionClassVector[ nActionIndex ] = CLASS_PARAGRAPH_END;
138 : }
139 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_END") )
140 : {
141 0 : maActionClassVector[ nActionIndex ] = CLASS_SHAPE_END;
142 : }
143 0 : else if( pAct->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_BEGIN") )
144 : {
145 0 : maActionClassVector[ nActionIndex ] = CLASS_SHAPE_START;
146 : }
147 : }
148 : SAL_INFO(
149 : "slideshow",
150 : "Shape text structure: " << pAct->GetComment()
151 : << " at action #" << nActionIndex);
152 0 : ++nActionIndex;
153 0 : break;
154 : }
155 : case MetaActionType::TEXT:
156 : case MetaActionType::TEXTARRAY:
157 : case MetaActionType::STRETCHTEXT:
158 0 : nLastTextActionIndex = nActionIndex;
159 : #if OSL_DEBUG_LEVEL > 1
160 : {
161 : MetaTextAction* pText = static_cast<MetaTextAction*>(pCurrAct);
162 : VERBOSE_TRACE( "Shape text \"%s\" at action #%d",
163 : OUStringToOString(pText->GetText(),
164 : RTL_TEXTENCODING_ISO_8859_1).getStr(),
165 : nActionIndex );
166 : }
167 : #endif
168 : // fallthrough intended
169 : default:
170 : // comment action and all actions not
171 : // explicitly handled here:
172 0 : nActionIndex += getNextActionOffset(pCurrAct);
173 0 : break;
174 : }
175 : }
176 :
177 0 : mbNodeTreeInitialized = true;
178 : }
179 :
180 0 : void DrawShapeSubsetting::updateSubsetBounds( const SubsetEntry& rSubsetEntry )
181 : {
182 : // TODO(F1): This removes too much from non-contiguous subsets
183 : mnMinSubsetActionIndex = ::std::min(
184 : mnMinSubsetActionIndex,
185 0 : rSubsetEntry.mnStartActionIndex );
186 : mnMaxSubsetActionIndex = ::std::max(
187 : mnMaxSubsetActionIndex,
188 0 : rSubsetEntry.mnEndActionIndex );
189 0 : }
190 :
191 0 : void DrawShapeSubsetting::updateSubsets()
192 : {
193 0 : maCurrentSubsets.clear();
194 :
195 0 : if( !maSubsetShapes.empty() )
196 : {
197 0 : if( maSubset.isEmpty() )
198 : {
199 : // non-subsetted node, with some child subsets
200 : // that subtract from it
201 : maCurrentSubsets.push_back( DocTreeNode( 0,
202 : mnMinSubsetActionIndex,
203 0 : DocTreeNode::NODETYPE_INVALID ) );
204 : maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
205 0 : maActionClassVector.size(),
206 0 : DocTreeNode::NODETYPE_INVALID ) );
207 : }
208 : else
209 : {
210 : // subsetted node, from which some further child
211 : // subsets subtract content
212 : maCurrentSubsets.push_back( DocTreeNode( maSubset.getStartIndex(),
213 : mnMinSubsetActionIndex,
214 0 : DocTreeNode::NODETYPE_INVALID ) );
215 : maCurrentSubsets.push_back( DocTreeNode( mnMaxSubsetActionIndex,
216 : maSubset.getEndIndex(),
217 0 : DocTreeNode::NODETYPE_INVALID ) );
218 : }
219 : }
220 : else
221 : {
222 : // no further child subsets, simply add our subset (if any)
223 0 : if( !maSubset.isEmpty() )
224 : {
225 : // subsetted node, without any subset children
226 0 : maCurrentSubsets.push_back( maSubset );
227 : }
228 : }
229 0 : }
230 :
231 :
232 :
233 : // Public methods
234 :
235 :
236 :
237 0 : DrawShapeSubsetting::DrawShapeSubsetting() :
238 : maActionClassVector(),
239 : mpMtf(),
240 : maSubset(),
241 : maSubsetShapes(),
242 : mnMinSubsetActionIndex( SAL_MAX_INT32 ),
243 : mnMaxSubsetActionIndex(0),
244 : maCurrentSubsets(),
245 0 : mbNodeTreeInitialized( false )
246 : {
247 0 : }
248 :
249 0 : DrawShapeSubsetting::DrawShapeSubsetting( const DocTreeNode& rShapeSubset,
250 : const GDIMetaFileSharedPtr& rMtf ) :
251 : maActionClassVector(),
252 : mpMtf( rMtf ),
253 : maSubset( rShapeSubset ),
254 : maSubsetShapes(),
255 : mnMinSubsetActionIndex( SAL_MAX_INT32 ),
256 : mnMaxSubsetActionIndex(0),
257 : maCurrentSubsets(),
258 0 : mbNodeTreeInitialized( false )
259 : {
260 0 : ENSURE_OR_THROW( mpMtf,
261 : "DrawShapeSubsetting::DrawShapeSubsetting(): Invalid metafile" );
262 :
263 0 : initCurrentSubsets();
264 0 : }
265 :
266 0 : void DrawShapeSubsetting::reset()
267 : {
268 0 : maActionClassVector.clear();
269 0 : mpMtf.reset();
270 0 : maSubset.reset();
271 0 : maSubsetShapes.clear();
272 0 : mnMinSubsetActionIndex = SAL_MAX_INT32;
273 0 : mnMaxSubsetActionIndex = 0;
274 0 : maCurrentSubsets.clear();
275 0 : mbNodeTreeInitialized = false;
276 0 : }
277 :
278 0 : void DrawShapeSubsetting::reset( const ::boost::shared_ptr< GDIMetaFile >& rMtf )
279 : {
280 0 : reset();
281 0 : mpMtf = rMtf;
282 :
283 0 : initCurrentSubsets();
284 0 : }
285 :
286 0 : void DrawShapeSubsetting::initCurrentSubsets()
287 : {
288 : // only add subset to vector, if it's not empty - that's
289 : // because the vector's content is later literally used
290 : // for e.g. painting.
291 0 : if( !maSubset.isEmpty() )
292 0 : maCurrentSubsets.push_back( maSubset );
293 0 : }
294 :
295 0 : DocTreeNode DrawShapeSubsetting::getSubsetNode() const
296 : {
297 0 : return maSubset;
298 : }
299 :
300 0 : AttributableShapeSharedPtr DrawShapeSubsetting::getSubsetShape( const DocTreeNode& rTreeNode ) const
301 : {
302 : SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::getSubsetShape()" );
303 :
304 : // subset shape already created for this DocTreeNode?
305 0 : SubsetEntry aEntry;
306 :
307 0 : aEntry.mnStartActionIndex = rTreeNode.getStartIndex();
308 0 : aEntry.mnEndActionIndex = rTreeNode.getEndIndex();
309 :
310 0 : ShapeSet::const_iterator aIter;
311 0 : if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
312 : {
313 : // already created, return found entry
314 0 : return aIter->mpShape;
315 : }
316 :
317 0 : return AttributableShapeSharedPtr();
318 : }
319 :
320 0 : void DrawShapeSubsetting::addSubsetShape( const AttributableShapeSharedPtr& rShape )
321 : {
322 : SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::addSubsetShape()" );
323 :
324 : // subset shape already created for this DocTreeNode?
325 0 : SubsetEntry aEntry;
326 0 : const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
327 :
328 0 : aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
329 0 : aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
330 :
331 0 : ShapeSet::const_iterator aIter;
332 0 : if( (aIter=maSubsetShapes.find( aEntry )) != maSubsetShapes.end() )
333 : {
334 : // already created, increment use count and return
335 :
336 : // safe cast, since set order does not depend on
337 : // mnSubsetQueriedCount
338 0 : const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount++;
339 : }
340 : else
341 : {
342 : // not yet created, init entry
343 0 : aEntry.mnSubsetQueriedCount = 1;
344 0 : aEntry.mpShape = rShape;
345 :
346 0 : maSubsetShapes.insert( aEntry );
347 :
348 : // update cached subset borders
349 0 : updateSubsetBounds( aEntry );
350 0 : updateSubsets();
351 0 : }
352 0 : }
353 :
354 0 : bool DrawShapeSubsetting::revokeSubsetShape( const AttributableShapeSharedPtr& rShape )
355 : {
356 : SAL_INFO( "slideshow", "::presentation::internal::DrawShapeSubsetting::revokeSubsetShape()" );
357 :
358 : // lookup subset shape
359 0 : SubsetEntry aEntry;
360 0 : const DocTreeNode& rEffectiveSubset( rShape->getSubsetNode() );
361 :
362 0 : aEntry.mnStartActionIndex = rEffectiveSubset.getStartIndex();
363 0 : aEntry.mnEndActionIndex = rEffectiveSubset.getEndIndex();
364 :
365 0 : ShapeSet::iterator aIter;
366 0 : if( (aIter=maSubsetShapes.find( aEntry )) == maSubsetShapes.end() )
367 0 : return false; // not found, subset was never queried
368 :
369 : // last client of the subset revoking?
370 0 : if( aIter->mnSubsetQueriedCount > 1 )
371 : {
372 : // no, still clients out there. Just decrement use count
373 : // safe cast, since order does not depend on mnSubsetQueriedCount
374 0 : const_cast<SubsetEntry&>(*aIter).mnSubsetQueriedCount--;
375 :
376 : SAL_INFO(
377 : "slideshow",
378 : "Subset summary: shape " << this << ", "
379 : << maSubsetShapes.size()
380 : << " open subsets, revoked subset has refcount "
381 : << aIter->mnSubsetQueriedCount);
382 :
383 0 : return false; // not the last client
384 : }
385 :
386 : SAL_INFO(
387 : "slideshow",
388 : "Subset summary: shape " << this << ", "
389 : << maSubsetShapes.size()
390 : << " open subsets, cleared subset has range ["
391 : << aEntry.mnStartActionIndex << ","
392 : << aEntry.mnEndActionIndex << "]");
393 :
394 : // yes, remove from set
395 0 : maSubsetShapes.erase( aIter );
396 :
397 :
398 : // update currently active subset for _our_ shape (the
399 : // part of this shape that is visible, i.e. not displayed
400 : // in subset shapes)
401 :
402 :
403 : // init bounds
404 0 : mnMinSubsetActionIndex = SAL_MAX_INT32;
405 0 : mnMaxSubsetActionIndex = 0;
406 :
407 : // TODO(P2): This is quite expensive, when
408 : // after every subset effect end, we have to scan
409 : // the whole shape set
410 :
411 : // determine new subset range
412 : ::std::for_each( maSubsetShapes.begin(),
413 : maSubsetShapes.end(),
414 : ::boost::bind(&DrawShapeSubsetting::updateSubsetBounds,
415 : this,
416 0 : _1 ) );
417 :
418 0 : updateSubsets();
419 :
420 0 : return true;
421 : }
422 :
423 : namespace
424 : {
425 : /** Iterate over all action classification entries in the
426 : given range, pass each element range found to the
427 : given functor.
428 :
429 : This method extracts, for each of the different action
430 : classifications, the count and the ranges for each of
431 : them, and calls the provided functor with that
432 : information.
433 :
434 : @tpl FunctorT
435 : This is the functor's operator() calling signature,
436 : with eCurrElemClassification denoting the current
437 : classification type the functor is called for,
438 : nCurrElemCount the running total of elements visited
439 : for the given class (starting from 0), and
440 : rCurrElemBegin/rCurrElemEnd the range of the current
441 : element (i.e. the iterators from the start to the end
442 : of this element).
443 : <pre>
444 : bool operator()( IndexClassificator eCurrElemClassification
445 : sal_Int32 nCurrElemCount,
446 : const IndexClassificatorVector::const_iterator& rCurrElemBegin,
447 : const IndexClassificatorVector::const_iterator& rCurrElemEnd );
448 : </pre>
449 : If the functor returns false, iteration over the
450 : shapes is immediately stopped.
451 :
452 : @param io_pFunctor
453 : This functor is called for every shape found.
454 :
455 : @param rBegin
456 : Start of range to iterate over
457 :
458 : @param rEnd
459 : End of range to iterate over
460 :
461 : @return the number of shapes found in the metafile
462 : */
463 0 : template< typename FunctorT > void iterateActionClassifications(
464 : FunctorT& io_rFunctor,
465 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
466 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd )
467 : {
468 0 : sal_Int32 nCurrShapeCount( 0 );
469 0 : sal_Int32 nCurrParaCount( 0 );
470 0 : sal_Int32 nCurrLineCount( 0 );
471 0 : sal_Int32 nCurrSentenceCount( 0 );
472 0 : sal_Int32 nCurrWordCount( 0 );
473 0 : sal_Int32 nCurrCharCount( 0 );
474 :
475 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastShapeStart(rBegin);
476 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastParaStart(rBegin);
477 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastLineStart(rBegin);
478 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastSentenceStart(rBegin);
479 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastWordStart(rBegin);
480 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastCharStart(rBegin);
481 :
482 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aNext;
483 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aCurr( rBegin );
484 0 : while( aCurr != rEnd )
485 : {
486 : // aNext will hold an iterator to the next element
487 : // (or the past-the-end iterator, if aCurr
488 : // references the last element). Used to pass a
489 : // valid half-open range to the functors.
490 0 : aNext = aCurr;
491 0 : ++aNext;
492 :
493 0 : switch( *aCurr )
494 : {
495 : default:
496 0 : ENSURE_OR_THROW( false,
497 : "Unexpected type in iterateDocShapes()" );
498 : case DrawShapeSubsetting::CLASS_NOOP:
499 : // ignore NOOP actions
500 0 : break;
501 :
502 : case DrawShapeSubsetting::CLASS_SHAPE_START:
503 : // regardless of ending action
504 : // classifications before: a new shape
505 : // always also starts contained elements
506 : // anew
507 0 : aLastShapeStart =
508 : aLastParaStart =
509 : aLastLineStart =
510 : aLastSentenceStart =
511 : aLastWordStart =
512 : aLastCharStart = aCurr;
513 0 : break;
514 :
515 : case DrawShapeSubsetting::CLASS_SHAPE_END:
516 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_SHAPE_END,
517 : nCurrShapeCount,
518 : aLastShapeStart,
519 0 : aNext ) )
520 : {
521 0 : return;
522 : }
523 :
524 0 : ++nCurrShapeCount;
525 : // FALLTHROUGH intended: shape end also
526 : // ends lines
527 : case DrawShapeSubsetting::CLASS_PARAGRAPH_END:
528 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_PARAGRAPH_END,
529 : nCurrParaCount,
530 : aLastParaStart,
531 0 : aNext ) )
532 : {
533 0 : return;
534 : }
535 :
536 0 : ++nCurrParaCount;
537 0 : aLastParaStart = aNext;
538 : // FALLTHROUGH intended: para end also
539 : // ends line
540 : case DrawShapeSubsetting::CLASS_LINE_END:
541 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_LINE_END,
542 : nCurrLineCount,
543 : aLastLineStart,
544 0 : aNext ) )
545 : {
546 0 : return;
547 : }
548 :
549 0 : ++nCurrLineCount;
550 0 : aLastLineStart = aNext;
551 :
552 0 : if( *aCurr == DrawShapeSubsetting::CLASS_LINE_END )
553 : {
554 : // DON'T fall through here, as a line
555 : // does NOT end neither a sentence,
556 : // nor a word. OTOH, all parent
557 : // structures (paragraph and shape),
558 : // which itself fall through to this
559 : // code, DO end word, sentence and
560 : // character cell.
561 :
562 : // TODO(F1): Maybe a line should end a
563 : // character cell, OTOH?
564 0 : break;
565 : }
566 : // FALLTHROUGH intended
567 : case DrawShapeSubsetting::CLASS_SENTENCE_END:
568 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_SENTENCE_END,
569 : nCurrSentenceCount,
570 : aLastSentenceStart,
571 0 : aNext ) )
572 : {
573 0 : return;
574 : }
575 :
576 0 : ++nCurrSentenceCount;
577 0 : aLastSentenceStart = aNext;
578 : // FALLTHROUGH intended
579 : case DrawShapeSubsetting::CLASS_WORD_END:
580 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_WORD_END,
581 : nCurrWordCount,
582 : aLastWordStart,
583 0 : aNext ) )
584 : {
585 0 : return;
586 : }
587 :
588 0 : ++nCurrWordCount;
589 0 : aLastWordStart = aNext;
590 : // FALLTHROUGH intended
591 : case DrawShapeSubsetting::CLASS_CHARACTER_CELL_END:
592 0 : if( !io_rFunctor( DrawShapeSubsetting::CLASS_CHARACTER_CELL_END,
593 : nCurrCharCount,
594 : aLastCharStart,
595 0 : aNext ) )
596 : {
597 0 : return;
598 : }
599 :
600 0 : ++nCurrCharCount;
601 0 : aLastCharStart = aNext;
602 0 : break;
603 : }
604 :
605 0 : aCurr = aNext;
606 : }
607 : }
608 :
609 0 : DrawShapeSubsetting::IndexClassificator mapDocTreeNode( DocTreeNode::NodeType eNodeType )
610 : {
611 0 : switch( eNodeType )
612 : {
613 : case DocTreeNode::NODETYPE_INVALID:
614 : // FALLTHROUGH intended
615 : default:
616 : SAL_WARN( "slideshow", "DrawShapeSubsetting::mapDocTreeNode(): unexpected node type");
617 0 : return DrawShapeSubsetting::CLASS_NOOP;
618 :
619 : case DocTreeNode::NODETYPE_LOGICAL_SHAPE:
620 : // FALLTHROUGH intended
621 : case DocTreeNode::NODETYPE_FORMATTING_SHAPE:
622 0 : return DrawShapeSubsetting::CLASS_SHAPE_END;
623 :
624 : case DocTreeNode::NODETYPE_FORMATTING_LINE:
625 0 : return DrawShapeSubsetting::CLASS_LINE_END;
626 :
627 : case DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH:
628 0 : return DrawShapeSubsetting::CLASS_PARAGRAPH_END;
629 :
630 : case DocTreeNode::NODETYPE_LOGICAL_SENTENCE:
631 0 : return DrawShapeSubsetting::CLASS_SENTENCE_END;
632 :
633 : case DocTreeNode::NODETYPE_LOGICAL_WORD:
634 0 : return DrawShapeSubsetting::CLASS_WORD_END;
635 :
636 : case DocTreeNode::NODETYPE_LOGICAL_CHARACTER_CELL:
637 0 : return DrawShapeSubsetting::CLASS_CHARACTER_CELL_END;
638 : };
639 : }
640 :
641 : /// Counts number of class occurrences
642 : class CountClassFunctor
643 : {
644 : public:
645 0 : CountClassFunctor( DrawShapeSubsetting::IndexClassificator eClass ) :
646 : meClass( eClass ),
647 0 : mnCurrCount(0)
648 : {
649 0 : }
650 :
651 0 : bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
652 : sal_Int32 /*nCurrElemCount*/,
653 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemBegin*/,
654 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& /*rCurrElemEnd*/ )
655 : {
656 0 : if( eCurrElemClassification == meClass )
657 0 : ++mnCurrCount;
658 :
659 0 : return true; // never stop, count all occurrences
660 : }
661 :
662 0 : sal_Int32 getCount() const
663 : {
664 0 : return mnCurrCount;
665 : }
666 :
667 : private:
668 : DrawShapeSubsetting::IndexClassificator meClass;
669 : sal_Int32 mnCurrCount;
670 : };
671 : }
672 :
673 0 : sal_Int32 DrawShapeSubsetting::implGetNumberOfTreeNodes( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
674 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
675 : DocTreeNode::NodeType eNodeType )
676 : {
677 : const IndexClassificator eRequestedClass(
678 0 : mapDocTreeNode( eNodeType ) );
679 :
680 : // create a counting functor for the requested class of
681 : // actions
682 0 : CountClassFunctor aFunctor( eRequestedClass );
683 :
684 : // count all occurrences in the given range
685 0 : iterateActionClassifications( aFunctor, rBegin, rEnd );
686 :
687 0 : return aFunctor.getCount();
688 : }
689 :
690 0 : sal_Int32 DrawShapeSubsetting::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const
691 : {
692 0 : ensureInitializedNodeTree();
693 :
694 0 : return implGetNumberOfTreeNodes( maActionClassVector.begin(),
695 0 : maActionClassVector.end(),
696 0 : eNodeType );
697 : }
698 :
699 : namespace
700 : {
701 : /** This functor finds the nth occurrence of a given
702 : action class.
703 :
704 : The operator() compares the given index value with the
705 : requested index, as given on the functor's
706 : constructor. Then, the operator() returns false,
707 : denoting that the requested action is found.
708 : */
709 : class FindNthElementFunctor
710 : {
711 : public:
712 0 : FindNthElementFunctor( sal_Int32 nNodeIndex,
713 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastBegin,
714 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rLastEnd,
715 : DrawShapeSubsetting::IndexClassificator eClass ) :
716 : mnNodeIndex( nNodeIndex ),
717 : mrLastBegin( rLastBegin ),
718 : mrLastEnd( rLastEnd ),
719 0 : meClass( eClass )
720 : {
721 0 : }
722 :
723 0 : bool operator()( DrawShapeSubsetting::IndexClassificator eCurrElemClassification,
724 : sal_Int32 nCurrElemCount,
725 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemBegin,
726 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rCurrElemEnd )
727 : {
728 0 : if( eCurrElemClassification == meClass &&
729 0 : nCurrElemCount == mnNodeIndex )
730 : {
731 0 : mrLastBegin = rCurrElemBegin;
732 0 : mrLastEnd = rCurrElemEnd;
733 :
734 0 : return false; // abort iteration, we've
735 : // already found what we've been
736 : // looking for
737 : }
738 :
739 0 : return true; // keep on truckin'
740 : }
741 :
742 : private:
743 : sal_Int32 mnNodeIndex;
744 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastBegin;
745 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator& mrLastEnd;
746 : DrawShapeSubsetting::IndexClassificator meClass;
747 : };
748 :
749 0 : DocTreeNode makeTreeNode( const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rBegin,
750 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rStart,
751 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator& rEnd,
752 : DocTreeNode::NodeType eNodeType )
753 : {
754 : return DocTreeNode( ::std::distance(rBegin,
755 0 : rStart),
756 : ::std::distance(rBegin,
757 0 : rEnd),
758 0 : eNodeType );
759 : }
760 : }
761 :
762 0 : DocTreeNode DrawShapeSubsetting::implGetTreeNode( const IndexClassificatorVector::const_iterator& rBegin,
763 : const IndexClassificatorVector::const_iterator& rEnd,
764 : sal_Int32 nNodeIndex,
765 : DocTreeNode::NodeType eNodeType ) const
766 : {
767 : const IndexClassificator eRequestedClass(
768 0 : mapDocTreeNode( eNodeType ) );
769 :
770 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastBegin(rEnd);
771 0 : DrawShapeSubsetting::IndexClassificatorVector::const_iterator aLastEnd(rEnd);
772 :
773 : // create a nth element functor for the requested class of
774 : // actions, and nNodeIndex as the target index
775 : FindNthElementFunctor aFunctor( nNodeIndex,
776 : aLastBegin,
777 : aLastEnd,
778 0 : eRequestedClass );
779 :
780 : // find given index in the given range
781 0 : iterateActionClassifications( aFunctor, rBegin, rEnd );
782 :
783 0 : return makeTreeNode( maActionClassVector.begin(),
784 : aLastBegin, aLastEnd,
785 0 : eNodeType );
786 : }
787 :
788 0 : DocTreeNode DrawShapeSubsetting::getTreeNode( sal_Int32 nNodeIndex,
789 : DocTreeNode::NodeType eNodeType ) const
790 : {
791 0 : ensureInitializedNodeTree();
792 :
793 0 : return implGetTreeNode( maActionClassVector.begin(),
794 0 : maActionClassVector.end(),
795 : nNodeIndex,
796 0 : eNodeType );
797 : }
798 :
799 0 : sal_Int32 DrawShapeSubsetting::getNumberOfSubsetTreeNodes( const DocTreeNode& rParentNode,
800 : DocTreeNode::NodeType eNodeType ) const
801 : {
802 0 : ensureInitializedNodeTree();
803 :
804 : // convert from vector indices to vector iterators
805 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
806 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
807 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
808 :
809 : return implGetNumberOfTreeNodes( aParentBegin,
810 : aParentEnd,
811 0 : eNodeType );
812 : }
813 :
814 0 : DocTreeNode DrawShapeSubsetting::getSubsetTreeNode( const DocTreeNode& rParentNode,
815 : sal_Int32 nNodeIndex,
816 : DocTreeNode::NodeType eNodeType ) const
817 : {
818 0 : ensureInitializedNodeTree();
819 :
820 : // convert from vector indices to vector iterators
821 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aBegin( maActionClassVector.begin() );
822 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentBegin( aBegin + rParentNode.getStartIndex() );
823 0 : const DrawShapeSubsetting::IndexClassificatorVector::const_iterator aParentEnd( aBegin + rParentNode.getEndIndex() );
824 :
825 : return implGetTreeNode( aParentBegin,
826 : aParentEnd,
827 : nNodeIndex,
828 0 : eNodeType );
829 : }
830 :
831 :
832 : }
833 3 : }
834 :
835 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|