Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sd/source/ui/func/fuolbull.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 <fuolbull.hxx>
21
#include <svl/intitem.hxx>
22
#include <svl/stritem.hxx>
23
#include <editeng/outliner.hxx>
24
#include <editeng/eeitem.hxx>
25
#include <sfx2/request.hxx>
26
#include <editeng/numitem.hxx>
27
#include <strings.hxx>
28
29
#include <svx/svxids.hrc>
30
#include <OutlineView.hxx>
31
#include <DrawDocShell.hxx>
32
#include <DrawViewShell.hxx>
33
#include <Window.hxx>
34
#include <drawdoc.hxx>
35
#include <sdabstdlg.hxx>
36
#include <svx/nbdtmg.hxx>
37
#include <svx/nbdtmgfact.hxx>
38
#include <svx/svdoutl.hxx>
39
#include <memory>
40
41
using namespace svx::sidebar;
42
namespace sd {
43
44
FuBulletAndPosition::FuBulletAndPosition(ViewShell& rViewShell, ::sd::Window* pWindow,
45
                                 ::sd::View* pView, SdDrawDocument& rDoc,
46
                                 SfxRequest& rReq)
47
0
       : FuPoor(rViewShell, pWindow, pView, rDoc, rReq)
48
0
{
49
0
}
50
51
rtl::Reference<FuPoor> FuBulletAndPosition::Create( ViewShell& rViewSh, ::sd::Window* pWin, ::sd::View* pView, SdDrawDocument& rDoc, SfxRequest& rReq )
52
0
{
53
0
    rtl::Reference<FuPoor> xFunc( new FuBulletAndPosition( rViewSh, pWin, pView, rDoc, rReq ) );
54
0
    xFunc->DoExecute(rReq);
55
0
    return xFunc;
56
0
}
57
58
void FuBulletAndPosition::DoExecute( SfxRequest& rReq )
59
0
{
60
0
    const sal_uInt16 nSId = rReq.GetSlot();
61
0
    if ( nSId == FN_SVX_SET_BULLET || nSId == FN_SVX_SET_NUMBER )
62
0
    {
63
0
        SetCurrentBulletsNumbering(rReq);
64
0
        return;
65
0
    }
66
67
0
    const SfxItemSet* pArgs = rReq.GetArgs();
68
0
    const SfxStringItem* pPageItem = SfxItemSet::GetItem<SfxStringItem>(pArgs, FN_PARAM_1, false);
69
70
0
    if ( pArgs && !pPageItem )
71
0
    {
72
        /* not direct to pOlView; therefore, SdDrawView::SetAttributes can catch
73
           changes to master page and redirect to a template */
74
0
        mpView->SetAttributes(*pArgs);
75
0
        return;
76
0
    }
77
78
    // fill ItemSet for Dialog
79
0
    SfxItemSet aEditAttr( mrDoc.GetPool() );
80
0
    mpView->GetAttributes( aEditAttr );
81
82
0
    SfxItemSetFixed<EE_PARA_NUMBULLET, EE_PARA_BULLET> aNewAttr( mrViewShell.GetPool() );
83
0
    aNewAttr.Put( aEditAttr, false );
84
85
0
    auto pView = mpView;
86
87
    // create and execute dialog
88
0
    SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create();
89
0
    ScopedVclPtr<AbstractSvxBulletAndPositionDlg> pDlg(pFact->CreateSvxBulletAndPositionDlg(mrViewShell.GetFrameWeld(), &aNewAttr, mpView));
90
0
    sal_uInt16 nResult = pDlg->Execute();
91
92
0
    if( nResult == RET_OK )
93
0
    {
94
0
        OutlinerView* pOLV = pView->GetTextEditOutlinerView();
95
96
0
        std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
97
98
0
        if (OutlineView* pOutlineView = dynamic_cast<OutlineView*>(pView))
99
0
        {
100
0
            pOLV = pOutlineView->GetViewByWindow(mrViewShell.GetActiveWindow());
101
0
            aGuard.reset(new OutlineViewModelChangeGuard(*pOutlineView));
102
0
        }
103
104
0
        if( pOLV )
105
0
            pOLV->EnsureNumberingIsOn();
106
107
0
        const SfxItemSet pOutputSet( *pDlg->GetOutputItemSet( &aNewAttr ) );
108
0
        pView->SetAttributes(pOutputSet, /*bReplaceAll=*/false, /*bSlide*/ pDlg->IsSlideScope(), /*bMaster=*/pDlg->IsApplyToMaster());
109
0
    }
110
111
0
    rReq.Done();
112
0
}
113
114
void FuBulletAndPosition::SetCurrentBulletsNumbering(SfxRequest& rReq)
115
0
{
116
0
    if (!mpView)
117
0
        return;
118
119
0
    const sal_uInt16 nSId = rReq.GetSlot();
120
0
    if ( nSId != FN_SVX_SET_BULLET && nSId != FN_SVX_SET_NUMBER )
121
0
    {
122
        // unexpected SfxRequest
123
0
        return;
124
0
    }
125
126
0
    const SfxUInt16Item* pItem = rReq.GetArgs()->GetItem(SID_ATTR_BULLET_INDEX);
127
0
    if (!pItem) // tdf#161653
128
0
        pItem = rReq.GetArg<SfxUInt16Item>(nSId);
129
0
    if ( !pItem )
130
0
    {
131
0
        rReq.Done();
132
0
        return;
133
0
    }
134
135
0
    SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aNewAttr( mrViewShell.GetPool() );
136
0
    {
137
0
        SfxItemSet aEditAttr( mrDoc.GetPool() );
138
0
        mpView->GetAttributes( aEditAttr );
139
0
        aNewAttr.Put( aEditAttr, false );
140
0
    }
141
142
0
    const DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >(&mrViewShell);
143
    //Init bullet level in "Customize" tab page in bullet dialog in master page view
144
0
    const bool bInMasterView = pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage;
145
0
    if ( bInMasterView )
146
0
    {
147
0
        SdrObject* pObj = mpView->GetTextEditObject();
148
0
        if( pObj && pObj->GetObjIdentifier() == SdrObjKind::OutlineText )
149
0
        {
150
0
            const sal_uInt16 nLevel = mpView->GetSelectionLevel();
151
0
            if( nLevel != 0xFFFF )
152
0
            {
153
                //save the itemset value
154
0
                SfxItemSet aStoreSet( aNewAttr );
155
0
                aNewAttr.ClearItem();
156
                //extend range
157
0
                aNewAttr.MergeRange( SID_PARAM_NUM_PRESET, SID_PARAM_CUR_NUM_LEVEL );
158
0
                aNewAttr.Put( aStoreSet );
159
                //put current level user selected
160
0
                aNewAttr.Put( SfxUInt16Item( SID_PARAM_CUR_NUM_LEVEL, nLevel ) );
161
0
            }
162
0
        }
163
0
    }
164
165
0
    sal_uInt16 nIdx = pItem->GetValue();
166
0
    bool bToggle = false;
167
0
    if( nIdx == BULLET_TOGGLE )
168
0
    {
169
        // Set bullet status to on/off
170
0
        nIdx = 1;
171
0
        bToggle = true;
172
0
    }
173
0
    nIdx--;
174
175
0
    TypedWhichId<SvxNumBulletItem> nNumItemId = SID_ATTR_NUMBERING_RULE;
176
0
    const SfxPoolItem* pTmpItem = GetNumBulletItem( aNewAttr, nNumItemId );
177
0
    std::unique_ptr<SvxNumRule> pNumRule;
178
0
    if ( pTmpItem )
179
0
    {
180
0
        pNumRule.reset(new SvxNumRule(static_cast<const SvxNumBulletItem*>(pTmpItem)->GetNumRule()));
181
182
        // get numbering rule corresponding to <nIdx> and apply the needed number formats to <pNumRule>
183
0
        NBOTypeMgrBase* pNumRuleMgr =
184
0
            NBOutlineTypeMgrFact::CreateInstance(
185
0
                nSId == FN_SVX_SET_BULLET ? NBOType::Bullets : NBOType::Numbering );
186
0
        if ( pNumRuleMgr )
187
0
        {
188
0
            sal_uInt16 nActNumLvl = sal_uInt16(0xFFFF);
189
0
            if(const SfxUInt16Item* pNumLevelItem = aNewAttr.GetItemIfSet(SID_PARAM_CUR_NUM_LEVEL, false))
190
0
                nActNumLvl = pNumLevelItem->GetValue();
191
192
0
            pNumRuleMgr->SetItems(&aNewAttr);
193
0
            SvxNumRule aTmpRule( *pNumRule );
194
0
            if ( nSId == FN_SVX_SET_BULLET && bToggle && nIdx==0 )
195
0
            {
196
                // for toggling bullets get default numbering rule
197
0
                pNumRuleMgr->ApplyNumRule( aTmpRule, nIdx, nActNumLvl, true );
198
0
            }
199
0
            else
200
0
            {
201
0
                pNumRuleMgr->ApplyNumRule( aTmpRule, nIdx, nActNumLvl );
202
0
            }
203
204
0
            sal_uInt16 nMask = 1;
205
0
            for(sal_uInt16 i = 0; i < pNumRule->GetLevelCount(); i++)
206
0
            {
207
0
                if(nActNumLvl & nMask)
208
0
                {
209
0
                    SvxNumberFormat aFmt(aTmpRule.GetLevel(i));
210
0
                    if (nSId == FN_SVX_SET_BULLET && bToggle)
211
0
                    {
212
                        // If changing to a bullet, then make its format and indent has a good
213
                        // default, similar to what the master page offers:
214
0
                        SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent(i, aFmt);
215
0
                    }
216
0
                    pNumRule->SetLevel(i, aFmt);
217
0
                }
218
0
                nMask <<= 1;
219
0
            }
220
0
        }
221
0
    }
222
223
0
    OutlinerView* pOLV = mpView->GetTextEditOutlinerView();
224
0
    std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard;
225
0
    if (OutlineView* pView = dynamic_cast<OutlineView*>(mpView))
226
0
    {
227
0
        pOLV = pView->GetViewByWindow(mrViewShell.GetActiveWindow());
228
0
        aGuard.reset(new OutlineViewModelChangeGuard(*pView));
229
0
    }
230
231
0
    SdrOutliner* pOwner = bInMasterView ? mpView->GetTextEditOutliner() : nullptr;
232
0
    const bool bOutlinerUndoEnabled = pOwner && !pOwner->IsInUndo() && pOwner->IsUndoEnabled();
233
0
    SdrModel* pSdrModel = bInMasterView ? &mpView->GetModel() : nullptr;
234
0
    const bool bModelUndoEnabled = pSdrModel && pSdrModel->IsUndoEnabled();
235
236
0
    if ( bOutlinerUndoEnabled )
237
0
    {
238
0
        pOwner->UndoActionStart( OLUNDO_ATTR );
239
0
    }
240
0
    else if ( bModelUndoEnabled )
241
0
    {
242
0
        pSdrModel->BegUndo();
243
0
    }
244
245
0
    if ( pOLV )
246
0
    {
247
0
        pOLV->ToggleBulletsNumbering( bToggle, nSId == FN_SVX_SET_BULLET, bInMasterView ? nullptr : pNumRule.get() );
248
0
    }
249
0
    else
250
0
    {
251
0
        mpView->ChangeMarkedObjectsBulletsNumbering( bToggle, nSId == FN_SVX_SET_BULLET, bInMasterView ? nullptr : pNumRule.get() );
252
0
    }
253
254
0
    if (bInMasterView && pNumRule)
255
0
    {
256
0
        SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aSetAttr( mrViewShell.GetPool() );
257
0
        aSetAttr.Put(SvxNumBulletItem( *pNumRule, nNumItemId ));
258
0
        mpView->SetAttributes(aSetAttr);
259
0
    }
260
261
0
    if( bOutlinerUndoEnabled )
262
0
    {
263
0
        pOwner->UndoActionEnd();
264
0
    }
265
0
    else if ( bModelUndoEnabled )
266
0
    {
267
0
        pSdrModel->EndUndo();
268
0
    }
269
270
0
    pNumRule.reset();
271
0
    rReq.Done();
272
0
}
273
274
const SvxNumBulletItem* FuBulletAndPosition::GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId)
275
0
{
276
0
    const SvxNumBulletItem* pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
277
278
0
    if(pTmpItem)
279
0
        return pTmpItem;
280
281
0
    nNumItemId = aNewAttr.GetPool()->GetWhichIDFromSlotID(SID_ATTR_NUMBERING_RULE);
282
0
    pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
283
0
    if (pTmpItem)
284
0
        return pTmpItem;
285
286
0
    bool bOutliner = false;
287
0
    bool bTitle = false;
288
289
0
    if( mpView )
290
0
    {
291
0
        const SdrMarkList& rMarkList = mpView->GetMarkedObjectList();
292
0
        const size_t nCount = rMarkList.GetMarkCount();
293
294
0
        for(size_t nNum = 0; nNum < nCount; ++nNum)
295
0
        {
296
0
            SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj();
297
0
            if( pObj->GetObjInventor() == SdrInventor::Default )
298
0
            {
299
0
                switch(pObj->GetObjIdentifier())
300
0
                {
301
0
                case SdrObjKind::TitleText:
302
0
                    bTitle = true;
303
0
                    break;
304
0
                case SdrObjKind::OutlineText:
305
0
                    bOutliner = true;
306
0
                    break;
307
0
                default:
308
0
                    break;
309
0
                }
310
0
            }
311
0
        }
312
0
    }
313
314
0
    const SvxNumBulletItem *pItem = nullptr;
315
0
    if(bOutliner)
316
0
    {
317
0
        SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool();
318
0
        SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( STR_LAYOUT_OUTLINE + " 1", SfxStyleFamily::Pseudo);
319
0
        if( pFirstStyleSheet )
320
0
            pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false);
321
0
    }
322
323
0
    if( pItem == nullptr )
324
0
        pItem = aNewAttr.GetPool()->GetSecondaryPool()->GetUserDefaultItem(EE_PARA_NUMBULLET);
325
326
    //DBG_ASSERT( pItem, "No EE_PARA_NUMBULLET in the Pool!" );
327
328
0
    aNewAttr.Put(pItem->CloneSetWhich(EE_PARA_NUMBULLET));
329
330
0
    const SvxNumBulletItem* pBulletItem = nullptr;
331
0
    if(bTitle && aNewAttr.GetItemState(EE_PARA_NUMBULLET, true, &pBulletItem) == SfxItemState::SET )
332
0
    {
333
0
        const SvxNumRule& rLclRule = pBulletItem->GetNumRule();
334
0
        SvxNumRule aNewRule( rLclRule );
335
0
        aNewRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS );
336
337
0
        SvxNumBulletItem aNewItem( std::move(aNewRule), EE_PARA_NUMBULLET );
338
0
        aNewAttr.Put(aNewItem);
339
0
    }
340
341
0
    pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false);
342
0
    return pTmpItem;
343
0
}
344
345
346
} // end of namespace sd
347
348
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */