Coverage Report

Created: 2026-02-14 09:37

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