Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/sidebar/paragraph/ParaLineSpacingControl.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 "ParaLineSpacingControl.hxx"
21
22
#include <editeng/editids.hrc>
23
#include <editeng/lspcitem.hxx>
24
#include <sfx2/dispatch.hxx>
25
#include <sfx2/module.hxx>
26
#include <sfx2/sfxsids.hrc>
27
#include <sfx2/viewfrm.hxx>
28
#include <svtools/unitconv.hxx>
29
#include <tools/fldunit.hxx>
30
#include <tools/mapunit.hxx>
31
32
#include <svl/intitem.hxx>
33
#include <svl/itemset.hxx>
34
35
#include <ParaLineSpacingPopup.hxx>
36
37
#include <vcl/commandinfoprovider.hxx>
38
#include <vcl/weld/Builder.hxx>
39
40
0
#define DEFAULT_LINE_SPACING  200
41
0
#define FIX_DIST_DEF          283
42
0
#define LINESPACE_1           100
43
0
#define LINESPACE_15          150
44
0
#define LINESPACE_2           200
45
0
#define LINESPACE_115         115
46
47
// values of the mxLineDist listbox
48
0
#define LLINESPACE_1          0
49
0
#define LLINESPACE_115        1
50
0
#define LLINESPACE_15         2
51
0
#define LLINESPACE_2          3
52
0
#define LLINESPACE_PROP       4
53
0
#define LLINESPACE_MIN        5
54
0
#define LLINESPACE_DURCH      6
55
0
#define LLINESPACE_FIX        7
56
57
0
#define MIN_FIXED_DISTANCE    28
58
59
using namespace svx;
60
61
ParaLineSpacingControl::ParaLineSpacingControl(SvxLineSpacingToolBoxControl* pControl, weld::Widget* pParent)
62
0
    : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/paralinespacingcontrol.ui"_ustr, u"ParaLineSpacingControl"_ustr)
63
0
    , mxControl(pControl)
64
0
    , meLNSpaceUnit(MapUnit::Map100thMM)
65
0
    , mxSpacing1Button(m_xBuilder->weld_button(u"spacing_1"_ustr))
66
0
    , mxSpacing115Button(m_xBuilder->weld_button(u"spacing_115"_ustr))
67
0
    , mxSpacing15Button(m_xBuilder->weld_button(u"spacing_15"_ustr))
68
0
    , mxSpacing2Button(m_xBuilder->weld_button(u"spacing_2"_ustr))
69
0
    , mxLineDist(m_xBuilder->weld_combo_box(u"line_dist"_ustr))
70
0
    , mxLineDistLabel(m_xBuilder->weld_label(u"value_label"_ustr))
71
0
    , mxLineDistAtPercentBox(m_xBuilder->weld_metric_spin_button(u"percent_box"_ustr, FieldUnit::PERCENT))
72
0
    , mxLineDistAtMetricBox(m_xBuilder->weld_metric_spin_button(u"metric_box"_ustr, FieldUnit::CM))
73
0
    , mpActLineDistFld(mxLineDistAtPercentBox.get())
74
0
{
75
0
    Link<weld::Button&,void> aLink = LINK(this, ParaLineSpacingControl, PredefinedValuesHandler);
76
0
    mxSpacing1Button->connect_clicked(aLink);
77
0
    mxSpacing115Button->connect_clicked(aLink);
78
0
    mxSpacing15Button->connect_clicked(aLink);
79
0
    mxSpacing2Button->connect_clicked(aLink);
80
81
0
    Link<weld::ComboBox&,void> aLink3 = LINK( this, ParaLineSpacingControl, LineSPDistHdl_Impl );
82
0
    mxLineDist->connect_changed(aLink3);
83
0
    SelectEntryPos(LLINESPACE_1);
84
85
0
    Link<weld::MetricSpinButton&,void> aLink2 = LINK( this, ParaLineSpacingControl, LineSPDistAtHdl_Impl );
86
0
    mxLineDistAtPercentBox->connect_value_changed( aLink2 );
87
0
    mxLineDistAtMetricBox->connect_value_changed( aLink2 );
88
89
0
    FieldUnit eUnit = FieldUnit::INCH;
90
0
    SfxPoolItemHolder aResult;
91
0
    SfxViewFrame* pCurrent(SfxViewFrame::Current());
92
0
    if (pCurrent && pCurrent->GetBindings().GetDispatcher()->QueryState(SID_ATTR_METRIC, aResult) >= SfxItemState::DEFAULT)
93
0
        eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(aResult.getItem())->GetValue());
94
0
    else
95
0
        eUnit = SfxModule::GetCurrentFieldUnit();
96
97
0
    SetFieldUnit(*mxLineDistAtMetricBox, eUnit);
98
99
0
    Initialize();
100
0
}
101
102
void ParaLineSpacingControl::GrabFocus()
103
0
{
104
0
    switch (mxLineDist->get_active())
105
0
    {
106
0
        case LLINESPACE_1:
107
0
            mxSpacing1Button->grab_focus();
108
0
            break;
109
0
        case LLINESPACE_115:
110
0
            mxSpacing115Button->grab_focus();
111
0
            break;
112
0
        case LLINESPACE_15:
113
0
            mxSpacing15Button->grab_focus();
114
0
            break;
115
0
        case LLINESPACE_2:
116
0
            mxSpacing2Button->grab_focus();
117
0
            break;
118
0
        default:
119
0
            mxLineDist->grab_focus();
120
0
            break;
121
0
    }
122
0
}
123
124
ParaLineSpacingControl::~ParaLineSpacingControl()
125
0
{
126
0
}
127
128
void ParaLineSpacingControl::Initialize()
129
0
{
130
0
    SfxPoolItemHolder aResult;
131
0
    SfxViewFrame* pCurrent = SfxViewFrame::Current();
132
0
    const bool bItemStateSet(nullptr != pCurrent);
133
0
    const SfxItemState eState(bItemStateSet
134
0
        ? pCurrent->GetBindings().GetDispatcher()->QueryState(SID_ATTR_PARA_LINESPACE, aResult)
135
0
        : SfxItemState::DEFAULT);
136
137
0
    mxLineDist->set_sensitive(true);
138
139
0
    if( bItemStateSet && (eState == SfxItemState::DEFAULT || eState == SfxItemState::SET) )
140
0
    {
141
0
        const SvxLineSpacingItem* currSPItem(static_cast<const SvxLineSpacingItem*>(aResult.getItem()));
142
        // It seems draw/impress and writer require different MapUnit values for fixed line spacing
143
        // metric values to be correctly calculated.
144
0
        MapUnit eUnit = MapUnit::Map100thMM; // works for draw/impress
145
0
        if (vcl::CommandInfoProvider::GetModuleIdentifier(pCurrent->GetFrame().GetFrameInterface())
146
0
                == "com.sun.star.text.TextDocument")
147
0
            eUnit = MapUnit::MapTwip; // works for writer
148
0
        meLNSpaceUnit = eUnit;
149
150
0
        switch( currSPItem->GetLineSpaceRule() )
151
0
        {
152
0
        case SvxLineSpaceRule::Auto:
153
0
            {
154
0
                SvxInterLineSpaceRule eInter = currSPItem->GetInterLineSpaceRule();
155
156
0
                switch( eInter )
157
0
                {
158
0
                case SvxInterLineSpaceRule::Off:
159
0
                    SelectEntryPos(LLINESPACE_1);
160
0
                    break;
161
162
0
                case SvxInterLineSpaceRule::Prop:
163
0
                    {
164
0
                        if ( LINESPACE_1 == currSPItem->GetPropLineSpace() )
165
0
                        {
166
0
                            SelectEntryPos(LLINESPACE_1);
167
0
                        }
168
0
                        else if ( LINESPACE_115 == currSPItem->GetPropLineSpace() )
169
0
                        {
170
0
                            SelectEntryPos(LLINESPACE_115);
171
0
                        }
172
0
                        else if ( LINESPACE_15 == currSPItem->GetPropLineSpace() )
173
0
                        {
174
0
                            SelectEntryPos(LLINESPACE_15);
175
0
                        }
176
0
                        else if ( LINESPACE_2 == currSPItem->GetPropLineSpace() )
177
0
                        {
178
0
                            SelectEntryPos(LLINESPACE_2);
179
0
                        }
180
0
                        else
181
0
                        {
182
0
                            SelectEntryPos(LLINESPACE_PROP);
183
0
                            mxLineDistAtPercentBox->set_value(mxLineDistAtPercentBox->normalize(currSPItem->GetPropLineSpace()), FieldUnit::PERCENT);
184
0
                        }
185
0
                    }
186
0
                    break;
187
188
0
                case SvxInterLineSpaceRule::Fix:
189
0
                    {
190
0
                        SelectEntryPos(LLINESPACE_DURCH);
191
0
                        SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetInterLineSpace(), eUnit);
192
0
                    }
193
0
                    break;
194
0
                default:
195
0
                    break;
196
0
                }
197
0
            }
198
0
            break;
199
0
        case SvxLineSpaceRule::Fix:
200
0
            {
201
0
                SelectEntryPos(LLINESPACE_FIX);
202
0
                SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetLineHeight(), eUnit);
203
0
            }
204
0
            break;
205
206
0
        case SvxLineSpaceRule::Min:
207
0
            {
208
0
                SelectEntryPos(LLINESPACE_MIN);
209
0
                SetMetricValue(*mxLineDistAtMetricBox, currSPItem->GetLineHeight(), eUnit);
210
0
            }
211
0
            break;
212
0
        default:
213
0
            break;
214
0
        }
215
0
    }
216
0
    else if( bItemStateSet && eState == SfxItemState::DISABLED )
217
0
    {
218
0
        mxLineDist->set_sensitive(false);
219
0
        mxLineDistLabel->set_sensitive(false);
220
0
        mpActLineDistFld->set_sensitive(false);
221
0
        mpActLineDistFld->set_text(u""_ustr);
222
223
0
    }
224
0
    else // !bItemStateSet || eState == SfxItemState::INVALID || eState == SfxItemState::UNKNOWN
225
0
    {
226
0
        mxLineDistLabel->set_sensitive(false);
227
0
        mpActLineDistFld->set_sensitive(false);
228
0
        mpActLineDistFld->set_text(u""_ustr);
229
0
        mxLineDist->set_active(-1);
230
0
    }
231
232
0
    mxLineDist->save_value();
233
0
}
234
235
void ParaLineSpacingControl::UpdateMetricFields()
236
0
{
237
0
    switch (mxLineDist->get_active())
238
0
    {
239
0
        case LLINESPACE_1:
240
0
        case LLINESPACE_115:
241
0
        case LLINESPACE_15:
242
0
        case LLINESPACE_2:
243
0
            if (mpActLineDistFld == mxLineDistAtPercentBox.get())
244
0
                mxLineDistAtMetricBox->hide();
245
0
            else
246
0
                mxLineDistAtPercentBox->hide();
247
248
0
            mxLineDistLabel->set_sensitive(false);
249
0
            mpActLineDistFld->show();
250
0
            mpActLineDistFld->set_sensitive(false);
251
0
            mpActLineDistFld->set_text(u""_ustr);
252
0
            break;
253
254
0
        case LLINESPACE_DURCH:
255
0
            mxLineDistAtPercentBox->hide();
256
257
0
            mpActLineDistFld = mxLineDistAtMetricBox.get();
258
0
            mxLineDistAtMetricBox->set_min(0, FieldUnit::NONE);
259
260
0
            if (mxLineDistAtMetricBox->get_text().isEmpty())
261
0
                mxLineDistAtMetricBox->set_value(mxLineDistAtMetricBox->normalize(0), FieldUnit::NONE);
262
263
0
            mxLineDistLabel->set_sensitive(true);
264
0
            mpActLineDistFld->show();
265
0
            mpActLineDistFld->set_sensitive(true);
266
0
            break;
267
268
0
        case LLINESPACE_MIN:
269
0
            mxLineDistAtPercentBox->hide();
270
271
0
            mpActLineDistFld = mxLineDistAtMetricBox.get();
272
0
            mxLineDistAtMetricBox->set_min(0, FieldUnit::NONE);
273
274
0
            if (mxLineDistAtMetricBox->get_text().isEmpty())
275
0
                mxLineDistAtMetricBox->set_value(mxLineDistAtMetricBox->normalize(0), FieldUnit::TWIP);
276
277
0
            mxLineDistLabel->set_sensitive(true);
278
0
            mpActLineDistFld->show();
279
0
            mpActLineDistFld->set_sensitive(true);
280
0
            break;
281
282
0
        case LLINESPACE_PROP:
283
0
            mxLineDistAtMetricBox->hide();
284
285
0
            mpActLineDistFld = mxLineDistAtPercentBox.get();
286
287
0
            if (mxLineDistAtPercentBox->get_text().isEmpty())
288
0
                mxLineDistAtPercentBox->set_value(mxLineDistAtPercentBox->normalize(100), FieldUnit::TWIP);
289
290
0
            mxLineDistLabel->set_sensitive(true);
291
0
            mpActLineDistFld->show();
292
0
            mpActLineDistFld->set_sensitive(true);
293
0
            break;
294
295
0
        case LLINESPACE_FIX:
296
0
            mxLineDistAtPercentBox->hide();
297
298
0
            mpActLineDistFld = mxLineDistAtMetricBox.get();
299
0
            sal_Int64 nTemp = mxLineDistAtMetricBox->get_value(FieldUnit::NONE);
300
0
            mxLineDistAtMetricBox->set_min(mxLineDistAtMetricBox->normalize(MIN_FIXED_DISTANCE), FieldUnit::TWIP);
301
302
0
            if (mxLineDistAtMetricBox->get_value(FieldUnit::NONE) != nTemp)
303
0
                SetMetricValue(*mxLineDistAtMetricBox, FIX_DIST_DEF, MapUnit::MapTwip);
304
305
0
            mxLineDistLabel->set_sensitive(true);
306
0
            mpActLineDistFld->show();
307
0
            mpActLineDistFld->set_sensitive(true);
308
0
            break;
309
0
    }
310
0
}
311
312
void ParaLineSpacingControl::SelectEntryPos(sal_Int32 nPos)
313
0
{
314
0
    mxLineDist->set_active(nPos);
315
0
    UpdateMetricFields();
316
0
}
317
318
IMPL_LINK_NOARG(ParaLineSpacingControl, LineSPDistHdl_Impl, weld::ComboBox&, void)
319
0
{
320
0
    UpdateMetricFields();
321
0
    ExecuteLineSpace();
322
0
}
323
324
IMPL_LINK_NOARG( ParaLineSpacingControl, LineSPDistAtHdl_Impl, weld::MetricSpinButton&, void )
325
0
{
326
0
    ExecuteLineSpace();
327
0
}
328
329
void ParaLineSpacingControl::ExecuteLineSpace()
330
0
{
331
0
    mxLineDist->save_value();
332
333
0
    SvxLineSpacingItem aSpacing(DEFAULT_LINE_SPACING, SID_ATTR_PARA_LINESPACE);
334
0
    const sal_Int32 nPos = mxLineDist->get_active();
335
336
0
    switch ( nPos )
337
0
    {
338
0
        case LLINESPACE_1:
339
0
        case LLINESPACE_115:
340
0
        case LLINESPACE_15:
341
0
        case LLINESPACE_2:
342
0
            SetLineSpace(aSpacing, nPos);
343
0
            break;
344
345
0
        case LLINESPACE_PROP:
346
0
            SetLineSpace(aSpacing, nPos, mxLineDistAtPercentBox->denormalize(static_cast<tools::Long>(mxLineDistAtPercentBox->get_value(FieldUnit::PERCENT))));
347
0
            break;
348
349
0
        case LLINESPACE_MIN:
350
0
        case LLINESPACE_DURCH:
351
0
        case LLINESPACE_FIX:
352
0
            SetLineSpace(aSpacing, nPos, GetCoreValue(*mxLineDistAtMetricBox, meLNSpaceUnit));
353
0
            break;
354
355
0
        default:
356
0
            break;
357
0
    }
358
359
0
    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
360
0
    {
361
0
        pViewFrm->GetBindings().GetDispatcher()->ExecuteList(
362
0
            SID_ATTR_PARA_LINESPACE, SfxCallMode::RECORD, { &aSpacing });
363
0
    }
364
0
}
365
366
void ParaLineSpacingControl::SetLineSpace(SvxLineSpacingItem& rLineSpace, sal_Int32 eSpace, tools::Long lValue)
367
0
{
368
0
    switch ( eSpace )
369
0
    {
370
0
        case LLINESPACE_1:
371
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
372
0
            rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
373
0
            break;
374
375
0
        case LLINESPACE_115:
376
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
377
0
            rLineSpace.SetPropLineSpace( LINESPACE_115 );
378
0
            break;
379
380
0
        case LLINESPACE_15:
381
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
382
0
            rLineSpace.SetPropLineSpace( LINESPACE_15 );
383
0
            break;
384
385
0
        case LLINESPACE_2:
386
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
387
0
            rLineSpace.SetPropLineSpace( LINESPACE_2 );
388
0
            break;
389
390
0
        case LLINESPACE_PROP:
391
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
392
0
            rLineSpace.SetPropLineSpace( static_cast<sal_uInt16>(lValue) );
393
0
            break;
394
395
0
        case LLINESPACE_MIN:
396
0
            rLineSpace.SetLineHeight( static_cast<sal_uInt16>(lValue) );
397
0
            rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
398
0
            break;
399
400
0
        case LLINESPACE_DURCH:
401
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Auto );
402
0
            rLineSpace.SetInterLineSpace( static_cast<sal_uInt16>(lValue) );
403
0
            break;
404
405
0
        case LLINESPACE_FIX:
406
0
            rLineSpace.SetLineHeight(static_cast<sal_uInt16>(lValue));
407
0
            rLineSpace.SetLineSpaceRule( SvxLineSpaceRule::Fix );
408
0
            rLineSpace.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
409
0
        break;
410
0
    }
411
0
}
412
413
IMPL_LINK(ParaLineSpacingControl, PredefinedValuesHandler, weld::Button&, rControl, void)
414
0
{
415
0
    if (&rControl == mxSpacing1Button.get())
416
0
    {
417
0
        ExecuteLineSpacing(LLINESPACE_1);
418
0
    }
419
0
    else if (&rControl == mxSpacing115Button.get())
420
0
    {
421
0
        ExecuteLineSpacing(LLINESPACE_115);
422
0
    }
423
0
    else if (&rControl == mxSpacing15Button.get())
424
0
    {
425
0
        ExecuteLineSpacing(LLINESPACE_15);
426
0
    }
427
0
    else if (&rControl == mxSpacing2Button.get())
428
0
    {
429
0
        ExecuteLineSpacing(LLINESPACE_2);
430
0
    }
431
0
}
432
433
void ParaLineSpacingControl::ExecuteLineSpacing(sal_Int32 nEntry)
434
0
{
435
0
    SvxLineSpacingItem aSpacing(DEFAULT_LINE_SPACING, SID_ATTR_PARA_LINESPACE);
436
437
0
    SetLineSpace(aSpacing, nEntry);
438
439
0
    if (SfxViewFrame* pViewFrm = SfxViewFrame::Current())
440
0
    {
441
0
        pViewFrm->GetBindings().GetDispatcher()->ExecuteList(
442
0
            SID_ATTR_PARA_LINESPACE, SfxCallMode::RECORD, { &aSpacing });
443
0
    }
444
445
    // close when the user used the buttons
446
0
    mxControl->EndPopupMode();
447
0
}
448
449
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */