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