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