xref: /core/editeng/source/outliner/outlvw.cxx (revision ead19f4c)
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 #include <memory>
21 #include <com/sun/star/i18n/WordType.hpp>
22 
23 #include <svl/itempool.hxx>
24 #include <editeng/editeng.hxx>
25 #include <editeng/editview.hxx>
26 #include <editeng/editdata.hxx>
27 
28 #include <svl/style.hxx>
29 #include <svl/languageoptions.hxx>
30 #include <i18nlangtag/languagetag.hxx>
31 
32 #include <editeng/outliner.hxx>
33 #include <outleeng.hxx>
34 #include "paralist.hxx"
35 #include "outlundo.hxx"
36 #include <editeng/outlobj.hxx>
37 #include <editeng/flditem.hxx>
38 #include <editeng/eeitem.hxx>
39 #include <editeng/numitem.hxx>
40 #include <vcl/window.hxx>
41 #include <vcl/event.hxx>
42 #include <vcl/ptrstyle.hxx>
43 #include <svl/itemset.hxx>
44 #include <svl/eitem.hxx>
45 #include <editeng/editstat.hxx>
46 #include <sal/log.hxx>
47 #include <osl/diagnose.h>
48 #include <tools/debug.hxx>
49 
50 using namespace ::com::sun::star;
51 
52 
OutlinerView(Outliner * pOut,vcl::Window * pWin)53 OutlinerView::OutlinerView( Outliner* pOut, vcl::Window* pWin )
54 {
55     pOwner                      = pOut;
56     pEditView.reset( new EditView( pOut->pEditEngine.get(), pWin ) );
57 }
58 
~OutlinerView()59 OutlinerView::~OutlinerView()
60 {
61 }
62 
Paint(const tools::Rectangle & rRect,OutputDevice * pTargetDevice)63 void OutlinerView::Paint( const tools::Rectangle& rRect, OutputDevice* pTargetDevice )
64 {
65     // For the first Paint/KeyInput/Drop an empty Outliner is turned into
66     // an Outliner with exactly one paragraph.
67     if( pOwner->bFirstParaIsEmpty )
68         pOwner->Insert( OUString() );
69 
70     pEditView->Paint( rRect, pTargetDevice );
71 }
72 
PostKeyEvent(const KeyEvent & rKEvt,vcl::Window const * pFrameWin)73 bool OutlinerView::PostKeyEvent( const KeyEvent& rKEvt, vcl::Window const * pFrameWin )
74 {
75     // For the first Paint/KeyInput/Drop an empty Outliner is turned into
76     // an Outliner with exactly one paragraph.
77     if( pOwner->bFirstParaIsEmpty )
78         pOwner->Insert( OUString() );
79 
80     bool bKeyProcessed = false;
81     ESelection aSel( pEditView->GetSelection() );
82     bool bSelection = aSel.HasRange();
83     vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
84     KeyFuncType eFunc = aKeyCode.GetFunction();
85     sal_uInt16 nCode = aKeyCode.GetCode();
86     bool bReadOnly = IsReadOnly();
87 
88     if( bSelection && ( nCode != KEY_TAB ) && EditEngine::DoesKeyChangeText( rKEvt ) )
89     {
90         if ( ImpCalcSelectedPages( false ) && !pOwner->ImpCanDeleteSelectedPages( this ) )
91             return true;
92     }
93 
94     if ( eFunc != KeyFuncType::DONTKNOW )
95     {
96         switch ( eFunc )
97         {
98             case KeyFuncType::CUT:
99             {
100                 if ( !bReadOnly )
101                 {
102                     Cut();
103                     bKeyProcessed = true;
104                 }
105             }
106             break;
107             case KeyFuncType::COPY:
108             {
109                 Copy();
110                 bKeyProcessed = true;
111             }
112             break;
113             case KeyFuncType::PASTE:
114             {
115                 if ( !bReadOnly )
116                 {
117                     PasteSpecial();
118                     bKeyProcessed = true;
119                 }
120             }
121             break;
122             case KeyFuncType::DELETE:
123             {
124                 if( !bReadOnly && !bSelection && ( pOwner->GetOutlinerMode() != OutlinerMode::TextObject ) )
125                 {
126                     if( aSel.nEndPos == pOwner->pEditEngine->GetTextLen( aSel.nEndPara ) )
127                     {
128                         Paragraph* pNext = pOwner->pParaList->GetParagraph( aSel.nEndPara+1 );
129                         if( pNext && pNext->HasFlag(ParaFlag::ISPAGE) )
130                         {
131                             if( !pOwner->ImpCanDeleteSelectedPages( this, aSel.nEndPara, 1 ) )
132                                 return false;
133                         }
134                     }
135                 }
136             }
137             break;
138             default:    // is then possibly edited below.
139                         eFunc = KeyFuncType::DONTKNOW;
140         }
141     }
142     if ( eFunc == KeyFuncType::DONTKNOW )
143     {
144         switch ( nCode )
145         {
146             case KEY_TAB:
147             {
148                 if ( !bReadOnly && !aKeyCode.IsMod1() && !aKeyCode.IsMod2() )
149                 {
150                     if ( ( pOwner->GetOutlinerMode() != OutlinerMode::TextObject ) &&
151                          ( pOwner->GetOutlinerMode() != OutlinerMode::TitleObject ) &&
152                          ( bSelection || !aSel.nStartPos ) )
153                     {
154                         Indent( aKeyCode.IsShift() ? -1 : +1 );
155                         bKeyProcessed = true;
156                     }
157                     else if ( ( pOwner->GetOutlinerMode() == OutlinerMode::TextObject ) &&
158                               !bSelection && !aSel.nEndPos && pOwner->ImplHasNumberFormat( aSel.nEndPara ) )
159                     {
160                         Indent( aKeyCode.IsShift() ? -1 : +1 );
161                         bKeyProcessed = true;
162                     }
163                 }
164             }
165             break;
166             case KEY_BACKSPACE:
167             {
168                 if( !bReadOnly && !bSelection && aSel.nEndPara && !aSel.nEndPos )
169                 {
170                     Paragraph* pPara = pOwner->pParaList->GetParagraph( aSel.nEndPara );
171                     Paragraph* pPrev = pOwner->pParaList->GetParagraph( aSel.nEndPara-1 );
172                     if( !pPrev->IsVisible()  )
173                         return true;
174                     if( !pPara->GetDepth() )
175                     {
176                         if(!pOwner->ImpCanDeleteSelectedPages(this, aSel.nEndPara , 1 ) )
177                             return true;
178                     }
179                 }
180             }
181             break;
182             case KEY_RETURN:
183             {
184                 if ( !bReadOnly )
185                 {
186                     // Special treatment: hard return at the end of a paragraph,
187                     // which has collapsed subparagraphs.
188                     Paragraph* pPara = pOwner->pParaList->GetParagraph( aSel.nEndPara );
189 
190                     if( !aKeyCode.IsShift() )
191                     {
192                         // Don't let insert empty paragraph with numbering. Instead end numbering.
193                         if (pPara->GetDepth() > -1 &&
194                             pOwner->pEditEngine->GetTextLen( aSel.nEndPara ) == 0)
195                         {
196                             ToggleBullets();
197                             return true;
198                         }
199                         // ImpGetCursor again???
200                         if( !bSelection &&
201                                 aSel.nEndPos == pOwner->pEditEngine->GetTextLen( aSel.nEndPara ) )
202                         {
203                             sal_Int32 nChildren = pOwner->pParaList->GetChildCount(pPara);
204                             if( nChildren && !pOwner->pParaList->HasVisibleChildren(pPara))
205                             {
206                                 pOwner->UndoActionStart( OLUNDO_INSERT );
207                                 sal_Int32 nTemp = aSel.nEndPara;
208                                 nTemp += nChildren;
209                                 nTemp++; // insert above next Non-Child
210                                 SAL_WARN_IF( nTemp < 0, "editeng", "OutlinerView::PostKeyEvent - overflow");
211                                 if (nTemp >= 0)
212                                 {
213                                     pOwner->Insert( OUString(),nTemp,pPara->GetDepth());
214                                     // Position the cursor
215                                     ESelection aTmpSel(nTemp,0,nTemp,0);
216                                     pEditView->SetSelection( aTmpSel );
217                                 }
218                                 pEditView->ShowCursor();
219                                 pOwner->UndoActionEnd();
220                                 bKeyProcessed = true;
221                             }
222                         }
223                     }
224                     if( !bKeyProcessed && !bSelection &&
225                                 !aKeyCode.IsShift() && aKeyCode.IsMod1() &&
226                             ( aSel.nEndPos == pOwner->pEditEngine->GetTextLen(aSel.nEndPara) ) )
227                     {
228                         pOwner->UndoActionStart( OLUNDO_INSERT );
229                         sal_Int32 nTemp = aSel.nEndPara;
230                         nTemp++;
231                         pOwner->Insert( OUString(), nTemp, pPara->GetDepth()+1 );
232 
233                         // Position the cursor
234                         ESelection aTmpSel(nTemp,0,nTemp,0);
235                         pEditView->SetSelection( aTmpSel );
236                         pEditView->ShowCursor();
237                         pOwner->UndoActionEnd();
238                         bKeyProcessed = true;
239                     }
240                 }
241             }
242             break;
243         }
244     }
245 
246     return bKeyProcessed || pEditView->PostKeyEvent( rKEvt, pFrameWin );
247 }
248 
ImpCheckMousePos(const Point & rPosPix,MouseTarget & reTarget)249 sal_Int32 OutlinerView::ImpCheckMousePos(const Point& rPosPix, MouseTarget& reTarget)
250 {
251     sal_Int32 nPara = EE_PARA_NOT_FOUND;
252 
253     Point aMousePosWin = pEditView->GetOutputDevice().PixelToLogic( rPosPix );
254     if( !pEditView->GetOutputArea().Contains( aMousePosWin ) )
255     {
256         reTarget = MouseTarget::Outside;
257     }
258     else
259     {
260         reTarget = MouseTarget::Text;
261 
262         Point aPaperPos( aMousePosWin );
263         tools::Rectangle aOutArea = pEditView->GetOutputArea();
264         tools::Rectangle aVisArea = pEditView->GetVisArea();
265         aPaperPos.AdjustX( -(aOutArea.Left()) );
266         aPaperPos.AdjustX(aVisArea.Left() );
267         aPaperPos.AdjustY( -(aOutArea.Top()) );
268         aPaperPos.AdjustY(aVisArea.Top() );
269 
270         bool bBullet;
271         if ( pOwner->IsTextPos( aPaperPos, 0, &bBullet ) )
272         {
273             Point aDocPos = pOwner->GetDocPos( aPaperPos );
274             nPara = pOwner->pEditEngine->FindParagraph( aDocPos.Y() );
275 
276             if ( bBullet )
277             {
278                 reTarget = MouseTarget::Bullet;
279             }
280             else
281             {
282                 // Check for hyperlink
283                 const SvxFieldItem* pFieldItem = pEditView->GetField( aMousePosWin );
284                 if ( pFieldItem && pFieldItem->GetField() && dynamic_cast< const SvxURLField* >(pFieldItem->GetField()) != nullptr )
285                     reTarget = MouseTarget::Hypertext;
286             }
287         }
288     }
289     return nPara;
290 }
291 
MouseMove(const MouseEvent & rMEvt)292 bool OutlinerView::MouseMove( const MouseEvent& rMEvt )
293 {
294     if( ( pOwner->GetOutlinerMode() == OutlinerMode::TextObject ) || pEditView->getEditEngine().IsInSelectionMode())
295         return pEditView->MouseMove( rMEvt );
296 
297     Point aMousePosWin( pEditView->GetOutputDevice().PixelToLogic( rMEvt.GetPosPixel() ) );
298     if( !pEditView->GetOutputArea().Contains( aMousePosWin ) )
299         return false;
300 
301     PointerStyle aPointer = GetPointer( rMEvt.GetPosPixel() );
302     pEditView->GetWindow()->SetPointer( aPointer );
303     return pEditView->MouseMove( rMEvt );
304 }
305 
306 
MouseButtonDown(const MouseEvent & rMEvt)307 bool OutlinerView::MouseButtonDown( const MouseEvent& rMEvt )
308 {
309     if ( ( pOwner->GetOutlinerMode() == OutlinerMode::TextObject ) || pEditView->getEditEngine().IsInSelectionMode() )
310         return pEditView->MouseButtonDown( rMEvt );
311 
312     Point aMousePosWin( pEditView->GetOutputDevice().PixelToLogic( rMEvt.GetPosPixel() ) );
313     if( !pEditView->GetOutputArea().Contains( aMousePosWin ) )
314         return false;
315 
316     PointerStyle aPointer = GetPointer( rMEvt.GetPosPixel() );
317     pEditView->GetWindow()->SetPointer( aPointer );
318 
319     MouseTarget eTarget;
320     sal_Int32 nPara = ImpCheckMousePos( rMEvt.GetPosPixel(), eTarget );
321     if ( eTarget == MouseTarget::Bullet )
322     {
323         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
324         bool bHasChildren = (pPara && pOwner->pParaList->HasChildren(pPara));
325         if( rMEvt.GetClicks() == 1 )
326         {
327             sal_Int32 nEndPara = nPara;
328             if ( bHasChildren && pOwner->pParaList->HasVisibleChildren(pPara) )
329                 nEndPara += pOwner->pParaList->GetChildCount( pPara );
330             // The selection is inverted, so that EditEngine does not scroll
331             ESelection aSel(nEndPara, EE_TEXTPOS_ALL, nPara, 0 );
332             pEditView->SetSelection( aSel );
333         }
334         else if( rMEvt.GetClicks() == 2 && bHasChildren )
335             ImpToggleExpand( pPara );
336 
337         return true;
338     }
339 
340     // special case for outliner view in impress, check if double click hits the page icon for toggle
341     if( (nPara == EE_PARA_NOT_FOUND) && (pOwner->GetOutlinerMode() == OutlinerMode::OutlineView) && (eTarget == MouseTarget::Text) && (rMEvt.GetClicks() == 2) )
342     {
343         ESelection aSel( pEditView->GetSelection() );
344         nPara = aSel.nStartPara;
345         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
346         if( (pPara && pOwner->pParaList->HasChildren(pPara)) && pPara->HasFlag(ParaFlag::ISPAGE) )
347         {
348             ImpToggleExpand( pPara );
349         }
350     }
351     return pEditView->MouseButtonDown( rMEvt );
352 }
353 
354 
MouseButtonUp(const MouseEvent & rMEvt)355 bool OutlinerView::MouseButtonUp( const MouseEvent& rMEvt )
356 {
357     if ( ( pOwner->GetOutlinerMode() == OutlinerMode::TextObject ) || pEditView->getEditEngine().IsInSelectionMode() )
358         return pEditView->MouseButtonUp( rMEvt );
359 
360     Point aMousePosWin( pEditView->GetOutputDevice().PixelToLogic( rMEvt.GetPosPixel() ) );
361     if( !pEditView->GetOutputArea().Contains( aMousePosWin ) )
362         return false;
363 
364     PointerStyle aPointer = GetPointer( rMEvt.GetPosPixel() );
365     pEditView->GetWindow()->SetPointer( aPointer );
366 
367     return pEditView->MouseButtonUp( rMEvt );
368 }
369 
ReleaseMouse()370 void OutlinerView::ReleaseMouse()
371 {
372     pEditView->ReleaseMouse();
373 }
374 
ImpToggleExpand(Paragraph const * pPara)375 void OutlinerView::ImpToggleExpand( Paragraph const * pPara )
376 {
377     sal_Int32 nPara = pOwner->pParaList->GetAbsPos( pPara );
378     pEditView->SetSelection( ESelection( nPara, 0, nPara, 0 ) );
379     ImplExpandOrCollaps( nPara, nPara, !pOwner->pParaList->HasVisibleChildren( pPara ) );
380     pEditView->ShowCursor();
381 }
382 
Select(Paragraph const * pParagraph,bool bSelect)383 void OutlinerView::Select( Paragraph const * pParagraph, bool bSelect )
384 {
385     sal_Int32 nPara = pOwner->pParaList->GetAbsPos( pParagraph );
386     sal_Int32 nEnd = 0;
387     if ( bSelect )
388         nEnd = SAL_MAX_INT32;
389 
390     ESelection aSel( nPara, 0, nPara, nEnd );
391     pEditView->SetSelection( aSel );
392 }
393 
SetDepth(sal_Int32 nParagraph,sal_Int16 nDepth)394 void OutlinerView::SetDepth(sal_Int32 nParagraph, sal_Int16 nDepth)
395 {
396     Paragraph* pParagraph = pOwner->GetParagraph(nParagraph);
397     pOwner->SetDepth(pParagraph, nDepth);
398 }
399 
GetDepth() const400 sal_Int16 OutlinerView::GetDepth() const
401 {
402     ESelection aESelection = GetSelection();
403     aESelection.Adjust();
404     sal_Int16 nDepth = pOwner->GetDepth(aESelection.nStartPara);
405     for (sal_Int32 nPara = aESelection.nStartPara + 1; nPara <= aESelection.nEndPara; ++nPara)
406     {
407         if (nDepth != pOwner->GetDepth(nPara))
408             return -2;
409     }
410     return nDepth;
411 }
412 
SetAttribs(const SfxItemSet & rAttrs)413 void OutlinerView::SetAttribs( const SfxItemSet& rAttrs )
414 {
415     bool bUpdate = pOwner->pEditEngine->SetUpdateLayout( false );
416 
417     if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() )
418         pOwner->UndoActionStart( OLUNDO_ATTR );
419 
420     ParaRange aSel = ImpGetSelectedParagraphs( false );
421 
422     pEditView->SetAttribs( rAttrs );
423 
424     // Update Bullet text
425     for( sal_Int32 nPara= aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ )
426     {
427         pOwner->ImplCheckNumBulletItem( nPara );
428         pOwner->ImplCalcBulletText( nPara, false, false );
429 
430         if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() )
431             pOwner->InsertUndo( std::make_unique<OutlinerUndoCheckPara>( pOwner, nPara ) );
432     }
433 
434     if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() )
435         pOwner->UndoActionEnd();
436 
437     pEditView->SetEditEngineUpdateLayout( bUpdate );
438 }
439 
ImpGetSelectedParagraphs(bool bIncludeHiddenChildren)440 ParaRange OutlinerView::ImpGetSelectedParagraphs( bool bIncludeHiddenChildren )
441 {
442     ESelection aSel = pEditView->GetSelection();
443     ParaRange aParas( aSel.nStartPara, aSel.nEndPara );
444     aParas.Adjust();
445 
446     // Record the  invisible Children of the last Parents in the selection
447     if ( bIncludeHiddenChildren )
448     {
449         Paragraph* pLast = pOwner->pParaList->GetParagraph( aParas.nEndPara );
450         if ( pOwner->pParaList->HasHiddenChildren( pLast ) )
451             aParas.nEndPara = aParas.nEndPara + pOwner->pParaList->GetChildCount( pLast );
452     }
453     return aParas;
454 }
455 
456 // TODO: Name should be changed!
AdjustDepth(short nDX)457 void OutlinerView::AdjustDepth( short nDX )
458 {
459     Indent( nDX );
460 }
461 
Indent(short nDiff)462 void OutlinerView::Indent( short nDiff )
463 {
464     if( !nDiff || ( ( nDiff > 0 ) && ImpCalcSelectedPages( true ) && !pOwner->ImpCanIndentSelectedPages( this ) ) )
465         return;
466 
467     const bool bOutlinerView = bool(pOwner->pEditEngine->GetControlWord() & EEControlBits::OUTLINER);
468     bool bUpdate = pOwner->pEditEngine->SetUpdateLayout( false );
469 
470     bool bUndo = !pOwner->IsInUndo() && pOwner->IsUndoEnabled();
471 
472     if( bUndo )
473         pOwner->UndoActionStart( OLUNDO_DEPTH );
474 
475     sal_Int16 nMinDepth = -1;   // Optimization: avoid recalculate too many paragraphs if not really needed.
476 
477     ParaRange aSel = ImpGetSelectedParagraphs( true );
478     for ( sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ )
479     {
480         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
481 
482         sal_Int16 nOldDepth = pPara->GetDepth();
483         sal_Int16 nNewDepth = nOldDepth + nDiff;
484 
485         if( bOutlinerView && nPara )
486         {
487             const bool bPage = pPara->HasFlag(ParaFlag::ISPAGE);
488             if( (bPage && (nDiff == +1)) || (!bPage && (nDiff == -1) && (nOldDepth <= 0))  )
489             {
490                             // Notify App
491                 pOwner->nDepthChangedHdlPrevDepth = nOldDepth;
492                 ParaFlag nPrevFlags = pPara->nFlags;
493 
494                 if( bPage )
495                     pPara->RemoveFlag( ParaFlag::ISPAGE );
496                 else
497                     pPara->SetFlag( ParaFlag::ISPAGE );
498 
499                 pOwner->DepthChangedHdl(pPara, nPrevFlags);
500                 pOwner->pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) );
501 
502                 if( bUndo )
503                     pOwner->InsertUndo( std::make_unique<OutlinerUndoChangeParaFlags>( pOwner, nPara, nPrevFlags, pPara->nFlags ) );
504 
505                 continue;
506             }
507         }
508 
509         // do not switch off numeration with tab
510         if( (nOldDepth == 0) && (nNewDepth == -1) )
511             continue;
512 
513         // do not indent if there is no numeration enabled
514         if( nOldDepth == -1 )
515             continue;
516 
517         if ( nNewDepth < Outliner::gnMinDepth )
518             nNewDepth = Outliner::gnMinDepth;
519         if ( nNewDepth > pOwner->nMaxDepth )
520             nNewDepth = pOwner->nMaxDepth;
521 
522         if( nOldDepth < nMinDepth )
523             nMinDepth = nOldDepth;
524         if( nNewDepth < nMinDepth )
525             nMinDepth = nNewDepth;
526 
527         if( nOldDepth != nNewDepth )
528         {
529             if ( ( nPara == aSel.nStartPara ) && aSel.nStartPara && ( pOwner->GetOutlinerMode() != OutlinerMode::TextObject ))
530             {
531                 // Special case: the predecessor of an indented paragraph is
532                 // invisible and is now on the same level as the visible
533                 // paragraph. In this case, the next visible paragraph is
534                 // searched for and fluffed.
535 #ifdef DBG_UTIL
536                 Paragraph* _pPara = pOwner->pParaList->GetParagraph( aSel.nStartPara );
537                 DBG_ASSERT(_pPara->IsVisible(),"Selected Paragraph invisible ?!");
538 #endif
539                 Paragraph* pPrev= pOwner->pParaList->GetParagraph( aSel.nStartPara-1 );
540 
541                 if( !pPrev->IsVisible() && ( pPrev->GetDepth() == nNewDepth ) )
542                 {
543                     // Predecessor is collapsed and is on the same level
544                     // => find next visible paragraph and expand it
545                     pPrev = pOwner->pParaList->GetParent( pPrev );
546                     while( !pPrev->IsVisible() )
547                         pPrev = pOwner->pParaList->GetParent( pPrev );
548 
549                     pOwner->Expand( pPrev );
550                     pOwner->InvalidateBullet(pOwner->pParaList->GetAbsPos(pPrev));
551                 }
552             }
553 
554             pOwner->nDepthChangedHdlPrevDepth = nOldDepth;
555             ParaFlag nPrevFlags = pPara->nFlags;
556 
557             pOwner->ImplInitDepth( nPara, nNewDepth, true );
558             pOwner->ImplCalcBulletText( nPara, false, false );
559 
560             if ( pOwner->GetOutlinerMode() == OutlinerMode::OutlineObject )
561                 pOwner->ImplSetLevelDependentStyleSheet( nPara );
562 
563             // Notify App
564             pOwner->DepthChangedHdl(pPara, nPrevFlags);
565         }
566         else
567         {
568             // Needs at least a repaint...
569             pOwner->pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) );
570         }
571     }
572 
573     sal_Int32 nParas = pOwner->pParaList->GetParagraphCount();
574     for ( sal_Int32 n = aSel.nEndPara+1; n < nParas; n++ )
575     {
576         Paragraph* pPara = pOwner->pParaList->GetParagraph( n );
577         if ( pPara->GetDepth() < nMinDepth )
578             break;
579         pOwner->ImplCalcBulletText( n, false, false );
580     }
581 
582     if ( bUpdate )
583     {
584         pEditView->SetEditEngineUpdateLayout( true );
585         pEditView->ShowCursor();
586     }
587 
588     if( bUndo )
589         pOwner->UndoActionEnd();
590 }
591 
AdjustHeight(tools::Long nDY)592 void OutlinerView::AdjustHeight( tools::Long nDY )
593 {
594     pEditView->MoveParagraphs( nDY );
595 }
596 
GetVisArea() const597 tools::Rectangle OutlinerView::GetVisArea() const
598 {
599     return pEditView->GetVisArea();
600 }
601 
Expand()602 void OutlinerView::Expand()
603 {
604     ParaRange aParas = ImpGetSelectedParagraphs( false );
605     ImplExpandOrCollaps( aParas.nStartPara, aParas.nEndPara, true );
606 }
607 
608 
Collapse()609 void OutlinerView::Collapse()
610 {
611     ParaRange aParas = ImpGetSelectedParagraphs( false );
612     ImplExpandOrCollaps( aParas.nStartPara, aParas.nEndPara, false );
613 }
614 
615 
ExpandAll()616 void OutlinerView::ExpandAll()
617 {
618     ImplExpandOrCollaps( 0, pOwner->pParaList->GetParagraphCount()-1, true );
619 }
620 
621 
CollapseAll()622 void OutlinerView::CollapseAll()
623 {
624     ImplExpandOrCollaps( 0, pOwner->pParaList->GetParagraphCount()-1, false );
625 }
626 
ImplExpandOrCollaps(sal_Int32 nStartPara,sal_Int32 nEndPara,bool bExpand)627 void OutlinerView::ImplExpandOrCollaps( sal_Int32 nStartPara, sal_Int32 nEndPara, bool bExpand )
628 {
629     bool bUpdate = pOwner->SetUpdateLayout( false );
630 
631     bool bUndo = !pOwner->IsInUndo() && pOwner->IsUndoEnabled();
632     if( bUndo )
633         pOwner->UndoActionStart( bExpand ? OLUNDO_EXPAND : OLUNDO_COLLAPSE );
634 
635     for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
636     {
637         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
638         bool bDone = bExpand ? pOwner->Expand( pPara ) : pOwner->Collapse( pPara );
639         if( bDone )
640         {
641             // The line under the paragraph should disappear ...
642             pOwner->pEditEngine->QuickMarkToBeRepainted( nPara );
643         }
644     }
645 
646     if( bUndo )
647         pOwner->UndoActionEnd();
648 
649     if ( bUpdate )
650     {
651         pOwner->SetUpdateLayout( true );
652         pEditView->ShowCursor();
653     }
654 }
655 
InsertText(const OutlinerParaObject & rParaObj)656 void OutlinerView::InsertText( const OutlinerParaObject& rParaObj )
657 {
658     // Like Paste, only EditView::Insert, instead of EditView::Paste.
659     // Actually not quite true that possible indentations must be corrected,
660     // but that comes later by a universal import. The indentation level is
661     // then determined right in the Inserted method.
662     // Possible structure:
663     // pImportInfo with DestPara, DestPos, nFormat, pParaObj...
664     // Possibly problematic:
665     // EditEngine, RTF => Splitting the area, later join together.
666 
667     if ( ImpCalcSelectedPages( false ) && !pOwner->ImpCanDeleteSelectedPages( this ) )
668         return;
669 
670     pOwner->UndoActionStart( OLUNDO_INSERT );
671 
672     const bool bPrevUpdateLayout = pOwner->pEditEngine->SetUpdateLayout( false );
673     sal_Int32 nStart, nParaCount;
674     nParaCount = pOwner->pEditEngine->GetParagraphCount();
675     sal_uInt16 nSize = ImpInitPaste( nStart );
676     pEditView->InsertText( rParaObj.GetTextObject() );
677     ImpPasted( nStart, nParaCount, nSize);
678     pEditView->SetEditEngineUpdateLayout( bPrevUpdateLayout );
679 
680     pOwner->UndoActionEnd();
681 
682     pEditView->ShowCursor();
683 }
684 
685 
Cut()686 void OutlinerView::Cut()
687 {
688     if ( !ImpCalcSelectedPages( false ) || pOwner->ImpCanDeleteSelectedPages( this ) ) {
689         pEditView->Cut();
690         // Chaining handling
691         aEndCutPasteLink.Call(nullptr);
692     }
693 }
694 
PasteSpecial(SotClipboardFormatId format)695 void OutlinerView::PasteSpecial(SotClipboardFormatId format)
696 {
697     Paste( true, format );
698 }
699 
Paste(bool bUseSpecial,SotClipboardFormatId format)700 void OutlinerView::Paste( bool bUseSpecial, SotClipboardFormatId format)
701 {
702     if ( ImpCalcSelectedPages( false ) && !pOwner->ImpCanDeleteSelectedPages( this ) )
703         return;
704 
705     pOwner->UndoActionStart( OLUNDO_INSERT );
706 
707     const bool bPrevUpdateLayout = pOwner->pEditEngine->SetUpdateLayout( false );
708     pOwner->bPasting = true;
709 
710     if ( bUseSpecial )
711         pEditView->PasteSpecial(format);
712     else
713         pEditView->Paste();
714 
715     if ( pOwner->GetOutlinerMode() == OutlinerMode::OutlineObject )
716     {
717         const sal_Int32 nParaCount = pOwner->pEditEngine->GetParagraphCount();
718 
719         for( sal_Int32 nPara = 0; nPara < nParaCount; nPara++ )
720             pOwner->ImplSetLevelDependentStyleSheet( nPara );
721     }
722 
723     pEditView->SetEditEngineUpdateLayout( bPrevUpdateLayout );
724     pOwner->UndoActionEnd();
725     pEditView->ShowCursor();
726 
727     // Chaining handling
728     // NOTE: We need to do this last because it pEditView may be deleted if a switch of box occurs
729     aEndCutPasteLink.Call(nullptr);
730 }
731 
CreateSelectionList(std::vector<Paragraph * > & aSelList)732 void OutlinerView::CreateSelectionList (std::vector<Paragraph*> &aSelList)
733 {
734     ParaRange aParas = ImpGetSelectedParagraphs( true );
735 
736     for ( sal_Int32 nPara = aParas.nStartPara; nPara <= aParas.nEndPara; nPara++ )
737     {
738         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
739         aSelList.push_back(pPara);
740     }
741 }
742 
SetStyleSheet(const OUString & rStyleName)743 void OutlinerView::SetStyleSheet(const OUString& rStyleName)
744 {
745     ParaRange aParas = ImpGetSelectedParagraphs(false);
746 
747     auto pStyle = pOwner->GetStyleSheetPool()->Find(rStyleName, SfxStyleFamily::Para);
748     if (!pStyle)
749         return;
750 
751     for (sal_Int32 nPara = aParas.nStartPara; nPara <= aParas.nEndPara; nPara++)
752         pOwner->SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle));
753 }
754 
GetStyleSheet() const755 const SfxStyleSheet* OutlinerView::GetStyleSheet() const
756 {
757     return pEditView->GetStyleSheet();
758 }
759 
GetStyleSheet()760 SfxStyleSheet* OutlinerView::GetStyleSheet()
761 {
762     return pEditView->GetStyleSheet();
763 }
764 
GetPointer(const Point & rPosPixel)765 PointerStyle OutlinerView::GetPointer( const Point& rPosPixel )
766 {
767     MouseTarget eTarget;
768     ImpCheckMousePos( rPosPixel, eTarget );
769 
770     PointerStyle ePointerStyle = PointerStyle::Arrow;
771     if ( eTarget == MouseTarget::Text )
772     {
773         ePointerStyle = GetOutliner()->IsVertical() ? PointerStyle::TextVertical : PointerStyle::Text;
774     }
775     else if ( eTarget == MouseTarget::Hypertext )
776     {
777         ePointerStyle = PointerStyle::RefHand;
778     }
779     else if ( eTarget == MouseTarget::Bullet )
780     {
781         ePointerStyle = PointerStyle::Move;
782     }
783 
784     return ePointerStyle;
785 }
786 
787 
ImpInitPaste(sal_Int32 & rStart)788 sal_Int32 OutlinerView::ImpInitPaste( sal_Int32& rStart )
789 {
790     pOwner->bPasting = true;
791     ESelection aSelection( pEditView->GetSelection() );
792     aSelection.Adjust();
793     rStart = aSelection.nStartPara;
794     sal_Int32 nSize = aSelection.nEndPara - aSelection.nStartPara + 1;
795     return nSize;
796 }
797 
798 
ImpPasted(sal_Int32 nStart,sal_Int32 nPrevParaCount,sal_Int32 nSize)799 void OutlinerView::ImpPasted( sal_Int32 nStart, sal_Int32 nPrevParaCount, sal_Int32 nSize)
800 {
801     pOwner->bPasting = false;
802     sal_Int32 nCurParaCount = pOwner->pEditEngine->GetParagraphCount();
803     if( nCurParaCount < nPrevParaCount )
804         nSize = nSize - ( nPrevParaCount - nCurParaCount );
805     else
806         nSize = nSize + ( nCurParaCount - nPrevParaCount );
807     pOwner->ImpTextPasted( nStart, nSize );
808 }
809 
Command(const CommandEvent & rCEvt)810 bool OutlinerView::Command(const CommandEvent& rCEvt)
811 {
812     return pEditView->Command(rCEvt);
813 }
814 
SelectRange(sal_Int32 nFirst,sal_Int32 nCount)815 void OutlinerView::SelectRange( sal_Int32 nFirst, sal_Int32 nCount )
816 {
817     sal_Int32 nLast = nFirst+nCount;
818     nCount = pOwner->pParaList->GetParagraphCount();
819     if( nLast <= nCount )
820         nLast = nCount - 1;
821     ESelection aSel( nFirst, 0, nLast, EE_TEXTPOS_ALL );
822     pEditView->SetSelection( aSel );
823 }
824 
825 
ImpCalcSelectedPages(bool bIncludeFirstSelected)826 sal_Int32 OutlinerView::ImpCalcSelectedPages( bool bIncludeFirstSelected )
827 {
828     ESelection aSel( pEditView->GetSelection() );
829     aSel.Adjust();
830 
831     sal_Int32 nPages = 0;
832     sal_Int32 nFirstPage = EE_PARA_MAX_COUNT;
833     sal_Int32 nStartPara = aSel.nStartPara;
834     if ( !bIncludeFirstSelected )
835         nStartPara++;   // All paragraphs after StartPara will be deleted
836     for ( sal_Int32 nPara = nStartPara; nPara <= aSel.nEndPara; nPara++ )
837     {
838         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
839         assert(pPara && "ImpCalcSelectedPages: invalid Selection?");
840         if( pPara->HasFlag(ParaFlag::ISPAGE) )
841         {
842             nPages++;
843             if( nFirstPage == EE_PARA_MAX_COUNT )
844                 nFirstPage = nPara;
845         }
846     }
847 
848     if( nPages )
849     {
850         pOwner->nDepthChangedHdlPrevDepth = nPages;
851         pOwner->mnFirstSelPage = nFirstPage;
852     }
853 
854     return nPages;
855 }
856 
857 
ToggleBullets()858 void OutlinerView::ToggleBullets()
859 {
860     pOwner->UndoActionStart( OLUNDO_DEPTH );
861 
862     ESelection aSel( pEditView->GetSelection() );
863     aSel.Adjust();
864 
865     const bool bUpdate = pOwner->pEditEngine->SetUpdateLayout( false );
866 
867     sal_Int16 nNewDepth = -2;
868     const SvxNumRule* pDefaultBulletNumRule = nullptr;
869 
870     for ( sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ )
871     {
872         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
873         DBG_ASSERT(pPara, "OutlinerView::ToggleBullets(), illegal selection?");
874 
875         if( pPara )
876         {
877             if( nNewDepth == -2 )
878             {
879                 nNewDepth = (pOwner->GetDepth(nPara) == -1) ? 0 : -1;
880                 if ( nNewDepth == 0 )
881                 {
882                     // determine default numbering rule for bullets
883                     const ESelection aSelection(nPara, 0);
884                     const SfxItemSet aTmpSet(pOwner->pEditEngine->GetAttribs(aSelection));
885                     const SfxPoolItem& rPoolItem = aTmpSet.GetPool()->GetUserOrPoolDefaultItem( EE_PARA_NUMBULLET );
886                     const SvxNumBulletItem* pNumBulletItem = dynamic_cast< const SvxNumBulletItem* >(&rPoolItem);
887                     pDefaultBulletNumRule =  pNumBulletItem ? &pNumBulletItem->GetNumRule() : nullptr;
888                 }
889             }
890 
891             pOwner->SetDepth( pPara, nNewDepth );
892 
893             if( nNewDepth == -1 )
894             {
895                 const SfxItemSet& rAttrs = pOwner->GetParaAttribs( nPara );
896                 if ( rAttrs.GetItemState( EE_PARA_BULLETSTATE ) == SfxItemState::SET )
897                 {
898                     SfxItemSet aAttrs(rAttrs);
899                     aAttrs.ClearItem( EE_PARA_BULLETSTATE );
900                     pOwner->SetParaAttribs( nPara, aAttrs );
901                 }
902             }
903             else
904             {
905                 if ( pDefaultBulletNumRule )
906                 {
907                     const SvxNumberFormat* pFmt = pOwner ->GetNumberFormat( nPara );
908                     if ( !pFmt
909                          || ( pFmt->GetNumberingType() != SVX_NUM_BITMAP
910                               && pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) )
911                     {
912                         SfxItemSet aAttrs( pOwner->GetParaAttribs( nPara ) );
913                         SvxNumRule aNewNumRule( *pDefaultBulletNumRule );
914                         aAttrs.Put( SvxNumBulletItem( std::move(aNewNumRule), EE_PARA_NUMBULLET ) );
915                         pOwner->SetParaAttribs( nPara, aAttrs );
916                     }
917                 }
918             }
919         }
920     }
921 
922     const sal_Int32 nParaCount = pOwner->pParaList->GetParagraphCount();
923     pOwner->ImplCheckParagraphs( aSel.nStartPara, nParaCount );
924 
925     sal_Int32 nEndPara = (nParaCount > 0) ? nParaCount-1 : nParaCount;
926     pOwner->pEditEngine->QuickMarkInvalid( ESelection( aSel.nStartPara, 0, nEndPara, 0 ) );
927 
928     pOwner->pEditEngine->SetUpdateLayout( bUpdate );
929 
930     pOwner->UndoActionEnd();
931 }
932 
933 
ToggleBulletsNumbering(const bool bToggle,const bool bHandleBullets,const SvxNumRule * pNumRule)934 void OutlinerView::ToggleBulletsNumbering(
935     const bool bToggle,
936     const bool bHandleBullets,
937     const SvxNumRule* pNumRule )
938 {
939     ESelection aSel( pEditView->GetSelection() );
940     aSel.Adjust();
941 
942     bool bToggleOn = true;
943     if ( bToggle )
944     {
945         bToggleOn = false;
946         const sal_Int16 nBulletNumberingStatus( pOwner->GetBulletsNumberingStatus( aSel.nStartPara, aSel.nEndPara ) );
947         if ( nBulletNumberingStatus != 0 && bHandleBullets )
948         {
949             // not all paragraphs have bullets and method called to toggle bullets --> bullets on
950             bToggleOn = true;
951         }
952         else if ( nBulletNumberingStatus != 1 && !bHandleBullets )
953         {
954             // not all paragraphs have numbering and method called to toggle numberings --> numberings on
955             bToggleOn = true;
956         }
957     }
958     if ( bToggleOn )
959     {
960         // apply bullets/numbering for selected paragraphs
961         ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle, true );
962     }
963     else
964     {
965         // switch off bullets/numbering for selected paragraphs
966         SwitchOffBulletsNumbering( true );
967     }
968 }
969 
EnsureNumberingIsOn()970 void OutlinerView::EnsureNumberingIsOn()
971 {
972     pOwner->UndoActionStart(OLUNDO_DEPTH);
973 
974     ESelection aSel(pEditView->GetSelection());
975     aSel.Adjust();
976 
977     const bool bUpdate = pOwner->pEditEngine->IsUpdateLayout();
978     pOwner->pEditEngine->SetUpdateLayout(false);
979 
980     for (sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++)
981     {
982         Paragraph* pPara = pOwner->pParaList->GetParagraph(nPara);
983         DBG_ASSERT(pPara, "OutlinerView::EnableBullets(), illegal selection?");
984 
985         if (pPara && pOwner->GetDepth(nPara) == -1)
986             pOwner->SetDepth(pPara, 0);
987     }
988 
989     sal_Int32 nParaCount = pOwner->pParaList->GetParagraphCount();
990     pOwner->ImplCheckParagraphs(aSel.nStartPara, nParaCount);
991 
992     const sal_Int32 nEndPara = (nParaCount > 0) ? nParaCount-1 : nParaCount;
993     pOwner->pEditEngine->QuickMarkInvalid(ESelection(aSel.nStartPara, 0, nEndPara, 0));
994 
995     pOwner->pEditEngine->SetUpdateLayout(bUpdate);
996 
997     pOwner->UndoActionEnd();
998 }
999 
ApplyBulletsNumbering(const bool bHandleBullets,const SvxNumRule * pNewNumRule,const bool bCheckCurrentNumRuleBeforeApplyingNewNumRule,const bool bAtSelection)1000 void OutlinerView::ApplyBulletsNumbering(
1001     const bool bHandleBullets,
1002     const SvxNumRule* pNewNumRule,
1003     const bool bCheckCurrentNumRuleBeforeApplyingNewNumRule,
1004     const bool bAtSelection )
1005 {
1006     if (!pOwner || !pOwner->pEditEngine || !pOwner->pParaList)
1007     {
1008         return;
1009     }
1010 
1011     pOwner->UndoActionStart(OLUNDO_DEPTH);
1012     const bool bUpdate = pOwner->pEditEngine->SetUpdateLayout(false);
1013 
1014     sal_Int32 nStartPara = 0;
1015     sal_Int32 nEndPara = 0;
1016     if ( bAtSelection )
1017     {
1018         ESelection aSel( pEditView->GetSelection() );
1019         aSel.Adjust();
1020         nStartPara = aSel.nStartPara;
1021         nEndPara = aSel.nEndPara;
1022     }
1023     else
1024     {
1025         nStartPara = 0;
1026         nEndPara = pOwner->pParaList->GetParagraphCount() - 1;
1027     }
1028 
1029     for (sal_Int32 nPara = nStartPara; nPara <= nEndPara; ++nPara)
1030     {
1031         Paragraph* pPara = pOwner->pParaList->GetParagraph(nPara);
1032         DBG_ASSERT(pPara, "OutlinerView::ApplyBulletsNumbering(..), illegal selection?");
1033 
1034         if (pPara)
1035         {
1036             const sal_Int16 nDepth = pOwner->GetDepth(nPara);
1037             if ( nDepth == -1 )
1038             {
1039                 pOwner->SetDepth( pPara, 0 );
1040             }
1041 
1042             const SfxItemSet& rAttrs = pOwner->GetParaAttribs(nPara);
1043             SfxItemSet aAttrs(rAttrs);
1044             aAttrs.Put(SfxBoolItem(EE_PARA_BULLETSTATE, true));
1045 
1046             // apply new numbering rule
1047             if ( pNewNumRule )
1048             {
1049                 bool bApplyNumRule = false;
1050                 if ( !bCheckCurrentNumRuleBeforeApplyingNewNumRule )
1051                 {
1052                     bApplyNumRule = true;
1053                 }
1054                 else
1055                 {
1056                     const SvxNumberFormat* pFmt = pOwner ->GetNumberFormat(nPara);
1057                     if (!pFmt)
1058                     {
1059                         bApplyNumRule = true;
1060                     }
1061                     else
1062                     {
1063                         sal_Int16 nNumType = pFmt->GetNumberingType();
1064                         if ( bHandleBullets
1065                              && nNumType != SVX_NUM_BITMAP && nNumType != SVX_NUM_CHAR_SPECIAL)
1066                         {
1067                             // Set to Normal bullet, old bullet type is Numbering bullet.
1068                             bApplyNumRule = true;
1069                         }
1070                         else if ( !bHandleBullets
1071                                   && (nNumType == SVX_NUM_BITMAP || nNumType == SVX_NUM_CHAR_SPECIAL))
1072                         {
1073                             // Set to Numbering bullet, old bullet type is Normal bullet.
1074                             bApplyNumRule = true;
1075                         }
1076                     }
1077                 }
1078 
1079                 if ( bApplyNumRule )
1080                 {
1081                     SvxNumRule aNewRule(*pNewNumRule);
1082 
1083                     // Get old bullet space.
1084                     {
1085                         const SvxNumBulletItem* pNumBulletItem = rAttrs.GetItemIfSet(EE_PARA_NUMBULLET, false);
1086                         if (pNumBulletItem)
1087                         {
1088                             // Use default value when has not contain bullet item.
1089                             ESelection aSelection(nPara, 0);
1090                             SfxItemSet aTmpSet(pOwner->pEditEngine->GetAttribs(aSelection));
1091                             pNumBulletItem = aTmpSet.GetItem(EE_PARA_NUMBULLET);
1092                         }
1093 
1094                         if (pNumBulletItem)
1095                         {
1096                             const sal_uInt16 nLevelCnt = std::min(pNumBulletItem->GetNumRule().GetLevelCount(), aNewRule.GetLevelCount());
1097                             for ( sal_uInt16 nLevel = 0; nLevel < nLevelCnt; ++nLevel )
1098                             {
1099                                 const SvxNumberFormat* pOldFmt = pNumBulletItem->GetNumRule().Get(nLevel);
1100                                 const SvxNumberFormat* pNewFmt = aNewRule.Get(nLevel);
1101                                 if (pOldFmt && pNewFmt && (pOldFmt->GetFirstLineOffset() != pNewFmt->GetFirstLineOffset() || pOldFmt->GetAbsLSpace() != pNewFmt->GetAbsLSpace()))
1102                                 {
1103                                     SvxNumberFormat aNewFmtClone(*pNewFmt);
1104                                     aNewFmtClone.SetFirstLineOffset(pOldFmt->GetFirstLineOffset());
1105                                     aNewFmtClone.SetAbsLSpace(pOldFmt->GetAbsLSpace());
1106                                     aNewRule.SetLevel(nLevel, &aNewFmtClone);
1107                                 }
1108                             }
1109                         }
1110                     }
1111 
1112                     aAttrs.Put(SvxNumBulletItem(std::move(aNewRule), EE_PARA_NUMBULLET));
1113                 }
1114             }
1115             pOwner->SetParaAttribs(nPara, aAttrs);
1116         }
1117     }
1118 
1119     const sal_uInt16 nParaCount = static_cast<sal_uInt16>(pOwner->pParaList->GetParagraphCount());
1120     pOwner->ImplCheckParagraphs( nStartPara, nParaCount );
1121     pOwner->pEditEngine->QuickMarkInvalid( ESelection( nStartPara, 0, nParaCount, 0 ) );
1122 
1123     pOwner->pEditEngine->SetUpdateLayout( bUpdate );
1124 
1125     pOwner->UndoActionEnd();
1126 }
1127 
1128 
SwitchOffBulletsNumbering(const bool bAtSelection)1129 void OutlinerView::SwitchOffBulletsNumbering(
1130     const bool bAtSelection )
1131 {
1132     sal_Int32 nStartPara = 0;
1133     sal_Int32 nEndPara = 0;
1134     if ( bAtSelection )
1135     {
1136         ESelection aSel( pEditView->GetSelection() );
1137         aSel.Adjust();
1138         nStartPara = aSel.nStartPara;
1139         nEndPara = aSel.nEndPara;
1140     }
1141     else
1142     {
1143         nStartPara = 0;
1144         nEndPara = pOwner->pParaList->GetParagraphCount() - 1;
1145     }
1146 
1147     pOwner->UndoActionStart( OLUNDO_DEPTH );
1148     const bool bUpdate = pOwner->pEditEngine->SetUpdateLayout( false );
1149 
1150     for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; ++nPara )
1151     {
1152         Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
1153         DBG_ASSERT(pPara, "OutlinerView::SwitchOffBulletsNumbering(...), illegal paragraph index?");
1154 
1155         if( pPara )
1156         {
1157             pOwner->SetDepth( pPara, -1 );
1158 
1159             const SfxItemSet& rAttrs = pOwner->GetParaAttribs( nPara );
1160             if (rAttrs.GetItemState( EE_PARA_BULLETSTATE ) == SfxItemState::SET)
1161             {
1162                 SfxItemSet aAttrs(rAttrs);
1163                 aAttrs.ClearItem( EE_PARA_BULLETSTATE );
1164                 pOwner->SetParaAttribs( nPara, aAttrs );
1165             }
1166         }
1167     }
1168 
1169     const sal_uInt16 nParaCount = static_cast<sal_uInt16>(pOwner->pParaList->GetParagraphCount());
1170     pOwner->ImplCheckParagraphs( nStartPara, nParaCount );
1171     pOwner->pEditEngine->QuickMarkInvalid( ESelection( nStartPara, 0, nParaCount, 0 ) );
1172 
1173     pOwner->pEditEngine->SetUpdateLayout( bUpdate );
1174     pOwner->UndoActionEnd();
1175 }
1176 
1177 
RemoveAttribsKeepLanguages(bool bRemoveParaAttribs)1178 void OutlinerView::RemoveAttribsKeepLanguages( bool bRemoveParaAttribs )
1179 {
1180     RemoveAttribs( bRemoveParaAttribs, true /*keep language attribs*/ );
1181 }
1182 
RemoveAttribs(bool bRemoveParaAttribs,bool bKeepLanguages)1183 void OutlinerView::RemoveAttribs( bool bRemoveParaAttribs, bool bKeepLanguages )
1184 {
1185     bool bUpdate = pOwner->SetUpdateLayout( false );
1186     pOwner->UndoActionStart( OLUNDO_ATTR );
1187     if (bKeepLanguages)
1188         pEditView->RemoveAttribsKeepLanguages( bRemoveParaAttribs );
1189     else
1190         pEditView->RemoveAttribs( bRemoveParaAttribs );
1191     if ( bRemoveParaAttribs )
1192     {
1193         // Loop through all paragraphs and set indentation and level
1194         ESelection aSel = pEditView->GetSelection();
1195         aSel.Adjust();
1196         for ( sal_Int32 nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ )
1197         {
1198             Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara );
1199             pOwner->ImplInitDepth( nPara, pPara->GetDepth(), false );
1200         }
1201     }
1202     pOwner->UndoActionEnd();
1203     pOwner->SetUpdateLayout( bUpdate );
1204 }
1205 
1206 
1207 // ======================   Simple pass-through   =======================
1208 
1209 
InsertText(const OUString & rNew,bool bSelect)1210 void OutlinerView::InsertText( const OUString& rNew, bool bSelect )
1211 {
1212     if( pOwner->bFirstParaIsEmpty )
1213         pOwner->Insert( OUString() );
1214     pEditView->InsertText( rNew, bSelect );
1215 }
1216 
SetVisArea(const tools::Rectangle & rRect)1217 void OutlinerView::SetVisArea( const tools::Rectangle& rRect )
1218 {
1219     pEditView->SetVisArea( rRect );
1220 }
1221 
1222 
SetSelection(const ESelection & rSel)1223 void OutlinerView::SetSelection( const ESelection& rSel )
1224 {
1225     pEditView->SetSelection( rSel );
1226 }
1227 
GetSelectionRectangles(std::vector<tools::Rectangle> & rLogicRects) const1228 void OutlinerView::GetSelectionRectangles(std::vector<tools::Rectangle>& rLogicRects) const
1229 {
1230     pEditView->GetSelectionRectangles(rLogicRects);
1231 }
1232 
SetReadOnly(bool bReadOnly)1233 void OutlinerView::SetReadOnly( bool bReadOnly )
1234 {
1235     pEditView->SetReadOnly( bReadOnly );
1236 }
1237 
IsReadOnly() const1238 bool OutlinerView::IsReadOnly() const
1239 {
1240     return pEditView->IsReadOnly();
1241 }
1242 
HasSelection() const1243 bool OutlinerView::HasSelection() const
1244 {
1245     return pEditView->HasSelection();
1246 }
1247 
ShowCursor(bool bGotoCursor,bool bActivate)1248 void OutlinerView::ShowCursor( bool bGotoCursor, bool bActivate )
1249 {
1250     pEditView->ShowCursor( bGotoCursor, /*bForceVisCursor=*/true, bActivate );
1251 }
1252 
HideCursor(bool bDeactivate)1253 void OutlinerView::HideCursor(bool bDeactivate)
1254 {
1255     pEditView->HideCursor(bDeactivate);
1256 }
1257 
SetWindow(vcl::Window * pWin)1258 void OutlinerView::SetWindow( vcl::Window* pWin )
1259 {
1260     pEditView->SetWindow( pWin );
1261 }
1262 
GetWindow() const1263 vcl::Window* OutlinerView::GetWindow() const
1264 {
1265     return pEditView->GetWindow();
1266 }
1267 
SetOutputArea(const tools::Rectangle & rRect)1268 void OutlinerView::SetOutputArea( const tools::Rectangle& rRect )
1269 {
1270     pEditView->SetOutputArea( rRect );
1271 }
1272 
GetOutputArea() const1273 tools::Rectangle const & OutlinerView::GetOutputArea() const
1274 {
1275     return pEditView->GetOutputArea();
1276 }
1277 
GetSelected() const1278 OUString OutlinerView::GetSelected() const
1279 {
1280     return pEditView->GetSelected();
1281 }
1282 
StartSpeller(weld::Widget * pDialogParent)1283 void OutlinerView::StartSpeller(weld::Widget* pDialogParent)
1284 {
1285     pEditView->StartSpeller(pDialogParent);
1286 }
1287 
StartThesaurus(weld::Widget * pDialogParent)1288 EESpellState OutlinerView::StartThesaurus(weld::Widget* pDialogParent)
1289 {
1290     return pEditView->StartThesaurus(pDialogParent);
1291 }
1292 
StartTextConversion(weld::Widget * pDialogParent,LanguageType nSrcLang,LanguageType nDestLang,const vcl::Font * pDestFont,sal_Int32 nOptions,bool bIsInteractive,bool bMultipleDoc)1293 void OutlinerView::StartTextConversion(weld::Widget* pDialogParent,
1294     LanguageType nSrcLang, LanguageType nDestLang, const vcl::Font *pDestFont,
1295     sal_Int32 nOptions, bool bIsInteractive, bool bMultipleDoc )
1296 {
1297     if (
1298         (LANGUAGE_KOREAN == nSrcLang && LANGUAGE_KOREAN == nDestLang) ||
1299         (LANGUAGE_CHINESE_SIMPLIFIED  == nSrcLang && LANGUAGE_CHINESE_TRADITIONAL == nDestLang) ||
1300         (LANGUAGE_CHINESE_TRADITIONAL == nSrcLang && LANGUAGE_CHINESE_SIMPLIFIED  == nDestLang)
1301        )
1302     {
1303         pEditView->StartTextConversion(pDialogParent, nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc);
1304     }
1305     else
1306     {
1307         OSL_FAIL( "unexpected language" );
1308     }
1309 }
1310 
1311 
StartSearchAndReplace(const SvxSearchItem & rSearchItem)1312 sal_Int32 OutlinerView::StartSearchAndReplace( const SvxSearchItem& rSearchItem )
1313 {
1314     return pEditView->StartSearchAndReplace( rSearchItem );
1315 }
1316 
TransliterateText(TransliterationFlags nTransliterationMode)1317 void OutlinerView::TransliterateText( TransliterationFlags nTransliterationMode )
1318 {
1319     pEditView->TransliterateText( nTransliterationMode );
1320 }
1321 
GetSelection() const1322 ESelection OutlinerView::GetSelection() const
1323 {
1324     return pEditView->GetSelection();
1325 }
1326 
1327 
Scroll(tools::Long nHorzScroll,tools::Long nVertScroll)1328 void OutlinerView::Scroll( tools::Long nHorzScroll, tools::Long nVertScroll )
1329 {
1330     pEditView->Scroll( nHorzScroll, nVertScroll );
1331 }
1332 
SetControlWord(EVControlBits nWord)1333 void OutlinerView::SetControlWord( EVControlBits nWord )
1334 {
1335     pEditView->SetControlWord( nWord );
1336 }
1337 
GetControlWord() const1338 EVControlBits OutlinerView::GetControlWord() const
1339 {
1340     return pEditView->GetControlWord();
1341 }
1342 
SetAnchorMode(EEAnchorMode eMode)1343 void OutlinerView::SetAnchorMode( EEAnchorMode eMode )
1344 {
1345     pEditView->SetAnchorMode( eMode );
1346 }
1347 
GetAnchorMode() const1348 EEAnchorMode OutlinerView::GetAnchorMode() const
1349 {
1350     return pEditView->GetAnchorMode();
1351 }
1352 
Copy()1353 void OutlinerView::Copy()
1354 {
1355     pEditView->Copy();
1356 }
1357 
InsertField(const SvxFieldItem & rFld)1358 void OutlinerView::InsertField( const SvxFieldItem& rFld )
1359 {
1360     pEditView->InsertField( rFld );
1361 }
1362 
GetFieldUnderMousePointer() const1363 const SvxFieldItem* OutlinerView::GetFieldUnderMousePointer() const
1364 {
1365     return pEditView->GetFieldUnderMousePointer();
1366 }
1367 
GetFieldAtSelection(bool bAlsoCheckBeforeCursor) const1368 const SvxFieldItem* OutlinerView::GetFieldAtSelection(bool bAlsoCheckBeforeCursor) const
1369 {
1370     return pEditView->GetFieldAtSelection(bAlsoCheckBeforeCursor);
1371 }
1372 
SelectFieldAtCursor()1373 void OutlinerView::SelectFieldAtCursor()
1374 {
1375     pEditView->SelectFieldAtCursor();
1376 }
1377 
SetInvalidateMore(sal_uInt16 nPixel)1378 void OutlinerView::SetInvalidateMore( sal_uInt16 nPixel )
1379 {
1380     pEditView->SetInvalidateMore( nPixel );
1381 }
1382 
1383 
GetInvalidateMore() const1384 sal_uInt16 OutlinerView::GetInvalidateMore() const
1385 {
1386     return pEditView->GetInvalidateMore();
1387 }
1388 
1389 
IsCursorAtWrongSpelledWord()1390 bool OutlinerView::IsCursorAtWrongSpelledWord()
1391 {
1392     return pEditView->IsCursorAtWrongSpelledWord();
1393 }
1394 
1395 
IsWrongSpelledWordAtPos(const Point & rPosPixel)1396 bool OutlinerView::IsWrongSpelledWordAtPos( const Point& rPosPixel )
1397 {
1398     return pEditView->IsWrongSpelledWordAtPos( rPosPixel, /*bMarkIfWrong*/false );
1399 }
1400 
ExecuteSpellPopup(const Point & rPosPixel,const Link<SpellCallbackInfo &,void> & rStartDlg)1401 void OutlinerView::ExecuteSpellPopup(const Point& rPosPixel, const Link<SpellCallbackInfo&,void>& rStartDlg)
1402 {
1403     pEditView->ExecuteSpellPopup(rPosPixel, rStartDlg);
1404 }
1405 
Read(SvStream & rInput,EETextFormat eFormat,SvKeyValueIterator * pHTTPHeaderAttrs)1406 void OutlinerView::Read( SvStream& rInput, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs )
1407 {
1408     sal_Int32 nOldParaCount = pEditView->getEditEngine().GetParagraphCount();
1409     ESelection aOldSel = pEditView->GetSelection();
1410     aOldSel.Adjust();
1411 
1412     pEditView->Read( rInput, eFormat, pHTTPHeaderAttrs );
1413 
1414     tools::Long nParaDiff = pEditView->getEditEngine().GetParagraphCount() - nOldParaCount;
1415     sal_Int32 nChangesStart = aOldSel.nStartPara;
1416     sal_Int32 nChangesEnd = nChangesStart + nParaDiff + (aOldSel.nEndPara-aOldSel.nStartPara);
1417 
1418     for ( sal_Int32 n = nChangesStart; n <= nChangesEnd; n++ )
1419     {
1420         if ( pOwner->GetOutlinerMode() == OutlinerMode::OutlineObject )
1421             pOwner->ImplSetLevelDependentStyleSheet( n );
1422     }
1423 
1424     pOwner->ImpFilterIndents( nChangesStart, nChangesEnd );
1425 }
1426 
SetBackgroundColor(const Color & rColor)1427 void OutlinerView::SetBackgroundColor( const Color& rColor )
1428 {
1429     pEditView->SetBackgroundColor( rColor );
1430 }
1431 
RegisterViewShell(OutlinerViewShell * pViewShell)1432 void OutlinerView::RegisterViewShell(OutlinerViewShell* pViewShell)
1433 {
1434     pEditView->RegisterViewShell(pViewShell);
1435 }
1436 
GetBackgroundColor() const1437 Color const & OutlinerView::GetBackgroundColor() const
1438 {
1439     return pEditView->GetBackgroundColor();
1440 }
1441 
GetAttribs()1442 SfxItemSet OutlinerView::GetAttribs()
1443 {
1444     return pEditView->GetAttribs();
1445 }
1446 
GetSelectedScriptType() const1447 SvtScriptType OutlinerView::GetSelectedScriptType() const
1448 {
1449     return pEditView->GetSelectedScriptType();
1450 }
1451 
GetSurroundingText() const1452 OUString OutlinerView::GetSurroundingText() const
1453 {
1454     return pEditView->GetSurroundingText();
1455 }
1456 
GetSurroundingTextSelection() const1457 Selection OutlinerView::GetSurroundingTextSelection() const
1458 {
1459     return pEditView->GetSurroundingTextSelection();
1460 }
1461 
DeleteSurroundingText(const Selection & rSelection)1462 bool OutlinerView::DeleteSurroundingText(const Selection& rSelection)
1463 {
1464     return pEditView->DeleteSurroundingText(rSelection);
1465 }
1466 
1467 // ===== some code for thesaurus sub menu within context menu
1468 
1469 namespace {
1470 
isSingleScriptType(SvtScriptType nScriptType)1471 bool isSingleScriptType( SvtScriptType nScriptType )
1472 {
1473     sal_uInt8 nScriptCount = 0;
1474 
1475     if (nScriptType & SvtScriptType::LATIN)
1476         ++nScriptCount;
1477     if (nScriptType & SvtScriptType::ASIAN)
1478         ++nScriptCount;
1479     if (nScriptType & SvtScriptType::COMPLEX)
1480         ++nScriptCount;
1481 
1482     return nScriptCount == 1;
1483 }
1484 
1485 }
1486 
1487 // returns: true if a word for thesaurus look-up was found at the current cursor position.
1488 // The status string will be word + iso language string (e.g. "light#en-US")
GetStatusValueForThesaurusFromContext(OUString & rStatusVal,LanguageType & rLang,const EditView & rEditView)1489 bool GetStatusValueForThesaurusFromContext(
1490     OUString &rStatusVal,
1491     LanguageType &rLang,
1492     const EditView &rEditView )
1493 {
1494     // get text and locale for thesaurus look up
1495     OUString aText;
1496     EditEngine& rEditEngine = rEditView.getEditEngine();
1497     ESelection aTextSel( rEditView.GetSelection() );
1498     if (!aTextSel.HasRange())
1499         aTextSel = rEditEngine.GetWord( aTextSel, i18n::WordType::DICTIONARY_WORD );
1500     aText = rEditEngine.GetText( aTextSel );
1501     aTextSel.Adjust();
1502 
1503     if (!isSingleScriptType(rEditEngine.GetScriptType(aTextSel)))
1504         return false;
1505 
1506     LanguageType nLang = rEditEngine.GetLanguage( aTextSel.nStartPara, aTextSel.nStartPos ).nLang;
1507     OUString aLangText( LanguageTag::convertToBcp47( nLang ) );
1508 
1509     // set word and locale to look up as status value
1510     rStatusVal  = aText + "#" + aLangText;
1511     rLang       = nLang;
1512 
1513     return aText.getLength() > 0;
1514 }
1515 
1516 
ReplaceTextWithSynonym(EditView & rEditView,const OUString & rSynonmText)1517 void ReplaceTextWithSynonym( EditView &rEditView, const OUString &rSynonmText )
1518 {
1519     // get selection to use
1520     ESelection aCurSel( rEditView.GetSelection() );
1521     if (!rEditView.HasSelection())
1522     {
1523         // select the same word that was used in GetStatusValueForThesaurusFromContext by calling GetWord.
1524         // (In the end both functions will call ImpEditEngine::SelectWord)
1525         rEditView.SelectCurrentWord( i18n::WordType::DICTIONARY_WORD );
1526         aCurSel = rEditView.GetSelection();
1527     }
1528 
1529     // replace word ...
1530     rEditView.InsertText( rSynonmText );
1531     rEditView.ShowCursor( true, false );
1532 }
1533 
1534 
1535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1536