1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <svl/eitem.hxx>
22 #include <svl/intitem.hxx>
23 #include <editeng/editeng.hxx>
24 #include <editeng/editview.hxx>
25 #include <editeng/editdata.hxx>
26 #include <editeng/lrspitem.hxx>
29 #include <svl/style.hxx>
30 #include <editeng/outliner.hxx>
31 #include "paralist.hxx"
32 #include <editeng/outlobj.hxx>
33 #include <outleeng.hxx>
34 #include "outlundo.hxx"
35 #include <editeng/eeitem.hxx>
36 #include <editeng/editstat.hxx>
37 #include <editeng/overflowingtxt.hxx>
38 #include <editeng/editobj.hxx>
39 #include <svl/itemset.hxx>
40 #include <vcl/metric.hxx>
41 #include <editeng/numitem.hxx>
42 #include <editeng/adjustitem.hxx>
43 #include <vcl/GraphicObject.hxx>
44 #include <editeng/svxfont.hxx>
45 #include <editeng/brushitem.hxx>
46 #include <svl/itempool.hxx>
47 #include <libxml/xmlwriter.h>
48 #include <sal/log.hxx>
49 #include <o3tl/safeint.hxx>
50 #include <o3tl/string_view.hxx>
51 #include <o3tl/temporary.hxx>
52 #include <osl/diagnose.h>
61 void Outliner::ImplCheckDepth( sal_Int16
& rnDepth
) const
63 if( rnDepth
< gnMinDepth
)
65 else if( rnDepth
> nMaxDepth
)
69 Paragraph
* Outliner::Insert(const OUString
& rText
, sal_Int32 nAbsPos
, sal_Int16 nDepth
)
71 DBG_ASSERT(pParaList
->GetParagraphCount(),"Insert:No Paras");
75 ImplCheckDepth( nDepth
);
77 sal_Int32 nParagraphCount
= pParaList
->GetParagraphCount();
78 if( nAbsPos
> nParagraphCount
)
79 nAbsPos
= nParagraphCount
;
81 if( bFirstParaIsEmpty
)
83 pPara
= pParaList
->GetParagraph( 0 );
84 if( pPara
->GetDepth() != nDepth
)
86 nDepthChangedHdlPrevDepth
= pPara
->GetDepth();
87 ParaFlag nPrevFlags
= pPara
->nFlags
;
88 pPara
->SetDepth( nDepth
);
89 DepthChangedHdl(pPara
, nPrevFlags
);
91 pPara
->nFlags
|= ParaFlag::HOLDDEPTH
;
92 SetText( rText
, pPara
);
96 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
97 ImplBlockInsertionCallbacks( true );
98 pPara
= new Paragraph( nDepth
);
99 pParaList
->Insert( std::unique_ptr
<Paragraph
>(pPara
), nAbsPos
);
100 pEditEngine
->InsertParagraph( nAbsPos
, OUString() );
101 DBG_ASSERT(pPara
==pParaList
->GetParagraph(nAbsPos
),"Insert:Failed");
102 ImplInitDepth( nAbsPos
, nDepth
, false );
103 ParagraphInsertedHdl(pPara
);
104 pPara
->nFlags
|= ParaFlag::HOLDDEPTH
;
105 SetText( rText
, pPara
);
106 ImplBlockInsertionCallbacks( false );
107 pEditEngine
->SetUpdateLayout( bUpdate
);
109 bFirstParaIsEmpty
= false;
110 DBG_ASSERT(pEditEngine
->GetParagraphCount()==pParaList
->GetParagraphCount(),"SetText failed");
115 void Outliner::ParagraphInserted( sal_Int32 nPara
)
118 if ( nBlockInsCallback
)
121 if( bPasting
|| pEditEngine
->IsInUndo() )
123 Paragraph
* pPara
= new Paragraph( -1 );
124 pParaList
->Insert( std::unique_ptr
<Paragraph
>(pPara
), nPara
);
125 if( pEditEngine
->IsInUndo() )
127 pPara
->bVisible
= true;
128 const SfxInt16Item
& rLevel
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_OUTLLEVEL
);
129 pPara
->SetDepth( rLevel
.GetValue() );
134 sal_Int16 nDepth
= -1;
135 Paragraph
* pParaBefore
= pParaList
->GetParagraph( nPara
-1 );
137 nDepth
= pParaBefore
->GetDepth();
139 Paragraph
* pPara
= new Paragraph( nDepth
);
140 pParaList
->Insert( std::unique_ptr
<Paragraph
>(pPara
), nPara
);
142 if( !pEditEngine
->IsInUndo() )
144 ImplCalcBulletText( nPara
, true, false );
145 ParagraphInsertedHdl(pPara
);
150 void Outliner::ParagraphDeleted( sal_Int32 nPara
)
153 if ( nBlockInsCallback
|| ( nPara
== EE_PARA_ALL
) )
156 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
160 sal_Int16 nDepth
= pPara
->GetDepth();
162 if( !pEditEngine
->IsInUndo() )
164 aParaRemovingHdl
.Call( { this, pPara
} );
167 pParaList
->Remove( nPara
);
169 if( pEditEngine
->IsInUndo() || bPasting
)
172 pPara
= pParaList
->GetParagraph( nPara
);
173 if ( pPara
&& ( pPara
->GetDepth() > nDepth
) )
175 ImplCalcBulletText( nPara
, true, false );
176 // Search for next on the this level ...
177 while ( pPara
&& pPara
->GetDepth() > nDepth
)
178 pPara
= pParaList
->GetParagraph( ++nPara
);
181 if ( pPara
&& ( pPara
->GetDepth() == nDepth
) )
182 ImplCalcBulletText( nPara
, true, false );
185 void Outliner::Init( OutlinerMode nMode
)
187 nOutlinerMode
= nMode
;
191 EEControlBits nCtrl
= pEditEngine
->GetControlWord();
192 nCtrl
&= ~EEControlBits(EEControlBits::OUTLINER
|EEControlBits::OUTLINER2
);
196 switch ( GetOutlinerMode() )
198 case OutlinerMode::TextObject
:
199 case OutlinerMode::TitleObject
:
202 case OutlinerMode::OutlineObject
:
203 nCtrl
|= EEControlBits::OUTLINER2
;
205 case OutlinerMode::OutlineView
:
206 nCtrl
|= EEControlBits::OUTLINER
;
209 default: OSL_FAIL( "Outliner::Init - Invalid Mode!" );
212 pEditEngine
->SetControlWord( nCtrl
);
214 const bool bWasUndoEnabled(IsUndoEnabled());
216 ImplInitDepth( 0, -1, false );
217 GetUndoManager().Clear();
218 EnableUndo(bWasUndoEnabled
);
221 void Outliner::SetMaxDepth( sal_Int16 nDepth
)
223 if( nMaxDepth
!= nDepth
)
225 nMaxDepth
= std::min( nDepth
, sal_Int16(SVX_MAX_NUM
-1) );
229 sal_Int16
Outliner::GetDepth( sal_Int32 nPara
) const
231 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
232 DBG_ASSERT( pPara
, "Outliner::GetDepth - Paragraph not found!" );
233 return pPara
? pPara
->GetDepth() : -1;
236 void Outliner::SetDepth( Paragraph
* pPara
, sal_Int16 nNewDepth
)
239 ImplCheckDepth( nNewDepth
);
241 if ( nNewDepth
== pPara
->GetDepth() )
244 nDepthChangedHdlPrevDepth
= pPara
->GetDepth();
245 ParaFlag nPrevFlags
= pPara
->nFlags
;
247 sal_Int32 nPara
= GetAbsPos( pPara
);
248 ImplInitDepth( nPara
, nNewDepth
, true );
249 ImplCalcBulletText( nPara
, false, false );
251 if ( GetOutlinerMode() == OutlinerMode::OutlineObject
)
252 ImplSetLevelDependentStyleSheet( nPara
);
254 DepthChangedHdl(pPara
, nPrevFlags
);
257 sal_Int16
Outliner::GetNumberingStartValue( sal_Int32 nPara
) const
259 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
260 DBG_ASSERT( pPara
, "Outliner::GetNumberingStartValue - Paragraph not found!" );
261 return pPara
? pPara
->GetNumberingStartValue() : -1;
264 void Outliner::SetNumberingStartValue( sal_Int32 nPara
, sal_Int16 nNumberingStartValue
)
266 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
267 DBG_ASSERT( pPara
, "Outliner::GetNumberingStartValue - Paragraph not found!" );
268 if( pPara
&& pPara
->GetNumberingStartValue() != nNumberingStartValue
)
270 if( IsUndoEnabled() && !IsInUndo() )
271 InsertUndo( std::make_unique
<OutlinerUndoChangeParaNumberingRestart
>( this, nPara
,
272 pPara
->GetNumberingStartValue(), nNumberingStartValue
,
273 pPara
->IsParaIsNumberingRestart(), pPara
->IsParaIsNumberingRestart() ) );
275 pPara
->SetNumberingStartValue( nNumberingStartValue
);
276 ImplCheckParagraphs( nPara
, pParaList
->GetParagraphCount() );
277 pEditEngine
->SetModified();
281 bool Outliner::IsParaIsNumberingRestart( sal_Int32 nPara
) const
283 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
284 DBG_ASSERT( pPara
, "Outliner::IsParaIsNumberingRestart - Paragraph not found!" );
285 return pPara
&& pPara
->IsParaIsNumberingRestart();
288 void Outliner::SetParaIsNumberingRestart( sal_Int32 nPara
, bool bParaIsNumberingRestart
)
290 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
291 DBG_ASSERT( pPara
, "Outliner::SetParaIsNumberingRestart - Paragraph not found!" );
292 if( pPara
&& (pPara
->IsParaIsNumberingRestart() != bParaIsNumberingRestart
) )
294 if( IsUndoEnabled() && !IsInUndo() )
295 InsertUndo( std::make_unique
<OutlinerUndoChangeParaNumberingRestart
>( this, nPara
,
296 pPara
->GetNumberingStartValue(), pPara
->GetNumberingStartValue(),
297 pPara
->IsParaIsNumberingRestart(), bParaIsNumberingRestart
) );
299 pPara
->SetParaIsNumberingRestart( bParaIsNumberingRestart
);
300 ImplCheckParagraphs( nPara
, pParaList
->GetParagraphCount() );
301 pEditEngine
->SetModified();
305 sal_Int32
Outliner::GetBulletsNumberingStatus(
306 const sal_Int32 nParaStart
,
307 const sal_Int32 nParaEnd
) const
309 if ( nParaStart
> nParaEnd
310 || nParaEnd
>= pParaList
->GetParagraphCount() )
312 SAL_WARN("editeng", "<Outliner::GetBulletsNumberingStatus> - unexpected parameter values" );
316 sal_Int32 nBulletsCount
= 0;
317 sal_Int32 nNumberingCount
= 0;
318 for (sal_Int32 nPara
= nParaStart
; nPara
<= nParaEnd
; ++nPara
)
320 if ( !pParaList
->GetParagraph(nPara
) )
324 const SvxNumberFormat
* pFmt
= GetNumberFormat(nPara
);
327 // At least, exists one paragraph that has no Bullets/Numbering.
330 else if ((pFmt
->GetNumberingType() == SVX_NUM_BITMAP
) || (pFmt
->GetNumberingType() == SVX_NUM_CHAR_SPECIAL
))
332 // Having Bullets in this paragraph.
337 // Having Numbering in this paragraph.
342 const sal_Int32 nParaCount
= nParaEnd
- nParaStart
+ 1;
343 if ( nBulletsCount
== nParaCount
)
347 else if ( nNumberingCount
== nParaCount
)
354 sal_Int32
Outliner::GetBulletsNumberingStatus() const
356 return pParaList
->GetParagraphCount() > 0
357 ? GetBulletsNumberingStatus( 0, pParaList
->GetParagraphCount()-1 )
361 std::optional
<OutlinerParaObject
> Outliner::CreateParaObject( sal_Int32 nStartPara
, sal_Int32 nCount
) const
363 if ( static_cast<sal_uInt64
>(nStartPara
) + nCount
>
364 o3tl::make_unsigned(pParaList
->GetParagraphCount()) )
365 nCount
= pParaList
->GetParagraphCount() - nStartPara
;
367 // When a new OutlinerParaObject is created because a paragraph is just being deleted,
368 // it can happen that the ParaList is not updated yet...
369 if ( ( nStartPara
+ nCount
) > pEditEngine
->GetParagraphCount() )
370 nCount
= pEditEngine
->GetParagraphCount() - nStartPara
;
375 std::unique_ptr
<EditTextObject
> xText
= pEditEngine
->CreateTextObject( nStartPara
, nCount
);
376 const bool bIsEditDoc(OutlinerMode::TextObject
== GetOutlinerMode());
377 ParagraphDataVector
aParagraphDataVector(nCount
);
378 const sal_Int32
nLastPara(nStartPara
+ nCount
- 1);
380 for(sal_Int32
nPara(nStartPara
); nPara
<= nLastPara
; nPara
++)
382 aParagraphDataVector
[nPara
-nStartPara
] = *GetParagraph(nPara
);
385 xText
->ClearPortionInfo(); // tdf#147166 the PortionInfo is unwanted here
386 OutlinerParaObject
aPObj(std::move(xText
), std::move(aParagraphDataVector
), bIsEditDoc
);
387 aPObj
.SetOutlinerMode(GetOutlinerMode());
392 void Outliner::SetToEmptyText()
394 SetText(GetEmptyParaObject());
397 void Outliner::SetText( const OUString
& rText
, Paragraph
* pPara
)
399 DBG_ASSERT(pPara
,"SetText:No Para");
401 const sal_Int32 nPara
= pParaList
->GetAbsPos( pPara
);
403 if (pEditEngine
->GetText( nPara
) == rText
)
405 // short-circuit logic to improve performance
406 bFirstParaIsEmpty
= false;
410 const bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
411 ImplBlockInsertionCallbacks( true );
415 pEditEngine
->SetText( nPara
, rText
);
416 ImplInitDepth( nPara
, pPara
->GetDepth(), false );
420 const OUString
aText(convertLineEnd(rText
, LINEEND_LF
));
423 sal_Int32 nInsPos
= nPara
+1;
425 // Loop over all tokens, but ignore the last one if empty
426 // (i.e. if strings ends with the delimiter, detected by
427 // checking nIdx against string length). This check also
428 // handle empty strings.
429 while( nIdx
>=0 && nIdx
<aText
.getLength() )
431 std::u16string_view aStr
= o3tl::getToken(aText
, 0, '\x0A', nIdx
);
436 pPara
= new Paragraph( -1 );
440 nCurDepth
= pPara
->GetDepth();
442 // In the outliner mode, filter the tabs and set the indentation
443 // about a LRSpaceItem. In EditEngine mode intend over old tabs
444 if( ( GetOutlinerMode() == OutlinerMode::OutlineObject
) ||
445 ( GetOutlinerMode() == OutlinerMode::OutlineView
) )
449 while ( ( nTabs
< aStr
.size() ) && ( aStr
[nTabs
] == '\t' ) )
452 aStr
= aStr
.substr(nTabs
);
454 // Keep depth? (see Outliner::Insert)
455 if( !(pPara
->nFlags
& ParaFlag::HOLDDEPTH
) )
457 nCurDepth
= nTabs
-1; //TODO: sal_Int32 -> sal_Int16!
458 ImplCheckDepth( nCurDepth
);
459 pPara
->SetDepth( nCurDepth
);
462 if( nPos
) // not with the first paragraph
464 pParaList
->Insert( std::unique_ptr
<Paragraph
>(pPara
), nInsPos
);
465 pEditEngine
->InsertParagraph( nInsPos
, OUString(aStr
) );
466 ParagraphInsertedHdl(pPara
);
471 pEditEngine
->SetText( nInsPos
, OUString(aStr
) );
473 ImplInitDepth( nInsPos
, nCurDepth
, false );
479 DBG_ASSERT(pParaList
->GetParagraphCount()==pEditEngine
->GetParagraphCount(),"SetText failed!");
480 bFirstParaIsEmpty
= false;
481 ImplBlockInsertionCallbacks( false );
482 // Restore the update mode.
483 pEditEngine
->SetUpdateLayout(bUpdate
, /*bRestoring=*/true);
486 // pView == 0 -> Ignore tabs
488 bool Outliner::ImpConvertEdtToOut( sal_Int32 nPara
)
491 bool bConverted
= false;
497 OUString
aStr( pEditEngine
->GetText( nPara
) );
498 const sal_Unicode
* pPtr
= aStr
.getStr();
500 sal_Int32 nHeadingNumberStart
= 0;
501 sal_Int32 nNumberingNumberStart
= 0;
502 SfxStyleSheet
* pStyle
= pEditEngine
->GetStyleSheet( nPara
);
505 OUString
aHeading_US( "heading" );
506 OUString
aNumber_US( "Numbering" );
507 aName
= pStyle
->GetName();
509 if ( ( nSearch
= aName
.indexOf( aHeading_US
) ) != -1 )
510 nHeadingNumberStart
= nSearch
+ aHeading_US
.getLength();
511 else if ( ( nSearch
= aName
.indexOf( aNumber_US
) ) != -1 )
512 nNumberingNumberStart
= nSearch
+ aNumber_US
.getLength();
515 if ( nHeadingNumberStart
|| nNumberingNumberStart
)
517 // PowerPoint import ?
518 if( nHeadingNumberStart
&& ( aStr
.getLength() >= 2 ) &&
519 ( pPtr
[0] != '\t' ) && ( pPtr
[1] == '\t' ) )
521 // Extract Bullet and Tab
522 aDelSel
= ESelection( nPara
, 0, nPara
, 2 );
525 sal_Int32 nPos
= nHeadingNumberStart
? nHeadingNumberStart
: nNumberingNumberStart
;
526 std::u16string_view aLevel
= comphelper::string::stripStart(aName
.subView(nPos
), ' ');
527 nTabs
= o3tl::toInt32(aLevel
);
529 nTabs
--; // Level 0 = "heading 1"
534 // filter leading tabs
535 while( *pPtr
== '\t' )
540 // Remove tabs from the text
542 aDelSel
= ESelection( nPara
, 0, nPara
, nTabs
);
545 if ( aDelSel
.HasRange() )
547 pEditEngine
->QuickDelete( aDelSel
);
550 const SfxInt16Item
& rLevel
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_OUTLLEVEL
);
551 sal_Int16 nOutlLevel
= rLevel
.GetValue();
553 ImplCheckDepth( nOutlLevel
);
554 ImplInitDepth( nPara
, nOutlLevel
, false );
559 void Outliner::SetText( const OutlinerParaObject
& rPObj
)
561 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
563 bool bUndo
= pEditEngine
->IsUndoEnabled();
566 Init( rPObj
.GetOutlinerMode() );
568 ImplBlockInsertionCallbacks( true );
569 pEditEngine
->SetText(rPObj
.GetTextObject());
571 bFirstParaIsEmpty
= false;
574 for( sal_Int32 nCurPara
= 0; nCurPara
< rPObj
.Count(); nCurPara
++ )
576 std::unique_ptr
<Paragraph
> pPara(new Paragraph( rPObj
.GetParagraphData(nCurPara
)));
577 ImplCheckDepth( pPara
->nDepth
);
579 pParaList
->Append(std::move(pPara
));
580 ImplCheckNumBulletItem( nCurPara
);
583 ImplCheckParagraphs( 0, pParaList
->GetParagraphCount() );
586 ImplBlockInsertionCallbacks( false );
587 pEditEngine
->SetUpdateLayout( bUpdate
);
589 DBG_ASSERT( pParaList
->GetParagraphCount()==rPObj
.Count(),"SetText failed");
590 DBG_ASSERT( pEditEngine
->GetParagraphCount()==rPObj
.Count(),"SetText failed");
593 void Outliner::AddText( const OutlinerParaObject
& rPObj
, bool bAppend
)
595 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
597 ImplBlockInsertionCallbacks( true );
599 if( bFirstParaIsEmpty
)
602 pEditEngine
->SetText(rPObj
.GetTextObject());
608 nPara
= pParaList
->GetParagraphCount();
609 pEditEngine
->InsertParagraph( EE_PARA_APPEND
, rPObj
.GetTextObject(), bAppend
);
611 bFirstParaIsEmpty
= false;
613 for( sal_Int32 n
= 0; n
< rPObj
.Count(); n
++ )
615 if ( n
== 0 && bAppend
)
617 // This first "paragraph" was just appended to an existing (incomplete) paragraph.
618 // Since no new paragraph will be added, the assumed increase-by-1 also won't happen.
623 Paragraph
* pPara
= new Paragraph( rPObj
.GetParagraphData(n
) );
624 pParaList
->Append(std::unique_ptr
<Paragraph
>(pPara
));
625 sal_Int32 nP
= nPara
+n
;
626 DBG_ASSERT(pParaList
->GetAbsPos(pPara
)==nP
,"AddText:Out of sync");
627 ImplInitDepth( nP
, pPara
->GetDepth(), false );
629 DBG_ASSERT( pEditEngine
->GetParagraphCount()==pParaList
->GetParagraphCount(), "SetText: OutOfSync" );
631 ImplCheckParagraphs( nPara
, pParaList
->GetParagraphCount() );
633 ImplBlockInsertionCallbacks( false );
634 pEditEngine
->SetUpdateLayout( bUpdate
);
637 OUString
Outliner::CalcFieldValue( const SvxFieldItem
& rField
, sal_Int32 nPara
, sal_Int32 nPos
, std::optional
<Color
>& rpTxtColor
, std::optional
<Color
>& rpFldColor
, std::optional
<FontLineStyle
>& rpFldLineStyle
)
639 if ( !aCalcFieldValueHdl
.IsSet() )
640 return OUString( ' ' );
642 EditFieldInfo
aFldInfo( this, rField
, nPara
, nPos
);
643 // The FldColor is preset with COL_LIGHTGRAY.
645 aFldInfo
.SetFieldColor( *rpFldColor
);
647 aCalcFieldValueHdl
.Call( &aFldInfo
);
648 if ( aFldInfo
.GetTextColor() )
650 rpTxtColor
= *aFldInfo
.GetTextColor();
653 if ( aFldInfo
.GetFontLineStyle() )
655 rpFldLineStyle
= *aFldInfo
.GetFontLineStyle();
658 if (aFldInfo
.GetFieldColor())
659 rpFldColor
= *aFldInfo
.GetFieldColor();
663 return aFldInfo
.GetRepresentation();
666 void Outliner::SetStyleSheet( sal_Int32 nPara
, SfxStyleSheet
* pStyle
)
668 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
671 pEditEngine
->SetStyleSheet( nPara
, pStyle
);
672 ImplCheckNumBulletItem( nPara
);
676 void Outliner::ImplCheckNumBulletItem( sal_Int32 nPara
)
678 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
680 pPara
->aBulSize
.setWidth( -1 );
683 void Outliner::ImplSetLevelDependentStyleSheet( sal_Int32 nPara
)
686 DBG_ASSERT( ( GetOutlinerMode() == OutlinerMode::OutlineObject
) || ( GetOutlinerMode() == OutlinerMode::OutlineView
), "SetLevelDependentStyleSheet: Wrong Mode!" );
688 SfxStyleSheet
* pStyle
= GetStyleSheet( nPara
);
693 sal_Int16 nDepth
= GetDepth( nPara
);
697 OUString
aNewStyleSheetName( pStyle
->GetName() );
698 aNewStyleSheetName
= aNewStyleSheetName
.subView( 0, aNewStyleSheetName
.getLength()-1 ) +
699 OUString::number( nDepth
+1 );
700 SfxStyleSheet
* pNewStyle
= static_cast<SfxStyleSheet
*>(GetStyleSheetPool()->Find( aNewStyleSheetName
, pStyle
->GetFamily() ));
701 DBG_ASSERT( pNewStyle
, "AutoStyleSheetName - Style not found!" );
702 if ( pNewStyle
&& ( pNewStyle
!= GetStyleSheet( nPara
) ) )
704 SfxItemSet
aOldAttrs( GetParaAttribs( nPara
) );
705 SetStyleSheet( nPara
, pNewStyle
);
706 if ( aOldAttrs
.GetItemState( EE_PARA_NUMBULLET
) == SfxItemState::SET
)
708 SfxItemSet
aAttrs( GetParaAttribs( nPara
) );
709 aAttrs
.Put( aOldAttrs
.Get( EE_PARA_NUMBULLET
) );
710 SetParaAttribs( nPara
, aAttrs
);
715 void Outliner::ImplInitDepth( sal_Int32 nPara
, sal_Int16 nDepth
, bool bCreateUndo
)
718 DBG_ASSERT( ( nDepth
>= gnMinDepth
) && ( nDepth
<= nMaxDepth
), "ImplInitDepth - Depth is invalid!" );
720 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
723 sal_Int16 nOldDepth
= pPara
->GetDepth();
724 pPara
->SetDepth( nDepth
);
726 // For IsInUndo attributes and style do not have to be set, there
727 // the old values are restored by the EditEngine.
731 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
733 bool bUndo
= bCreateUndo
&& IsUndoEnabled();
735 SfxItemSet
aAttrs( pEditEngine
->GetParaAttribs( nPara
) );
736 aAttrs
.Put( SfxInt16Item( EE_PARA_OUTLLEVEL
, nDepth
) );
737 pEditEngine
->SetParaAttribs( nPara
, aAttrs
);
738 ImplCheckNumBulletItem( nPara
);
739 ImplCalcBulletText( nPara
, false, false );
743 InsertUndo( std::make_unique
<OutlinerUndoChangeDepth
>( this, nPara
, nOldDepth
, nDepth
) );
746 pEditEngine
->SetUpdateLayout( bUpdate
);
749 void Outliner::SetParaAttribs( sal_Int32 nPara
, const SfxItemSet
& rSet
)
752 pEditEngine
->SetParaAttribs( nPara
, rSet
);
755 void Outliner::SetCharAttribs(sal_Int32 nPara
, const SfxItemSet
& rSet
)
757 pEditEngine
->SetCharAttribs(nPara
, rSet
);
760 bool Outliner::Expand( Paragraph
const * pPara
)
762 if ( !pParaList
->HasHiddenChildren( pPara
) )
765 std::unique_ptr
<OLUndoExpand
> pUndo
;
766 bool bUndo
= IsUndoEnabled() && !IsInUndo();
769 UndoActionStart( OLUNDO_EXPAND
);
770 pUndo
.reset( new OLUndoExpand( this, OLUNDO_EXPAND
) );
771 pUndo
->nCount
= pParaList
->GetAbsPos( pPara
);
773 pParaList
->Expand( pPara
);
774 InvalidateBullet(pParaList
->GetAbsPos(pPara
));
777 InsertUndo( std::move(pUndo
) );
783 bool Outliner::Collapse( Paragraph
const * pPara
)
785 if ( !pParaList
->HasVisibleChildren( pPara
) ) // collapsed
788 std::unique_ptr
<OLUndoExpand
> pUndo
;
791 if( !IsInUndo() && IsUndoEnabled() )
795 UndoActionStart( OLUNDO_COLLAPSE
);
796 pUndo
.reset( new OLUndoExpand( this, OLUNDO_COLLAPSE
) );
797 pUndo
->nCount
= pParaList
->GetAbsPos( pPara
);
800 pParaList
->Collapse( pPara
);
801 InvalidateBullet(pParaList
->GetAbsPos(pPara
));
804 InsertUndo( std::move(pUndo
) );
810 vcl::Font
Outliner::ImpCalcBulletFont( sal_Int32 nPara
) const
812 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
813 DBG_ASSERT( pFmt
&& ( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
) && ( pFmt
->GetNumberingType() != SVX_NUM_NUMBER_NONE
), "ImpCalcBulletFont: Missing or BitmapBullet!" );
816 if ( !pEditEngine
->IsFlatMode() )
818 ESelection
aSel( nPara
, 0, nPara
, 0 );
819 aStdFont
= EditEngine::CreateFontFromItemSet( pEditEngine
->GetAttribs( aSel
), pEditEngine
->GetScriptType( aSel
) );
823 aStdFont
= pEditEngine
->GetStandardFont( nPara
);
826 vcl::Font aBulletFont
;
827 std::optional
<vcl::Font
> pSourceFont
;
828 if ( pFmt
->GetNumberingType() == SVX_NUM_CHAR_SPECIAL
)
830 pSourceFont
= pFmt
->GetBulletFont();
835 aBulletFont
= *pSourceFont
;
839 aBulletFont
= aStdFont
;
840 aBulletFont
.SetUnderline( LINESTYLE_NONE
);
841 aBulletFont
.SetOverline( LINESTYLE_NONE
);
842 aBulletFont
.SetStrikeout( STRIKEOUT_NONE
);
843 aBulletFont
.SetEmphasisMark( FontEmphasisMark::NONE
);
844 aBulletFont
.SetRelief( FontRelief::NONE
);
847 // Use original scale...
849 double fFontScaleY
= pFmt
->GetBulletRelSize() * (getScalingParameters().fFontY
/ 100.0);
850 double fScaledLineHeight
= aStdFont
.GetFontSize().Height();
851 fScaledLineHeight
*= fFontScaleY
* 10;
852 fScaledLineHeight
/= 1000.0;
854 aBulletFont
.SetAlignment( ALIGN_BOTTOM
);
855 aBulletFont
.SetFontSize(Size(0, basegfx::fround(fScaledLineHeight
)));
856 bool bVertical
= IsVertical();
857 aBulletFont
.SetVertical( bVertical
);
858 aBulletFont
.SetOrientation( Degree10(bVertical
? (IsTopToBottom() ? 2700 : 900) : 0) );
860 Color
aColor( COL_AUTO
);
861 if( !pEditEngine
->IsFlatMode() && !( pEditEngine
->GetControlWord() & EEControlBits::NOCOLORS
) )
863 aColor
= pFmt
->GetBulletColor();
866 if ( ( aColor
== COL_AUTO
) || ( IsForceAutoColor() ) )
867 aColor
= pEditEngine
->GetAutoColor();
869 aBulletFont
.SetColor( aColor
);
873 void Outliner::PaintBullet(sal_Int32 nPara
, const Point
& rStartPos
, const Point
& rOrigin
,
874 Degree10 nOrientation
, OutputDevice
& rOutDev
)
877 bool bDrawBullet
= false;
880 const SfxBoolItem
& rBulletState
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_BULLETSTATE
);
881 bDrawBullet
= rBulletState
.GetValue();
884 if (!(bDrawBullet
&& ImplHasNumberFormat(nPara
)))
887 bool bVertical
= IsVertical();
888 bool bTopToBottom
= IsTopToBottom();
890 bool bRightToLeftPara
= pEditEngine
->IsRightToLeft( nPara
);
892 tools::Rectangle
aBulletArea( ImpCalcBulletArea( nPara
, true, false ) );
894 double fSpacingFactorX
= getScalingParameters().fSpacingX
/ 100.0;
896 tools::Long nStretchBulletX
= basegfx::fround(double(aBulletArea
.Left()) * fSpacingFactorX
);
897 tools::Long nStretchBulletWidth
= basegfx::fround(double(aBulletArea
.GetWidth()) * fSpacingFactorX
);
898 aBulletArea
= tools::Rectangle(Point(nStretchBulletX
, aBulletArea
.Top()),
899 Size(nStretchBulletWidth
, aBulletArea
.GetHeight()) );
901 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
902 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
903 if ( pFmt
&& ( pFmt
->GetNumberingType() != SVX_NUM_NUMBER_NONE
) )
905 if( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
)
907 vcl::Font
aBulletFont( ImpCalcBulletFont( nPara
) );
909 bool bSymbol
= pFmt
->GetNumberingType() == SVX_NUM_CHAR_SPECIAL
;
910 aBulletFont
.SetAlignment( bSymbol
? ALIGN_BOTTOM
: ALIGN_BASELINE
);
911 vcl::Font aOldFont
= rOutDev
.GetFont();
912 rOutDev
.SetFont( aBulletFont
);
914 ParagraphInfos aParaInfos
= pEditEngine
->GetParagraphInfos( nPara
);
918 // aTextPos.Y() = rStartPos.Y() + aBulletArea.Bottom();
919 aTextPos
.setY( rStartPos
.Y() + ( bSymbol
? aBulletArea
.Bottom() : aParaInfos
.nFirstLineMaxAscent
) );
920 if ( !bRightToLeftPara
)
921 aTextPos
.setX( rStartPos
.X() + aBulletArea
.Left() );
923 aTextPos
.setX( rStartPos
.X() + GetPaperSize().Width() - aBulletArea
.Right() );
929 // aTextPos.X() = rStartPos.X() - aBulletArea.Bottom();
930 aTextPos
.setX( rStartPos
.X() - (bSymbol
? aBulletArea
.Bottom() : aParaInfos
.nFirstLineMaxAscent
) );
931 aTextPos
.setY( rStartPos
.Y() + aBulletArea
.Left() );
935 aTextPos
.setX( rStartPos
.X() + (bSymbol
? aBulletArea
.Bottom() : aParaInfos
.nFirstLineMaxAscent
) );
936 aTextPos
.setY( rStartPos
.Y() + aBulletArea
.Left() );
942 // Both TopLeft and bottom left is not quite correct,
943 // since in EditEngine baseline ...
944 rOrigin
.RotateAround(aTextPos
, nOrientation
);
946 vcl::Font
aRotatedFont( aBulletFont
);
947 aRotatedFont
.SetOrientation( nOrientation
);
948 rOutDev
.SetFont( aRotatedFont
);
951 // VCL will take care of brackets and so on...
952 vcl::text::ComplexTextLayoutFlags nLayoutMode
= rOutDev
.GetLayoutMode();
953 nLayoutMode
&= ~vcl::text::ComplexTextLayoutFlags(vcl::text::ComplexTextLayoutFlags::BiDiRtl
|vcl::text::ComplexTextLayoutFlags::BiDiStrong
);
954 if ( bRightToLeftPara
)
955 nLayoutMode
|= vcl::text::ComplexTextLayoutFlags::BiDiRtl
| vcl::text::ComplexTextLayoutFlags::TextOriginLeft
| vcl::text::ComplexTextLayoutFlags::BiDiStrong
;
956 rOutDev
.SetLayoutMode( nLayoutMode
);
958 if(bStrippingPortions
)
960 const vcl::Font
& aSvxFont(rOutDev
.GetFont());
962 rOutDev
.GetTextArray( pPara
->GetText(), &aBuf
);
966 // aTextPos is Bottom, go to Baseline
967 FontMetric
aMetric(rOutDev
.GetFontMetric());
968 aTextPos
.AdjustY( -(aMetric
.GetDescent()) );
971 assert(aBuf
.get_factor() == 1);
972 DrawingText(aTextPos
, pPara
->GetText(), 0, pPara
->GetText().getLength(), aBuf
.get_subunit_array(), {},
973 aSvxFont
, nPara
, bRightToLeftPara
? 1 : 0, nullptr, nullptr, false, false, true, nullptr, Color(), Color());
977 rOutDev
.DrawText( aTextPos
, pPara
->GetText() );
980 rOutDev
.SetFont( aOldFont
);
984 if ( pFmt
->GetBrush()->GetGraphicObject() )
989 aBulletPos
.setY( rStartPos
.Y() + aBulletArea
.Top() );
990 if ( !bRightToLeftPara
)
991 aBulletPos
.setX( rStartPos
.X() + aBulletArea
.Left() );
993 aBulletPos
.setX( rStartPos
.X() + GetPaperSize().Width() - aBulletArea
.Right() );
999 aBulletPos
.setX( rStartPos
.X() - aBulletArea
.Bottom() );
1000 aBulletPos
.setY( rStartPos
.Y() + aBulletArea
.Left() );
1004 aBulletPos
.setX( rStartPos
.X() + aBulletArea
.Top() );
1005 aBulletPos
.setY( rStartPos
.Y() - aBulletArea
.Right() );
1009 if(bStrippingPortions
)
1011 if(aDrawBulletHdl
.IsSet())
1013 // call something analog to aDrawPortionHdl (if set) and feed it something
1014 // analog to DrawPortionInfo...
1015 // created aDrawBulletHdl, Set/GetDrawBulletHdl.
1016 // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx
1017 DrawBulletInfo
aDrawBulletInfo(
1018 *pFmt
->GetBrush()->GetGraphicObject(),
1022 aDrawBulletHdl
.Call(&aDrawBulletInfo
);
1027 pFmt
->GetBrush()->GetGraphicObject()->Draw(rOutDev
, aBulletPos
, pPara
->aBulSize
);
1033 // In case of collapsed subparagraphs paint a line before the text.
1034 if( !pParaList
->HasChildren(pPara
) || pParaList
->HasVisibleChildren(pPara
) ||
1035 bStrippingPortions
|| nOrientation
)
1038 tools::Long nWidth
= rOutDev
.PixelToLogic( Size( 10, 0 ) ).Width();
1040 Point aStartPos
, aEndPos
;
1043 aStartPos
.setY( rStartPos
.Y() + aBulletArea
.Bottom() );
1044 if ( !bRightToLeftPara
)
1045 aStartPos
.setX( rStartPos
.X() + aBulletArea
.Right() );
1047 aStartPos
.setX( rStartPos
.X() + GetPaperSize().Width() - aBulletArea
.Left() );
1048 aEndPos
= aStartPos
;
1049 aEndPos
.AdjustX(nWidth
);
1053 aStartPos
.setX( rStartPos
.X() - aBulletArea
.Bottom() );
1054 aStartPos
.setY( rStartPos
.Y() + aBulletArea
.Right() );
1055 aEndPos
= aStartPos
;
1056 aEndPos
.AdjustY(nWidth
);
1059 const Color
& rOldLineColor
= rOutDev
.GetLineColor();
1060 rOutDev
.SetLineColor( COL_BLACK
);
1061 rOutDev
.DrawLine( aStartPos
, aEndPos
);
1062 rOutDev
.SetLineColor( rOldLineColor
);
1065 void Outliner::InvalidateBullet(sal_Int32 nPara
)
1067 tools::Long nLineHeight
= static_cast<tools::Long
>(pEditEngine
->GetLineHeight(nPara
));
1068 for (OutlinerView
* pView
: aViewList
)
1070 Point
aPos( pView
->pEditView
->GetWindowPosTopLeft(nPara
) );
1071 tools::Rectangle
aRect( pView
->GetOutputArea() );
1072 aRect
.SetRight( aPos
.X() );
1073 aRect
.SetTop( aPos
.Y() );
1074 aRect
.SetBottom( aPos
.Y() );
1075 aRect
.AdjustBottom(nLineHeight
);
1077 pView
->pEditView
->InvalidateWindow(aRect
);
1081 ErrCode
Outliner::Read( SvStream
& rInput
, const OUString
& rBaseURL
, EETextFormat eFormat
, SvKeyValueIterator
* pHTTPHeaderAttrs
)
1084 bool bOldUndo
= pEditEngine
->IsUndoEnabled();
1085 EnableUndo( false );
1087 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
1091 ImplBlockInsertionCallbacks( true );
1092 ErrCode nRet
= pEditEngine
->Read( rInput
, rBaseURL
, eFormat
, pHTTPHeaderAttrs
);
1094 bFirstParaIsEmpty
= false;
1096 sal_Int32 nParas
= pEditEngine
->GetParagraphCount();
1098 for ( sal_Int32 n
= 0; n
< nParas
; n
++ )
1100 std::unique_ptr
<Paragraph
> pPara(new Paragraph( 0 ));
1101 pParaList
->Append(std::move(pPara
));
1104 ImpFilterIndents( 0, nParas
-1 );
1106 ImplBlockInsertionCallbacks( false );
1107 pEditEngine
->SetUpdateLayout( bUpdate
);
1108 EnableUndo( bOldUndo
);
1114 void Outliner::ImpFilterIndents( sal_Int32 nFirstPara
, sal_Int32 nLastPara
)
1116 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
1118 Paragraph
* pLastConverted
= nullptr;
1119 for( sal_Int32 nPara
= nFirstPara
; nPara
<= nLastPara
; nPara
++ )
1121 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1124 if( ImpConvertEdtToOut( nPara
) )
1126 pLastConverted
= pPara
;
1128 else if ( pLastConverted
)
1130 // Arrange normal paragraphs below the heading ...
1131 pPara
->SetDepth( pLastConverted
->GetDepth() );
1134 ImplInitDepth( nPara
, pPara
->GetDepth(), false );
1138 pEditEngine
->SetUpdateLayout( bUpdate
);
1141 EditUndoManager
& Outliner::GetUndoManager()
1143 return pEditEngine
->GetUndoManager();
1146 EditUndoManager
* Outliner::SetUndoManager(EditUndoManager
* pNew
)
1148 return pEditEngine
->SetUndoManager(pNew
);
1151 void Outliner::ImpTextPasted( sal_Int32 nStartPara
, sal_Int32 nCount
)
1153 bool bUpdate
= pEditEngine
->SetUpdateLayout( false );
1155 const sal_Int32 nStart
= nStartPara
;
1157 Paragraph
* pPara
= pParaList
->GetParagraph( nStartPara
);
1159 while( nCount
&& pPara
)
1161 if( GetOutlinerMode() != OutlinerMode::TextObject
)
1163 nDepthChangedHdlPrevDepth
= pPara
->GetDepth();
1164 ParaFlag nPrevFlags
= pPara
->nFlags
;
1166 ImpConvertEdtToOut( nStartPara
);
1168 if( nStartPara
== nStart
)
1170 // the existing paragraph has changed depth or flags
1171 if( (pPara
->GetDepth() != nDepthChangedHdlPrevDepth
) || (pPara
->nFlags
!= nPrevFlags
) )
1172 DepthChangedHdl(pPara
, nPrevFlags
);
1175 else // EditEngine mode
1177 sal_Int16 nDepth
= -1;
1178 const SfxItemSet
& rAttrs
= pEditEngine
->GetParaAttribs( nStartPara
);
1179 if ( rAttrs
.GetItemState( EE_PARA_OUTLLEVEL
) == SfxItemState::SET
)
1181 const SfxInt16Item
& rLevel
= rAttrs
.Get( EE_PARA_OUTLLEVEL
);
1182 nDepth
= rLevel
.GetValue();
1184 if ( nDepth
!= GetDepth( nStartPara
) )
1185 ImplInitDepth( nStartPara
, nDepth
, false );
1190 pPara
= pParaList
->GetParagraph( nStartPara
);
1193 pEditEngine
->SetUpdateLayout( bUpdate
);
1195 DBG_ASSERT(pParaList
->GetParagraphCount()==pEditEngine
->GetParagraphCount(),"ImpTextPasted failed");
1198 bool Outliner::IndentingPagesHdl( OutlinerView
* pView
)
1200 if( !aIndentingPagesHdl
.IsSet() )
1202 return aIndentingPagesHdl
.Call( pView
);
1205 bool Outliner::ImpCanIndentSelectedPages( OutlinerView
* pCurView
)
1207 // The selected pages must already be set in advance through
1208 // ImpCalcSelectedPages
1210 // If the first paragraph is on level 0 it can not indented in any case,
1211 // possible there might be indentations in the following on the 0 level.
1212 if ( ( mnFirstSelPage
== 0 ) && ( GetOutlinerMode() != OutlinerMode::TextObject
) )
1214 if ( nDepthChangedHdlPrevDepth
== 1 ) // is the only page
1217 (void)pCurView
->ImpCalcSelectedPages( false ); // without the first
1219 return IndentingPagesHdl( pCurView
);
1223 bool Outliner::ImpCanDeleteSelectedPages( OutlinerView
* pCurView
)
1225 // The selected pages must already be set in advance through
1226 // ImpCalcSelectedPages
1227 return RemovingPagesHdl( pCurView
);
1230 Outliner::Outliner(SfxItemPool
* pPool
, OutlinerMode nMode
)
1232 , nDepthChangedHdlPrevDepth(0)
1234 , bFirstParaIsEmpty(true)
1235 , nBlockInsCallback(0)
1236 , bStrippingPortions(false)
1240 pParaList
.reset( new ParagraphList
);
1241 pParaList
->SetVisibleStateChangedHdl( LINK( this, Outliner
, ParaVisibleStateChangedHdl
) );
1242 std::unique_ptr
<Paragraph
> pPara(new Paragraph( 0 ));
1243 pParaList
->Append(std::move(pPara
));
1245 pEditEngine
.reset( new OutlinerEditEng( this, pPool
) );
1246 pEditEngine
->SetBeginMovingParagraphsHdl( LINK( this, Outliner
, BeginMovingParagraphsHdl
) );
1247 pEditEngine
->SetEndMovingParagraphsHdl( LINK( this, Outliner
, EndMovingParagraphsHdl
) );
1248 pEditEngine
->SetBeginPasteOrDropHdl( LINK( this, Outliner
, BeginPasteOrDropHdl
) );
1249 pEditEngine
->SetEndPasteOrDropHdl( LINK( this, Outliner
, EndPasteOrDropHdl
) );
1254 Outliner::~Outliner()
1258 pEditEngine
.reset();
1261 size_t Outliner::InsertView( OutlinerView
* pView
, size_t nIndex
)
1265 if ( nIndex
>= aViewList
.size() )
1267 aViewList
.push_back( pView
);
1268 ActualIndex
= aViewList
.size() - 1;
1272 ViewList::iterator it
= aViewList
.begin();
1273 advance( it
, nIndex
);
1274 ActualIndex
= nIndex
;
1276 pEditEngine
->InsertView( pView
->pEditView
.get(), nIndex
);
1280 void Outliner::RemoveView( OutlinerView
const * pView
)
1282 ViewList::iterator it
= std::find(aViewList
.begin(), aViewList
.end(), pView
);
1283 if (it
!= aViewList
.end())
1285 pView
->pEditView
->HideCursor(); // HACK
1286 pEditEngine
->RemoveView( pView
->pEditView
.get() );
1287 aViewList
.erase( it
);
1291 void Outliner::RemoveView( size_t nIndex
)
1293 EditView
* pEditView
= pEditEngine
->GetView( nIndex
);
1294 pEditView
->HideCursor(); // HACK
1296 pEditEngine
->RemoveView( nIndex
);
1299 ViewList::iterator it
= aViewList
.begin();
1300 advance( it
, nIndex
);
1301 aViewList
.erase( it
);
1306 OutlinerView
* Outliner::GetView( size_t nIndex
) const
1308 return ( nIndex
>= aViewList
.size() ) ? nullptr : aViewList
[ nIndex
];
1311 size_t Outliner::GetViewCount() const
1313 return aViewList
.size();
1316 void Outliner::ParagraphInsertedHdl(Paragraph
* pPara
)
1319 aParaInsertedHdl
.Call( { this, pPara
} );
1323 void Outliner::DepthChangedHdl(Paragraph
* pPara
, ParaFlag nPrevFlags
)
1326 aDepthChangedHdl
.Call( { this, pPara
, nPrevFlags
} );
1330 sal_Int32
Outliner::GetAbsPos( Paragraph
const * pPara
) const
1332 DBG_ASSERT(pPara
,"GetAbsPos:No Para");
1333 return pParaList
->GetAbsPos( pPara
);
1336 sal_Int32
Outliner::GetParagraphCount() const
1338 return pParaList
->GetParagraphCount();
1341 Paragraph
* Outliner::GetParagraph( sal_Int32 nAbsPos
) const
1343 return pParaList
->GetParagraph( nAbsPos
);
1346 bool Outliner::HasChildren( Paragraph
const * pParagraph
) const
1348 return pParaList
->HasChildren( pParagraph
);
1351 bool Outliner::ImplHasNumberFormat( sal_Int32 nPara
) const
1353 return GetNumberFormat(nPara
) != nullptr;
1356 const SvxNumberFormat
* Outliner::GetNumberFormat( sal_Int32 nPara
) const
1358 const SvxNumberFormat
* pFmt
= nullptr;
1360 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1364 sal_Int16 nDepth
= pPara
->GetDepth();
1368 const SvxNumBulletItem
& rNumBullet
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_NUMBULLET
);
1369 if ( rNumBullet
.GetNumRule().GetLevelCount() > nDepth
)
1370 pFmt
= rNumBullet
.GetNumRule().Get( nDepth
);
1376 Size
Outliner::ImplGetBulletSize( sal_Int32 nPara
)
1378 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1382 if( pPara
->aBulSize
.Width() == -1 )
1384 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
1385 DBG_ASSERT( pFmt
, "ImplGetBulletSize - no Bullet!" );
1387 if ( pFmt
->GetNumberingType() == SVX_NUM_NUMBER_NONE
)
1389 pPara
->aBulSize
= Size( 0, 0 );
1391 else if( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
)
1393 OUString aBulletText
= ImplGetBulletText( nPara
);
1394 OutputDevice
* pRefDev
= pEditEngine
->GetRefDevice();
1395 vcl::Font
aBulletFont( ImpCalcBulletFont( nPara
) );
1396 vcl::Font
aRefFont( pRefDev
->GetFont());
1397 pRefDev
->SetFont( aBulletFont
);
1398 pPara
->aBulSize
.setWidth( pRefDev
->GetTextWidth( aBulletText
) );
1399 pPara
->aBulSize
.setHeight( pRefDev
->GetTextHeight() );
1400 pRefDev
->SetFont( aRefFont
);
1404 pPara
->aBulSize
= OutputDevice::LogicToLogic(pFmt
->GetGraphicSize(),
1405 MapMode(MapUnit::Map100thMM
),
1406 pEditEngine
->GetRefDevice()->GetMapMode());
1410 return pPara
->aBulSize
;
1413 void Outliner::ImplCheckParagraphs( sal_Int32 nStart
, sal_Int32 nEnd
)
1416 for ( sal_Int32 n
= nStart
; n
< nEnd
; n
++ )
1418 Paragraph
* pPara
= pParaList
->GetParagraph( n
);
1421 pPara
->Invalidate();
1422 ImplCalcBulletText( n
, false, false );
1427 void Outliner::SetRefDevice( OutputDevice
* pRefDev
)
1429 pEditEngine
->SetRefDevice( pRefDev
);
1430 for ( sal_Int32 n
= pParaList
->GetParagraphCount(); n
; )
1432 Paragraph
* pPara
= pParaList
->GetParagraph( --n
);
1433 pPara
->Invalidate();
1437 void Outliner::ParaAttribsChanged( sal_Int32 nPara
)
1439 // The Outliner does not have an undo of its own, when paragraphs are
1440 // separated/merged. When ParagraphInserted the attribute EE_PARA_OUTLLEVEL
1441 // may not be set, this is however needed when the depth of the paragraph
1442 // is to be determined.
1443 if (!pEditEngine
->IsInUndo())
1445 if (pParaList
->GetParagraphCount() != pEditEngine
->GetParagraphCount())
1447 Paragraph
* pPara
= pParaList
->GetParagraph(nPara
);
1450 // tdf#100734: force update of bullet
1451 pPara
->Invalidate();
1452 const SfxInt16Item
& rLevel
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_OUTLLEVEL
);
1453 if (pPara
->GetDepth() == rLevel
.GetValue())
1455 pPara
->SetDepth(rLevel
.GetValue());
1456 ImplCalcBulletText(nPara
, true, true);
1459 void Outliner::StyleSheetChanged( SfxStyleSheet
const * pStyle
)
1462 // The EditEngine calls StyleSheetChanged also for derived styles.
1463 // Here all the paragraphs, which had the said template, used to be
1464 // hunted by an ImpRecalcParaAttribs, why?
1465 // => only the Bullet-representation can really change...
1466 sal_Int32 nParas
= pParaList
->GetParagraphCount();
1467 for( sal_Int32 nPara
= 0; nPara
< nParas
; nPara
++ )
1469 if ( pEditEngine
->GetStyleSheet( nPara
) == pStyle
)
1471 ImplCheckNumBulletItem( nPara
);
1472 ImplCalcBulletText( nPara
, false, false );
1473 // EditEngine formats changed paragraphs before calling this method,
1474 // so they are not reformatted now and use wrong bullet indent
1475 pEditEngine
->QuickMarkInvalid( ESelection( nPara
, 0, nPara
, 0 ) );
1480 tools::Rectangle
Outliner::ImpCalcBulletArea( sal_Int32 nPara
, bool bAdjust
, bool bReturnPaperPos
)
1482 // Bullet area within the paragraph ...
1483 tools::Rectangle aBulletArea
;
1485 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
1489 Size
aBulletSize( ImplGetBulletSize( nPara
) );
1491 bool bOutlineMode
= bool( pEditEngine
->GetControlWord() & EEControlBits::OUTLINER
);
1493 // the ODF attribute text:space-before which holds the spacing to add to the left of the label
1494 const auto nSpaceBefore
= pFmt
->GetAbsLSpace() + pFmt
->GetFirstLineOffset();
1496 const SvxLRSpaceItem
& rLR
= pEditEngine
->GetParaAttrib( nPara
, bOutlineMode
? EE_PARA_OUTLLRSPACE
: EE_PARA_LRSPACE
);
1497 aTopLeft
.setX( rLR
.GetTextLeft() + rLR
.GetTextFirstLineOffset() + nSpaceBefore
);
1499 tools::Long nBulletWidth
= std::max( static_cast<tools::Long
>(-rLR
.GetTextFirstLineOffset()), static_cast<tools::Long
>((-pFmt
->GetFirstLineOffset()) + pFmt
->GetCharTextDistance()) );
1500 if ( nBulletWidth
< aBulletSize
.Width() ) // The Bullet creates its space
1501 nBulletWidth
= aBulletSize
.Width();
1503 if ( bAdjust
&& !bOutlineMode
)
1505 // Adjust when centered or align right
1506 const SvxAdjustItem
& rItem
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_JUST
);
1507 if ( ( !pEditEngine
->IsRightToLeft( nPara
) && ( rItem
.GetAdjust() != SvxAdjust::Left
) ) ||
1508 ( pEditEngine
->IsRightToLeft( nPara
) && ( rItem
.GetAdjust() != SvxAdjust::Right
) ) )
1510 aTopLeft
.setX( pEditEngine
->GetFirstLineStartX( nPara
) - nBulletWidth
);
1515 ParagraphInfos aInfos
= pEditEngine
->GetParagraphInfos( nPara
);
1516 if ( aInfos
.bValid
)
1518 aTopLeft
.setY( /* aInfos.nFirstLineOffset + */ // nFirstLineOffset is already added to the StartPos (PaintBullet) from the EditEngine
1519 aInfos
.nFirstLineHeight
- aInfos
.nFirstLineTextHeight
1520 + aInfos
.nFirstLineTextHeight
/ 2
1521 - aBulletSize
.Height() / 2 );
1522 // may prefer to print out on the baseline ...
1523 if( ( pFmt
->GetNumberingType() != SVX_NUM_NUMBER_NONE
) && ( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
) && ( pFmt
->GetNumberingType() != SVX_NUM_CHAR_SPECIAL
) )
1525 vcl::Font
aBulletFont( ImpCalcBulletFont( nPara
) );
1526 if ( aBulletFont
.GetCharSet() != RTL_TEXTENCODING_SYMBOL
)
1528 OutputDevice
* pRefDev
= pEditEngine
->GetRefDevice();
1529 vcl::Font aOldFont
= pRefDev
->GetFont();
1530 pRefDev
->SetFont( aBulletFont
);
1531 FontMetric
aMetric( pRefDev
->GetFontMetric() );
1532 // Leading on the first line ...
1533 aTopLeft
.setY( /* aInfos.nFirstLineOffset + */ aInfos
.nFirstLineMaxAscent
);
1534 aTopLeft
.AdjustY( -(aMetric
.GetAscent()) );
1535 pRefDev
->SetFont( aOldFont
);
1541 if( pFmt
->GetNumAdjust() == SvxAdjust::Right
)
1543 aTopLeft
.AdjustX(nBulletWidth
- aBulletSize
.Width() );
1545 else if( pFmt
->GetNumAdjust() == SvxAdjust::Center
)
1547 aTopLeft
.AdjustX(( nBulletWidth
- aBulletSize
.Width() ) / 2 );
1550 if ( aTopLeft
.X() < 0 ) // then push
1553 aBulletArea
= tools::Rectangle( aTopLeft
, aBulletSize
);
1555 if ( bReturnPaperPos
)
1557 Size
aBulletSize( aBulletArea
.GetSize() );
1558 Point
aBulletDocPos( aBulletArea
.TopLeft() );
1559 aBulletDocPos
.AdjustY(pEditEngine
->GetDocPosTopLeft( nPara
).Y() );
1560 Point
aBulletPos( aBulletDocPos
);
1564 aBulletPos
.setY( aBulletDocPos
.X() );
1565 aBulletPos
.setX( GetPaperSize().Width() - aBulletDocPos
.Y() );
1567 aBulletPos
.AdjustX( -(aBulletSize
.Height()) );
1568 Size
aSz( aBulletSize
);
1569 aBulletSize
.setWidth( aSz
.Height() );
1570 aBulletSize
.setHeight( aSz
.Width() );
1572 else if ( pEditEngine
->IsRightToLeft( nPara
) )
1574 aBulletPos
.setX( GetPaperSize().Width() - aBulletDocPos
.X() - aBulletSize
.Width() );
1577 aBulletArea
= tools::Rectangle( aBulletPos
, aBulletSize
);
1582 EBulletInfo
Outliner::GetBulletInfo( sal_Int32 nPara
)
1586 aInfo
.nParagraph
= nPara
;
1587 aInfo
.bVisible
= ImplHasNumberFormat( nPara
);
1589 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
1590 aInfo
.nType
= pFmt
? pFmt
->GetNumberingType() : 0;
1594 if( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
)
1596 aInfo
.aText
= ImplGetBulletText( nPara
);
1598 if( pFmt
->GetBulletFont() )
1599 aInfo
.aFont
= *pFmt
->GetBulletFont();
1603 if ( aInfo
.bVisible
)
1605 aInfo
.aBounds
= ImpCalcBulletArea( nPara
, true, true );
1611 OUString
Outliner::GetText( Paragraph
const * pParagraph
, sal_Int32 nCount
) const
1614 OUStringBuffer
aText(128);
1615 sal_Int32 nStartPara
= pParaList
->GetAbsPos( pParagraph
);
1616 for ( sal_Int32 n
= 0; n
< nCount
; n
++ )
1618 aText
.append(pEditEngine
->GetText( nStartPara
+ n
));
1619 if ( (n
+1) < nCount
)
1622 return aText
.makeStringAndClear();
1625 void Outliner::Remove( Paragraph
const * pPara
, sal_Int32 nParaCount
)
1628 sal_Int32 nPos
= pParaList
->GetAbsPos( pPara
);
1629 if( !nPos
&& ( nParaCount
>= pParaList
->GetParagraphCount() ) )
1635 for( sal_Int32 n
= 0; n
< nParaCount
; n
++ )
1636 pEditEngine
->RemoveParagraph( nPos
);
1640 void Outliner::StripPortions()
1642 bStrippingPortions
= true;
1643 pEditEngine
->StripPortions();
1644 bStrippingPortions
= false;
1647 void Outliner::DrawingText( const Point
& rStartPos
, const OUString
& rText
, sal_Int32 nTextStart
,
1648 sal_Int32 nTextLen
, std::span
<const sal_Int32
> pDXArray
,
1649 std::span
<const sal_Bool
> pKashidaArray
, const SvxFont
& rFont
,
1650 sal_Int32 nPara
, sal_uInt8 nRightToLeft
,
1651 const EEngineData::WrongSpellVector
* pWrongSpellVector
,
1652 const SvxFieldData
* pFieldData
,
1654 bool bEndOfParagraph
,
1656 const css::lang::Locale
* pLocale
,
1657 const Color
& rOverlineColor
,
1658 const Color
& rTextLineColor
)
1660 if(aDrawPortionHdl
.IsSet())
1662 DrawPortionInfo
aInfo( rStartPos
, rText
, nTextStart
, nTextLen
, rFont
, nPara
, pDXArray
, pKashidaArray
, pWrongSpellVector
,
1663 pFieldData
, pLocale
, rOverlineColor
, rTextLineColor
, nRightToLeft
, false, 0, bEndOfLine
, bEndOfParagraph
, bEndOfBullet
);
1665 aDrawPortionHdl
.Call( &aInfo
);
1669 void Outliner::DrawingTab( const Point
& rStartPos
, tools::Long nWidth
, const OUString
& rChar
, const SvxFont
& rFont
,
1670 sal_Int32 nPara
, sal_uInt8 nRightToLeft
, bool bEndOfLine
, bool bEndOfParagraph
,
1671 const Color
& rOverlineColor
, const Color
& rTextLineColor
)
1673 if(aDrawPortionHdl
.IsSet())
1675 DrawPortionInfo
aInfo( rStartPos
, rChar
, 0, rChar
.getLength(), rFont
, nPara
, {}, {}, nullptr,
1676 nullptr, nullptr, rOverlineColor
, rTextLineColor
, nRightToLeft
, true, nWidth
, bEndOfLine
, bEndOfParagraph
, false);
1678 aDrawPortionHdl
.Call( &aInfo
);
1682 bool Outliner::RemovingPagesHdl( OutlinerView
* pView
)
1684 return !aRemovingPagesHdl
.IsSet() || aRemovingPagesHdl
.Call( pView
);
1687 bool Outliner::ImpCanDeleteSelectedPages( OutlinerView
* pCurView
, sal_Int32 _nFirstPage
, sal_Int32 nPages
)
1690 nDepthChangedHdlPrevDepth
= nPages
;
1691 mnFirstSelPage
= _nFirstPage
;
1692 return RemovingPagesHdl( pCurView
);
1695 SfxItemSet
const & Outliner::GetParaAttribs( sal_Int32 nPara
) const
1697 return pEditEngine
->GetParaAttribs( nPara
);
1700 IMPL_LINK( Outliner
, ParaVisibleStateChangedHdl
, Paragraph
&, rPara
, void )
1702 sal_Int32 nPara
= pParaList
->GetAbsPos( &rPara
);
1703 pEditEngine
->ShowParagraph( nPara
, rPara
.IsVisible() );
1706 IMPL_LINK_NOARG(Outliner
, BeginMovingParagraphsHdl
, MoveParagraphsInfo
&, void)
1709 aBeginMovingHdl
.Call( this );
1712 IMPL_LINK( Outliner
, BeginPasteOrDropHdl
, PasteOrDropInfos
&, rInfos
, void )
1714 UndoActionStart( EDITUNDO_DRAGANDDROP
);
1715 maBeginPasteOrDropHdl
.Call(&rInfos
);
1718 IMPL_LINK( Outliner
, EndPasteOrDropHdl
, PasteOrDropInfos
&, rInfos
, void )
1721 ImpTextPasted( rInfos
.nStartPara
, rInfos
.nEndPara
- rInfos
.nStartPara
+ 1 );
1722 maEndPasteOrDropHdl
.Call( &rInfos
);
1726 IMPL_LINK( Outliner
, EndMovingParagraphsHdl
, MoveParagraphsInfo
&, rInfos
, void )
1728 pParaList
->MoveParagraphs( rInfos
.nStartPara
, rInfos
.nDestPara
, rInfos
.nEndPara
- rInfos
.nStartPara
+ 1 );
1729 sal_Int32 nChangesStart
= std::min( rInfos
.nStartPara
, rInfos
.nDestPara
);
1730 sal_Int32 nParas
= pParaList
->GetParagraphCount();
1731 for ( sal_Int32 n
= nChangesStart
; n
< nParas
; n
++ )
1732 ImplCalcBulletText( n
, false, false );
1735 aEndMovingHdl
.Call( this );
1738 static bool isSameNumbering( const SvxNumberFormat
& rN1
, const SvxNumberFormat
& rN2
)
1740 if( rN1
.GetNumberingType() != rN2
.GetNumberingType() )
1743 if( rN1
.GetNumStr(1) != rN2
.GetNumStr(1) )
1746 if( (rN1
.GetPrefix() != rN2
.GetPrefix()) || (rN1
.GetSuffix() != rN2
.GetSuffix()) )
1752 sal_uInt16
Outliner::ImplGetNumbering( sal_Int32 nPara
, const SvxNumberFormat
* pParaFmt
)
1754 sal_uInt16 nNumber
= pParaFmt
->GetStart() - 1;
1756 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1757 const sal_Int16 nParaDepth
= pPara
->GetDepth();
1761 pPara
= pParaList
->GetParagraph( nPara
);
1762 const sal_Int16 nDepth
= pPara
->GetDepth();
1764 // ignore paragraphs that are below our paragraph or have no numbering
1765 if( (nDepth
> nParaDepth
) || (nDepth
== -1) )
1768 // stop on paragraphs that are above our paragraph
1769 if( nDepth
< nParaDepth
)
1772 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
1774 if( pFmt
== nullptr )
1775 continue; // ignore paragraphs without bullets
1777 // check if numbering less than or equal to pParaFmt
1778 if( !isSameNumbering( *pFmt
, *pParaFmt
) || ( pFmt
->GetStart() < pParaFmt
->GetStart() ) )
1781 if ( pFmt
->GetStart() > pParaFmt
->GetStart() )
1783 nNumber
+= pFmt
->GetStart() - pParaFmt
->GetStart();
1787 const SfxBoolItem
& rBulletState
= pEditEngine
->GetParaAttrib( nPara
, EE_PARA_BULLETSTATE
);
1789 if( rBulletState
.GetValue() )
1792 // same depth, same number format, check for restart
1793 const sal_Int16 nNumberingStartValue
= pPara
->GetNumberingStartValue();
1794 if( (nNumberingStartValue
!= -1) || pPara
->IsParaIsNumberingRestart() )
1796 if( nNumberingStartValue
!= -1 )
1797 nNumber
+= nNumberingStartValue
- 1;
1806 void Outliner::ImplCalcBulletText( sal_Int32 nPara
, bool bRecalcLevel
, bool bRecalcChildren
)
1809 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1813 OUString aBulletText
;
1814 const SvxNumberFormat
* pFmt
= GetNumberFormat( nPara
);
1815 if( pFmt
&& ( pFmt
->GetNumberingType() != SVX_NUM_BITMAP
) )
1817 aBulletText
+= pFmt
->GetPrefix();
1818 if( pFmt
->GetNumberingType() == SVX_NUM_CHAR_SPECIAL
)
1820 sal_UCS4 cChar
= pFmt
->GetBulletChar();
1821 aBulletText
+= OUString(&cChar
, 1);
1823 else if( pFmt
->GetNumberingType() != SVX_NUM_NUMBER_NONE
)
1825 aBulletText
+= pFmt
->GetNumStr( ImplGetNumbering( nPara
, pFmt
) );
1827 aBulletText
+= pFmt
->GetSuffix();
1830 if (pPara
->GetText() != aBulletText
)
1831 pPara
->SetText( aBulletText
);
1835 sal_Int16 nDepth
= pPara
->GetDepth();
1836 pPara
= pParaList
->GetParagraph( ++nPara
);
1837 if ( !bRecalcChildren
)
1839 while ( pPara
&& ( pPara
->GetDepth() > nDepth
) )
1840 pPara
= pParaList
->GetParagraph( ++nPara
);
1843 if ( pPara
&& ( pPara
->GetDepth() < nDepth
) )
1853 void Outliner::Clear()
1856 if( !bFirstParaIsEmpty
)
1858 ImplBlockInsertionCallbacks( true );
1859 pEditEngine
->Clear();
1861 pParaList
->Append( std::unique_ptr
<Paragraph
>(new Paragraph( gnMinDepth
)));
1862 bFirstParaIsEmpty
= true;
1863 ImplBlockInsertionCallbacks( false );
1867 Paragraph
* pPara
= pParaList
->GetParagraph( 0 );
1869 pPara
->SetDepth( gnMinDepth
);
1873 void Outliner::SetFlatMode( bool bFlat
)
1876 if( bFlat
!= pEditEngine
->IsFlatMode() )
1878 for ( sal_Int32 nPara
= pParaList
->GetParagraphCount(); nPara
; )
1879 pParaList
->GetParagraph( --nPara
)->aBulSize
.setWidth( -1 );
1881 pEditEngine
->SetFlatMode( bFlat
);
1885 OUString
Outliner::ImplGetBulletText( sal_Int32 nPara
)
1888 Paragraph
* pPara
= pParaList
->GetParagraph( nPara
);
1891 ImplCalcBulletText( nPara
, false, false );
1892 aRes
= pPara
->GetText();
1897 // this is needed for StarOffice Api
1898 void Outliner::SetLevelDependentStyleSheet( sal_Int32 nPara
)
1900 SfxItemSet
aOldAttrs( pEditEngine
->GetParaAttribs( nPara
) );
1901 ImplSetLevelDependentStyleSheet( nPara
);
1902 pEditEngine
->SetParaAttribs( nPara
, aOldAttrs
);
1905 void Outliner::ImplBlockInsertionCallbacks( bool b
)
1909 nBlockInsCallback
++;
1913 DBG_ASSERT( nBlockInsCallback
, "ImplBlockInsertionCallbacks ?!" );
1914 nBlockInsCallback
--;
1915 if ( !nBlockInsCallback
)
1917 // Call blocked notify events...
1918 while(!pEditEngine
->aNotifyCache
.empty())
1920 EENotify
aNotify(pEditEngine
->aNotifyCache
.front());
1921 // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler...
1922 pEditEngine
->aNotifyCache
.erase(pEditEngine
->aNotifyCache
.begin());
1923 pEditEngine
->aOutlinerNotifyHdl
.Call( aNotify
);
1929 IMPL_LINK( Outliner
, EditEngineNotifyHdl
, EENotify
&, rNotify
, void )
1931 if ( !nBlockInsCallback
)
1932 pEditEngine
->aOutlinerNotifyHdl
.Call( rNotify
);
1934 pEditEngine
->aNotifyCache
.push_back(rNotify
);
1937 /** sets a link that is called at the beginning of a drag operation at an edit view */
1938 void Outliner::SetBeginDropHdl( const Link
<EditView
*,void>& rLink
)
1940 pEditEngine
->SetBeginDropHdl( rLink
);
1943 /** sets a link that is called at the end of a drag operation at an edit view */
1944 void Outliner::SetEndDropHdl( const Link
<EditView
*,void>& rLink
)
1946 pEditEngine
->SetEndDropHdl( rLink
);
1949 /** sets a link that is called before a drop or paste operation. */
1950 void Outliner::SetBeginPasteOrDropHdl( const Link
<PasteOrDropInfos
*,void>& rLink
)
1952 maBeginPasteOrDropHdl
= rLink
;
1955 /** sets a link that is called after a drop or paste operation. */
1956 void Outliner::SetEndPasteOrDropHdl( const Link
<PasteOrDropInfos
*,void>& rLink
)
1958 maEndPasteOrDropHdl
= rLink
;
1961 void Outliner::SetParaFlag( Paragraph
* pPara
, ParaFlag nFlag
)
1963 if( pPara
&& !pPara
->HasFlag( nFlag
) )
1965 if( IsUndoEnabled() && !IsInUndo() )
1966 InsertUndo( std::make_unique
<OutlinerUndoChangeParaFlags
>( this, GetAbsPos( pPara
), pPara
->nFlags
, pPara
->nFlags
|nFlag
) );
1968 pPara
->SetFlag( nFlag
);
1972 bool Outliner::HasParaFlag( const Paragraph
* pPara
, ParaFlag nFlag
)
1974 return pPara
&& pPara
->HasFlag( nFlag
);
1978 bool Outliner::IsPageOverflow()
1980 return pEditEngine
->IsPageOverflow();
1983 std::optional
<NonOverflowingText
> Outliner::GetNonOverflowingText() const
1986 * nCount should be the number of paragraphs of the non overflowing text
1987 * nStart should be the starting paragraph of the non overflowing text (XXX: Always 0?)
1990 if ( GetParagraphCount() < 1 )
1993 // last non-overflowing paragraph is before the first overflowing one
1994 sal_Int32 nCount
= pEditEngine
->GetOverflowingParaNum();
1995 sal_Int32 nOverflowLine
= pEditEngine
->GetOverflowingLineNum(); // XXX: Unused for now
1997 // Defensive check: overflowing para index beyond actual # of paragraphs?
1998 if ( nCount
> GetParagraphCount()-1) {
1999 SAL_INFO("editeng.chaining",
2000 "[Overflowing] Ops, trying to retrieve para "
2001 << nCount
<< " when max index is " << GetParagraphCount()-1 );
2007 SAL_INFO("editeng.chaining",
2008 "[Overflowing] No Overflowing text but GetNonOverflowinText called?!");
2012 // NOTE: We want the selection of the overflowing text from here
2013 // At the same time we may want to consider the beginning of such text
2014 // in a more fine grained way (i.e. as GetNonOverflowingText did)
2017 sal_Int32 nHeadPara = pEditEngine->GetOverflowingParaNum();
2018 sal_uInt32 nParaCount = GetParagraphCount();
2020 sal_uInt32 nLen = 0;
2021 for ( sal_Int32 nLine = 0;
2022 nLine < pEditEngine->GetOverflowingLineNum();
2024 nLen += GetLineLen(nHeadPara, nLine);
2027 sal_uInt32 nOverflowingPara = pEditEngine->GetOverflowingParaNum();
2028 ESelection aOverflowingTextSel;
2029 sal_Int32 nLastPara = nParaCount-1;
2030 sal_Int32 nLastParaLen = GetText(GetParagraph(nLastPara)).getLength();
2031 aOverflowingTextSel = ESelection(nOverflowingPara, nLen,
2032 nLastPara, nLastParaLen);
2033 bool bLastParaInterrupted =
2034 pEditEngine->GetOverflowingLineNum() > 0;
2036 return new NonOverflowingText(aOverflowingTextSel, bLastParaInterrupted);
2040 // Only overflowing text, i.e. 1st line of 1st paragraph overflowing
2041 bool bItAllOverflew
= nCount
== 0 && nOverflowLine
== 0;
2042 if ( bItAllOverflew
)
2044 ESelection
aEmptySel(0,0,0,0);
2045 //EditTextObject *pTObj = pEditEngine->CreateTextObject(aEmptySel);
2046 bool const bLastParaInterrupted
= true; // Last Para was interrupted since everything overflew
2047 return NonOverflowingText(aEmptySel
, bLastParaInterrupted
);
2048 } else { // Get the lines that of the overflowing para fit in the box
2050 sal_Int32 nOverflowingPara
= nCount
;
2051 sal_uInt32 nLen
= 0;
2053 for ( sal_Int32 nLine
= 0;
2054 nLine
< pEditEngine
->GetOverflowingLineNum();
2057 nLen
+= GetLineLen(nOverflowingPara
, nLine
);
2060 //sal_Int32 nStartPara = 0;
2061 //sal_Int32 nStartPos = 0;
2062 ESelection aOverflowingTextSelection
;
2064 const sal_Int32 nEndPara
= GetParagraphCount()-1;
2065 const sal_Int32 nEndPos
= pEditEngine
->GetTextLen(nEndPara
);
2068 // XXX: What happens inside this case might be dependent on the joining paragraph or not-thingy
2069 // Overflowing paragraph is empty or first line overflowing: it's not "Non-Overflowing" text then
2070 sal_Int32 nParaLen
= GetText(GetParagraph(nOverflowingPara
-1)).getLength();
2071 aOverflowingTextSelection
=
2072 ESelection(nOverflowingPara
-1, nParaLen
, nEndPara
, nEndPos
);
2074 // We take until we have to from the overflowing paragraph
2075 aOverflowingTextSelection
=
2076 ESelection(nOverflowingPara
, nLen
, nEndPara
, nEndPos
);
2078 //EditTextObject *pTObj = pEditEngine->CreateTextObject(aNonOverflowingTextSelection);
2080 //sal_Int32 nLastLine = GetLineCount(nOverflowingPara)-1;
2081 bool bLastParaInterrupted
=
2082 pEditEngine
->GetOverflowingLineNum() > 0;
2084 return NonOverflowingText(aOverflowingTextSelection
, bLastParaInterrupted
);
2088 OutlinerParaObject
Outliner::GetEmptyParaObject() const
2090 std::unique_ptr
<EditTextObject
> pEmptyText
= pEditEngine
->GetEmptyTextObject();
2091 OutlinerParaObject
aPObj( std::move(pEmptyText
) );
2092 aPObj
.SetOutlinerMode(GetOutlinerMode());
2096 std::optional
<OverflowingText
> Outliner::GetOverflowingText() const
2098 if ( pEditEngine
->GetOverflowingParaNum() < 0)
2102 // Defensive check: overflowing para index beyond actual # of paragraphs?
2103 if ( pEditEngine
->GetOverflowingParaNum() > GetParagraphCount()-1) {
2104 SAL_INFO("editeng.chaining",
2105 "[Overflowing] Ops, trying to retrieve para "
2106 << pEditEngine
->GetOverflowingParaNum() << " when max index is "
2107 << GetParagraphCount()-1 );
2111 sal_Int32 nHeadPara
= pEditEngine
->GetOverflowingParaNum();
2112 sal_uInt32 nParaCount
= GetParagraphCount();
2114 sal_uInt32 nLen
= 0;
2115 for ( sal_Int32 nLine
= 0;
2116 nLine
< pEditEngine
->GetOverflowingLineNum();
2118 nLen
+= GetLineLen(nHeadPara
, nLine
);
2121 sal_uInt32 nOverflowingPara
= pEditEngine
->GetOverflowingParaNum();
2122 ESelection aOverflowingTextSel
;
2123 sal_Int32 nLastPara
= nParaCount
-1;
2124 sal_Int32 nLastParaLen
= GetText(GetParagraph(nLastPara
)).getLength();
2125 aOverflowingTextSel
= ESelection(nOverflowingPara
, nLen
,
2126 nLastPara
, nLastParaLen
);
2127 return OverflowingText(pEditEngine
->CreateTransferable(aOverflowingTextSel
));
2131 void Outliner::ClearOverflowingParaNum()
2133 pEditEngine
->ClearOverflowingParaNum();
2136 void Outliner::dumpAsXml(xmlTextWriterPtr pWriter
) const
2141 pWriter
= xmlNewTextWriterFilename("outliner.xml", 0);
2142 xmlTextWriterSetIndent(pWriter
,1);
2143 (void)xmlTextWriterSetIndentString(pWriter
, BAD_CAST(" "));
2144 (void)xmlTextWriterStartDocument(pWriter
, nullptr, nullptr, nullptr);
2148 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("Outliner"));
2149 pParaList
->dumpAsXml(pWriter
);
2150 (void)xmlTextWriterEndElement(pWriter
);
2154 (void)xmlTextWriterEndDocument(pWriter
);
2155 xmlFreeTextWriter(pWriter
);
2159 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */