Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/tbxctrls/fontworkgallery.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
21
#include <com/sun/star/text/WritingMode.hpp>
22
23
#include <comphelper/lok.hxx>
24
#include <comphelper/propertyvalue.hxx>
25
#include <comphelper/servicehelper.hxx>
26
#include <comphelper/processfactory.hxx>
27
#include <com/sun/star/frame/ModuleManager.hpp>
28
29
#include <o3tl/untaint.hxx>
30
#include <vcl/toolbox.hxx>
31
#include <vcl/virdev.hxx>
32
#include <vcl/weld/Builder.hxx>
33
#include <vcl/weld/CheckButton.hxx>
34
#include <vcl/weld/Dialog.hxx>
35
#include <vcl/weld/RadioButton.hxx>
36
#include <vcl/weld/Toolbar.hxx>
37
38
#include <sfx2/viewsh.hxx>
39
40
#include <svl/itempool.hxx>
41
42
#include <svtools/toolbarmenu.hxx>
43
#include <svtools/popupwindowcontroller.hxx>
44
45
#include <svx/fmmodel.hxx>
46
#include <svx/svdpage.hxx>
47
#include <svx/svdobj.hxx>
48
#include <svx/svdview.hxx>
49
50
#include <svx/gallery.hxx>
51
#include <svx/fontworkgallery.hxx>
52
53
#include <tools/UnitConversion.hxx>
54
55
#include <memory>
56
57
#include <svx/strings.hrc>
58
#include <svx/dialmgr.hxx>
59
60
using namespace ::com::sun::star::uno;
61
using namespace ::com::sun::star::beans;
62
63
namespace svx
64
{
65
66
FontWorkGalleryDialog::FontWorkGalleryDialog(weld::Window* pParent, SdrView& rSdrView,
67
                                             Reference<css::frame::XFrame> xFrame)
68
0
    : GenericDialogController(pParent, u"svx/ui/fontworkgallerydialog.ui"_ustr, u"FontworkGalleryDialog"_ustr)
69
0
    , mnThemeId(0xffff)
70
0
    , mrSdrView(rSdrView)
71
0
    , mbInsertIntoPage(true)
72
0
    , mpDestModel(nullptr)
73
0
    , maCtlFavorites(m_xBuilder->weld_icon_view(u"ctlFavoriteswin"_ustr))
74
0
    , mxOKButton(m_xBuilder->weld_button(u"ok"_ustr))
75
0
    , mxFrame(std::move(xFrame))
76
0
{
77
0
    Size aSize(530, 400);
78
0
    maCtlFavorites->set_size_request(aSize.Width(), aSize.Height());
79
80
0
    maCtlFavorites->connect_item_activated( LINK( this, FontWorkGalleryDialog, DoubleClickFavoriteHdl ) );
81
0
    mxOKButton->connect_clicked(LINK(this, FontWorkGalleryDialog, ClickOKHdl));
82
83
0
    initFavorites( GALLERY_THEME_FONTWORK );
84
0
    fillFavorites( GALLERY_THEME_FONTWORK );
85
0
}
86
87
FontWorkGalleryDialog::~FontWorkGalleryDialog()
88
0
{
89
0
}
90
91
void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId)
92
0
{
93
    // the favorites are read via the gallery
94
0
    sal_uInt32 nFavCount = GalleryExplorer::GetSdrObjCount( nThemeId );
95
96
    // lock gallery theme
97
0
    GalleryExplorer::BeginLocking(nThemeId);
98
99
0
    sal_uInt32 nModelPos;
100
0
    FmFormModel *pModel = nullptr;
101
102
0
    for( nModelPos = 0; nModelPos < nFavCount; nModelPos++ )
103
0
    {
104
0
        Bitmap aThumb;
105
106
0
        if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty())
107
0
        {
108
0
            ScopedVclPtrInstance< VirtualDevice > pVDev;
109
0
            const Point aNull(0, 0);
110
111
0
            if (pVDev->GetDPIScaleFactor() > 1)
112
0
                aThumb.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
113
114
0
            const Size aSize(aThumb.GetSizePixel());
115
116
0
            pVDev->SetOutputSizePixel(aSize);
117
118
0
            static const sal_uInt32 nLen(8);
119
0
            static const Color aW(COL_WHITE);
120
0
            static const Color aG(0xef, 0xef, 0xef);
121
122
0
            pVDev->DrawCheckered(aNull, aSize, nLen, aW, aG);
123
124
0
            pVDev->DrawBitmap(aNull, aThumb);
125
0
            maFavoritesHorizontal.emplace_back(pVDev->GetBitmap(Point(0,0), aSize));
126
0
        }
127
0
    }
128
129
    // release gallery theme
130
0
    GalleryExplorer::EndLocking(nThemeId);
131
0
}
132
133
void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId)
134
0
{
135
0
    mnThemeId = nThemeId;
136
137
0
    auto nFavCount = maFavoritesHorizontal.size();
138
139
0
    maCtlFavorites->clear();
140
141
0
    std::vector<OUString> aTitles;
142
0
    (void)GalleryExplorer::FillObjListTitle(nThemeId, aTitles);
143
0
    assert(aTitles.size() == nFavCount);
144
145
0
    for (size_t nIndex = 0; nIndex < nFavCount; nIndex++)
146
0
    {
147
0
        OUString sId = OUString::number(static_cast<sal_uInt16>(nIndex + 1));
148
0
        const OUString sTitle = aTitles.at(nIndex);
149
0
        maCtlFavorites->insert(-1, nullptr, &sId, &maFavoritesHorizontal[nIndex], nullptr);
150
0
        maCtlFavorites->set_item_accessible_name(nIndex, sTitle);
151
0
        maCtlFavorites->set_item_tooltip_text(nIndex, sTitle);
152
0
    }
153
154
0
    if (maCtlFavorites->n_children())
155
0
        maCtlFavorites->select(0);
156
0
}
157
158
void FontWorkGalleryDialog::SetSdrObjectRef( SdrModel* pModel)
159
0
{
160
0
    mbInsertIntoPage = false;
161
0
    mpDestModel = pModel;
162
0
}
163
164
void FontWorkGalleryDialog::insertSelectedFontwork()
165
0
{
166
0
    OUString sItemId = maCtlFavorites->get_selected_id();
167
0
    if (sItemId.isEmpty())
168
0
        return;
169
170
0
    sal_Int32 nItemId = sItemId.toInt32();
171
172
0
    if (nItemId == 0)
173
0
        return;
174
175
0
    FmFormModel aModel;
176
177
0
    if( !GalleryExplorer::GetSdrObj( mnThemeId, nItemId-1, &aModel ) )
178
0
        return;
179
180
0
    SdrPage* pPage = aModel.GetPage(0);
181
0
    if( !(pPage && pPage->GetObjCount()) )
182
0
        return;
183
184
    // tdf#116993 Calc uses a 'special' mode for this dialog in being the
185
    // only caller of ::SetSdrObjectRef. Only in that case mpDestModel seems
186
    // to be the correct target SdrModel.
187
    // If this is not used, the correct SdrModel seems to be the one from
188
    // the mrSdrView that is used to insert (InsertObjectAtView below) the
189
    // cloned SdrObject.
190
0
    const bool bUseSpecialCalcMode(!mbInsertIntoPage && nullptr != mpDestModel);
191
192
    // center shape on current view
193
0
    OutputDevice* pOutDev(mrSdrView.GetFirstOutputDevice());
194
195
0
    if (!pOutDev)
196
0
        return;
197
198
    // Clone directly to target SdrModel (may be different due to user/caller (!))
199
0
    rtl::Reference<SdrObject> xNewObject(
200
0
        pPage->GetObj(0)->CloneSdrObject(
201
0
            bUseSpecialCalcMode ? *mpDestModel : mrSdrView.getSdrModelFromSdrView()));
202
203
0
    const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
204
0
    css::uno::Reference<css::frame::XModuleManager> xModuleManager =
205
0
            css::frame::ModuleManager::create(xContext);
206
0
    OUString aModuleIdentifier = xModuleManager->identify(mxFrame);
207
208
0
    if (aModuleIdentifier != "com.sun.star.drawing.DrawingDocument"  &&
209
0
        aModuleIdentifier != "com.sun.star.presentation.PresentationDocument" )
210
0
    {
211
0
        xNewObject->SetName(SvxResId(STR_ObjNameSingulFONTWORK) + u" 1");
212
0
        xNewObject->MakeNameUnique();
213
0
    }
214
0
    else
215
0
        xNewObject->SetName(OUString());
216
217
    // tdf#117629
218
    // Since the 'old' ::CloneSdrObject also copies the SdrPage* the
219
    // SdrObject::getUnoShape() *will* create the wrong UNO API object
220
    // early. This IS one of the reasons I do change these things - this
221
    // error does not happen with my next change I am working on already
222
    // ARGH! For now, reset the SdrPage* to nullptr.
223
    // What sense does it have to copy the SdrPage* of the original SdrObject ?!?
224
    // TTTT: This also *might* be the hidden reason for the strange code at the
225
    // end of SdrObject::SetPage that tries to delete the SvxShape under some
226
    // circumstances...
227
    // xNewObject->SetPage(nullptr);
228
229
0
    tools::Rectangle aObjRect( xNewObject->GetLogicRect() );
230
0
    Point aPagePos;
231
0
    Size aFontworkSize = aObjRect.GetSize();
232
233
0
    SfxViewShell* pKitViewShell = comphelper::LibreOfficeKit::isActive() ?
234
0
        SfxViewShell::Current() : nullptr;
235
0
    if (pKitViewShell)
236
0
    {
237
0
        aPagePos = convertTwipToMm100(pKitViewShell->getLOKVisibleArea().Center());
238
239
0
        sal_Int32 nLOKViewWidth = 0.8 * convertTwipToMm100(pKitViewShell->getLOKVisibleArea().getOpenWidth());
240
0
        if (aFontworkSize.getWidth() > nLOKViewWidth)
241
0
        {
242
0
            double fScale = static_cast<double>(aFontworkSize.getWidth()) / nLOKViewWidth;
243
0
            aFontworkSize.setWidth(aFontworkSize.getWidth() / fScale);
244
0
            aFontworkSize.setHeight(aFontworkSize.getHeight() / fScale);
245
0
        }
246
0
    }
247
0
    else
248
0
    {
249
0
        Size aSize = pOutDev->GetOutputSizePixel();
250
0
        tools::Rectangle aPixelVisRect(Point(0,0), aSize);
251
0
        tools::Rectangle aVisArea = pOutDev->PixelToLogic(aPixelVisRect);
252
253
0
        aPagePos = aVisArea.Center();
254
0
    }
255
256
0
    if (aPagePos.getX() > aFontworkSize.getWidth() / 2)
257
0
        aPagePos.AdjustX( -(aFontworkSize.getWidth() / 2) );
258
0
    if (aPagePos.getY() > aFontworkSize.getHeight() / 2)
259
0
        aPagePos.AdjustY( -(aFontworkSize.getHeight() / 2) );
260
261
0
    tools::Rectangle aNewObjectRectangle(aPagePos, aFontworkSize);
262
0
    xNewObject->SetLogicRect(aNewObjectRectangle);
263
264
0
    if (bUseSpecialCalcMode)
265
0
    {
266
0
        mxSdrObject = std::move(xNewObject);
267
0
    }
268
0
    else
269
0
    {
270
0
        SdrPageView* pPV(mrSdrView.GetSdrPageView());
271
272
0
        if (nullptr != pPV)
273
0
        {
274
0
            mrSdrView.InsertObjectAtView( xNewObject.get(), *pPV );
275
0
        }
276
0
    }
277
0
}
278
279
IMPL_LINK_NOARG(FontWorkGalleryDialog, ClickOKHdl, weld::Button&, void)
280
0
{
281
0
    insertSelectedFontwork();
282
0
    m_xDialog->response(RET_OK);
283
0
}
284
285
IMPL_LINK_NOARG(FontWorkGalleryDialog, DoubleClickFavoriteHdl, const weld::TreeIter&, bool)
286
0
{
287
0
    insertSelectedFontwork();
288
0
    m_xDialog->response(RET_OK);
289
0
    return true;
290
0
}
291
292
namespace {
293
294
class FontworkAlignmentWindow final : public WeldToolbarPopup
295
{
296
public:
297
    FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
298
    virtual void GrabFocus() override
299
0
    {
300
0
        mxLeft->grab_focus();
301
0
    }
302
    virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
303
304
private:
305
    rtl::Reference<svt::PopupWindowController> mxControl;
306
    std::unique_ptr<weld::RadioButton> mxLeft;
307
    std::unique_ptr<weld::RadioButton> mxCenter;
308
    std::unique_ptr<weld::RadioButton> mxRight;
309
    std::unique_ptr<weld::RadioButton> mxStretch;
310
    bool mbSettingValue;
311
312
    DECL_LINK( SelectHdl, weld::Toggleable&, void );
313
314
    void    implSetAlignment( int nAlignmentMode, bool bEnabled );
315
};
316
317
}
318
319
constexpr OUString gsFontworkAlignment(u".uno:FontworkAlignment"_ustr);
320
321
FontworkAlignmentWindow::FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
322
0
    : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/fontworkalignmentcontrol.ui"_ustr, u"FontworkAlignmentControl"_ustr)
323
0
    , mxControl(pControl)
324
0
    , mxLeft(m_xBuilder->weld_radio_button(u"left"_ustr))
325
0
    , mxCenter(m_xBuilder->weld_radio_button(u"center"_ustr))
326
0
    , mxRight(m_xBuilder->weld_radio_button(u"right"_ustr))
327
0
    , mxStretch(m_xBuilder->weld_radio_button(u"stretch"_ustr))
328
0
    , mbSettingValue(false)
329
0
{
330
0
    mxLeft->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
331
0
    mxCenter->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
332
0
    mxRight->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
333
0
    mxStretch->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
334
335
0
    AddStatusListener( gsFontworkAlignment );
336
0
}
337
338
void FontworkAlignmentWindow::implSetAlignment( int nSurface, bool bEnabled )
339
0
{
340
0
    bool bSettingValue = mbSettingValue;
341
0
    mbSettingValue = true;
342
0
    mxLeft->set_active(nSurface == 0 && bEnabled);
343
0
    mxLeft->set_sensitive(bEnabled);
344
0
    mxCenter->set_active(nSurface == 1 && bEnabled);
345
0
    mxCenter->set_sensitive(bEnabled);
346
0
    mxRight->set_active(nSurface == 2 && bEnabled);
347
0
    mxRight->set_sensitive(bEnabled);
348
    //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
349
    //mxWord->set_active(nSurface == 3 && bEnabled);
350
    //mxWord->set_sensitive(bEnabled);
351
0
    mxStretch->set_active(nSurface == 4 && bEnabled);
352
0
    mxStretch->set_sensitive(bEnabled);
353
0
    mbSettingValue = bSettingValue;
354
0
}
355
356
void FontworkAlignmentWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
357
0
{
358
0
    if( Event.FeatureURL.Main != gsFontworkAlignment )
359
0
        return;
360
361
0
    if( !Event.IsEnabled )
362
0
    {
363
0
        implSetAlignment( 0, false );
364
0
    }
365
0
    else
366
0
    {
367
0
        sal_Int32 nValue = 0;
368
0
        if( Event.State >>= nValue )
369
0
            implSetAlignment( nValue, true );
370
0
    }
371
0
}
372
373
IMPL_LINK(FontworkAlignmentWindow, SelectHdl, weld::Toggleable&, rButton, void)
374
0
{
375
0
    if (mbSettingValue || !rButton.get_active())
376
0
        return;
377
378
0
    sal_Int32 nAlignment;
379
0
    if (mxLeft->get_active())
380
0
        nAlignment = 0;
381
0
    else if (mxCenter->get_active())
382
0
        nAlignment = 1;
383
0
    else if (mxRight->get_active())
384
0
        nAlignment = 2;
385
    //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
386
    //else if (mxWord->get_active())
387
    //    nAlignment = 3;
388
0
    else
389
0
        nAlignment = 4;
390
391
0
    Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
392
0
        gsFontworkAlignment.copy(5), nAlignment) };
393
394
0
    mxControl->dispatchCommand( gsFontworkAlignment, aArgs );
395
396
0
    implSetAlignment( nAlignment, true );
397
398
0
    mxControl->EndPopupMode();
399
0
}
400
401
namespace {
402
403
class FontworkAlignmentControl : public svt::PopupWindowController
404
{
405
public:
406
    explicit FontworkAlignmentControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
407
408
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
409
    virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
410
411
    // XInitialization
412
    virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
413
414
    // XServiceInfo
415
    virtual OUString SAL_CALL getImplementationName() override;
416
    virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
417
};
418
419
}
420
421
FontworkAlignmentControl::FontworkAlignmentControl( const Reference< XComponentContext >& rxContext )
422
0
: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), u".uno:FontworkAlignment"_ustr )
423
0
{
424
0
}
425
426
std::unique_ptr<WeldToolbarPopup> FontworkAlignmentControl::weldPopupWindow()
427
0
{
428
0
    return std::make_unique<FontworkAlignmentWindow>(this, m_pToolbar);
429
0
}
430
431
VclPtr<vcl::Window> FontworkAlignmentControl::createVclPopupWindow( vcl::Window* pParent )
432
0
{
433
0
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
434
0
        std::make_unique<FontworkAlignmentWindow>(this, pParent->GetFrameWeld()));
435
436
0
    mxInterimPopover->Show();
437
438
0
    return mxInterimPopover;
439
0
}
440
441
// XInitialization
442
void SAL_CALL FontworkAlignmentControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
443
0
{
444
0
    svt::PopupWindowController::initialize( aArguments );
445
446
0
    if (m_pToolbar)
447
0
    {
448
0
        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
449
0
        m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
450
0
    }
451
452
0
    ToolBox* pToolBox = nullptr;
453
0
    ToolBoxItemId nId;
454
0
    if ( getToolboxId( nId, &pToolBox ) )
455
0
        pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
456
0
}
457
458
// XServiceInfo
459
460
461
OUString FontworkAlignmentControl::getImplementationName()
462
0
{
463
0
    return u"com.sun.star.comp.svx.FontworkAlignmentController"_ustr;
464
0
}
465
466
467
Sequence< OUString > FontworkAlignmentControl::getSupportedServiceNames()
468
0
{
469
0
    return { u"com.sun.star.frame.ToolbarController"_ustr };
470
0
}
471
472
473
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
474
com_sun_star_comp_svx_FontworkAlignmentControl_get_implementation(
475
    css::uno::XComponentContext* xContext,
476
    css::uno::Sequence<css::uno::Any> const &)
477
0
{
478
0
    return cppu::acquire(new FontworkAlignmentControl(xContext));
479
0
}
480
481
namespace {
482
483
class FontworkCharacterSpacingWindow final : public WeldToolbarPopup
484
{
485
public:
486
    FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
487
    virtual void GrabFocus() override;
488
489
    virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
490
private:
491
    rtl::Reference<svt::PopupWindowController> mxControl;
492
    std::unique_ptr<weld::RadioButton> mxVeryTight;
493
    std::unique_ptr<weld::RadioButton> mxTight;
494
    std::unique_ptr<weld::RadioButton> mxNormal;
495
    std::unique_ptr<weld::RadioButton> mxLoose;
496
    std::unique_ptr<weld::RadioButton> mxVeryLoose;
497
    std::unique_ptr<weld::RadioButton> mxCustom;
498
    std::unique_ptr<weld::CheckButton> mxKernPairs;
499
    sal_Int32 mnCharacterSpacing;
500
    bool mbSettingValue;
501
    bool mbCommandDispatched;
502
503
    DECL_LINK( KernSelectHdl, weld::Toggleable&, void );
504
    DECL_LINK( SelectHdl, weld::Toggleable&, void );
505
    DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool );
506
507
    void    implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled );
508
    void    implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled);
509
    void    DispatchSpacingDialog();
510
};
511
512
}
513
514
constexpr OUString gsFontworkCharacterSpacing(u".uno:FontworkCharacterSpacing"_ustr);
515
constexpr OUString gsFontworkKernCharacterPairs(u".uno:FontworkKernCharacterPairs"_ustr);
516
517
FontworkCharacterSpacingWindow::FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
518
0
    : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/fontworkcharacterspacingcontrol.ui"_ustr, u"FontworkCharacterSpacingControl"_ustr)
519
0
    , mxControl(pControl)
520
0
    , mxVeryTight(m_xBuilder->weld_radio_button(u"verytight"_ustr))
521
0
    , mxTight(m_xBuilder->weld_radio_button(u"tight"_ustr))
522
0
    , mxNormal(m_xBuilder->weld_radio_button(u"normal"_ustr))
523
0
    , mxLoose(m_xBuilder->weld_radio_button(u"loose"_ustr))
524
0
    , mxVeryLoose(m_xBuilder->weld_radio_button(u"veryloose"_ustr))
525
0
    , mxCustom(m_xBuilder->weld_radio_button(u"custom"_ustr))
526
0
    , mxKernPairs(m_xBuilder->weld_check_button(u"kernpairs"_ustr))
527
0
    , mnCharacterSpacing(0)
528
0
    , mbSettingValue(false)
529
0
    , mbCommandDispatched(false)
530
0
{
531
0
    mxVeryTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
532
0
    mxTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
533
0
    mxNormal->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
534
0
    mxLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
535
0
    mxVeryLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
536
0
    mxCustom->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
537
0
    mxCustom->connect_mouse_release(LINK(this, FontworkCharacterSpacingWindow, MouseReleaseHdl));
538
539
0
    mxKernPairs->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, KernSelectHdl));
540
541
0
    AddStatusListener( gsFontworkCharacterSpacing );
542
0
    AddStatusListener( gsFontworkKernCharacterPairs );
543
544
    // See TODO in svx/source/toolbars/fontworkbar.cxx for SID_FONTWORK_KERN_CHARACTER_PAIRS,
545
    // the kernpairs setting is ignored, so hide the widget entirely
546
0
    mxKernPairs->hide();
547
0
}
548
549
void FontworkCharacterSpacingWindow::GrabFocus()
550
0
{
551
0
    mxVeryTight->grab_focus();
552
0
}
553
554
void FontworkCharacterSpacingWindow::implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled )
555
0
{
556
0
    bool bSettingValue = mbSettingValue;
557
0
    mbSettingValue = true;
558
559
0
    mxVeryTight->set_sensitive(bEnabled);
560
0
    mxTight->set_sensitive(bEnabled);
561
0
    mxNormal->set_sensitive(bEnabled);
562
0
    mxLoose->set_sensitive(bEnabled);
563
0
    mxVeryLoose->set_sensitive(bEnabled);
564
0
    mxCustom->set_sensitive(bEnabled);
565
566
0
    mxVeryTight->set_active(false);
567
0
    mxTight->set_active(false);
568
0
    mxNormal->set_active(false);
569
0
    mxLoose->set_active(false);
570
0
    mxVeryLoose->set_active(false);
571
0
    mxCustom->set_active(true);
572
573
0
    switch(nCharacterSpacing)
574
0
    {
575
0
        case 80:
576
0
            mxVeryTight->set_active(true);
577
0
            break;
578
0
        case 90:
579
0
            mxTight->set_active(true);
580
0
            break;
581
0
        case 100:
582
0
            mxNormal->set_active(true);
583
0
            break;
584
0
        case 120:
585
0
            mxLoose->set_active(true);
586
0
            break;
587
0
        case 150:
588
0
            mxVeryLoose->set_active(true);
589
0
            break;
590
0
    }
591
592
0
    mnCharacterSpacing = nCharacterSpacing;
593
594
0
    mbSettingValue = bSettingValue;
595
0
}
596
597
void FontworkCharacterSpacingWindow::implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled)
598
0
{
599
0
    mxKernPairs->set_sensitive(bEnabled);
600
0
    mxKernPairs->set_active(bKernOnOff);
601
0
}
602
603
void FontworkCharacterSpacingWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
604
0
{
605
0
    if( Event.FeatureURL.Main == gsFontworkCharacterSpacing )
606
0
    {
607
0
        if( !Event.IsEnabled )
608
0
        {
609
0
            implSetCharacterSpacing( 0, false );
610
0
        }
611
0
        else
612
0
        {
613
0
            sal_Int32 nValue = 0;
614
0
            if( Event.State >>= nValue )
615
0
                implSetCharacterSpacing( nValue, true );
616
0
        }
617
0
    }
618
0
    else if( Event.FeatureURL.Main == gsFontworkKernCharacterPairs )
619
0
    {
620
0
        if( !Event.IsEnabled )
621
0
        {
622
0
            implSetKernCharacterPairs(false, false);
623
0
        }
624
0
        else
625
0
        {
626
0
            bool bValue = false;
627
0
            if( Event.State >>= bValue )
628
0
                implSetKernCharacterPairs(bValue, true);
629
0
        }
630
0
    }
631
0
}
632
633
IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, KernSelectHdl, weld::Toggleable&, void)
634
0
{
635
0
    if (mbSettingValue)
636
0
        return;
637
638
0
    bool bKernOnOff = mxKernPairs->get_active();
639
0
    Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
640
0
        gsFontworkKernCharacterPairs.copy(5), bKernOnOff) };
641
642
0
    mxControl->dispatchCommand( gsFontworkKernCharacterPairs, aArgs );
643
0
    mbCommandDispatched = true;
644
645
0
    implSetKernCharacterPairs(bKernOnOff, true);
646
647
0
    mxControl->EndPopupMode();
648
0
}
649
650
void FontworkCharacterSpacingWindow::DispatchSpacingDialog()
651
0
{
652
0
    Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
653
0
        gsFontworkCharacterSpacing.copy(5), mnCharacterSpacing) };
654
655
0
    rtl::Reference<svt::PopupWindowController> xControl(mxControl);
656
0
    xControl->EndPopupMode();
657
0
    xControl->dispatchCommand(u".uno:FontworkCharacterSpacingDialog"_ustr, aArgs);
658
0
    mbCommandDispatched = true;
659
0
}
660
661
IMPL_LINK(FontworkCharacterSpacingWindow, SelectHdl, weld::Toggleable&, rButton, void)
662
0
{
663
0
    if (!rButton.get_active())
664
0
        return;
665
666
0
    if (mbSettingValue)
667
0
        return;
668
669
    // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee
670
    // this toggle will happen before that mouse release though it does in
671
    // practice for vcl and gtk
672
0
    if (mbCommandDispatched)
673
0
        return;
674
675
0
    if (mxCustom->get_active())
676
0
        DispatchSpacingDialog();
677
0
    else
678
0
    {
679
0
        sal_Int32 nCharacterSpacing;
680
0
        if (mxVeryTight->get_active())
681
0
            nCharacterSpacing = 80;
682
0
        else if (mxTight->get_active())
683
0
            nCharacterSpacing = 90;
684
0
        else if (mxLoose->get_active())
685
0
            nCharacterSpacing = 120;
686
0
        else if (mxVeryLoose->get_active())
687
0
            nCharacterSpacing = 150;
688
0
        else
689
0
            nCharacterSpacing = 100;
690
691
0
        Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
692
0
            gsFontworkCharacterSpacing.copy(5), nCharacterSpacing) };
693
694
0
        mxControl->dispatchCommand( gsFontworkCharacterSpacing,  aArgs );
695
0
        mbCommandDispatched = true;
696
697
0
        implSetCharacterSpacing( nCharacterSpacing, true );
698
0
    }
699
700
0
    mxControl->EndPopupMode();
701
0
}
702
703
IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, MouseReleaseHdl, const MouseEvent&, bool)
704
0
{
705
    /*
706
     tdf#145296 if the "custom" radiobutton was presented preselected as
707
     toggled on and the user clicked on it then there's no toggled signal sent
708
     because the item was already toggled on and didn't change state.
709
710
     So if that happens launch the custom spacing dialog explicitly here on
711
     mouse release.
712
    */
713
0
    if (mxCustom->get_active() && !mbCommandDispatched)
714
0
    {
715
0
        DispatchSpacingDialog();
716
0
        return true;
717
0
    }
718
0
    return false;
719
0
}
720
721
namespace {
722
723
class FontworkCharacterSpacingControl : public svt::PopupWindowController
724
{
725
public:
726
    explicit FontworkCharacterSpacingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
727
728
    virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
729
    virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
730
731
    // XInitialization
732
    virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
733
734
    // XServiceInfo
735
    virtual OUString SAL_CALL getImplementationName() override;
736
    virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
737
};
738
739
}
740
741
FontworkCharacterSpacingControl::FontworkCharacterSpacingControl( const Reference< XComponentContext >& rxContext )
742
0
: svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), u".uno:FontworkCharacterSpacingFloater"_ustr )
743
0
{
744
0
}
745
746
std::unique_ptr<WeldToolbarPopup> FontworkCharacterSpacingControl::weldPopupWindow()
747
0
{
748
0
    return std::make_unique<FontworkCharacterSpacingWindow>(this, m_pToolbar);
749
0
}
750
751
VclPtr<vcl::Window> FontworkCharacterSpacingControl::createVclPopupWindow( vcl::Window* pParent )
752
0
{
753
0
    mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
754
0
        std::make_unique<FontworkCharacterSpacingWindow>(this, pParent->GetFrameWeld()));
755
756
0
    mxInterimPopover->Show();
757
758
0
    return mxInterimPopover;
759
0
}
760
761
// XInitialization
762
void SAL_CALL FontworkCharacterSpacingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
763
0
{
764
0
    svt::PopupWindowController::initialize( aArguments );
765
766
0
    if (m_pToolbar)
767
0
    {
768
0
        mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
769
0
        m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
770
0
    }
771
772
0
    ToolBox* pToolBox = nullptr;
773
0
    ToolBoxItemId nId;
774
0
    if ( getToolboxId( nId, &pToolBox ) )
775
0
        pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
776
0
}
777
778
// XServiceInfo
779
780
781
OUString FontworkCharacterSpacingControl::getImplementationName()
782
0
{
783
0
    return u"com.sun.star.comp.svx.FontworkCharacterSpacingController"_ustr;
784
0
}
785
786
787
Sequence< OUString > FontworkCharacterSpacingControl::getSupportedServiceNames()
788
0
{
789
0
    Sequence<OUString> aSNS { u"com.sun.star.frame.ToolbarController"_ustr };
790
0
    return aSNS;
791
0
}
792
793
794
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
795
com_sun_star_comp_svx_FontworkCharacterSpacingControl_get_implementation(
796
    css::uno::XComponentContext* xContext,
797
    css::uno::Sequence<css::uno::Any> const &)
798
0
{
799
0
    return cppu::acquire(new FontworkCharacterSpacingControl(xContext));
800
0
}
801
802
FontworkCharacterSpacingDialog::FontworkCharacterSpacingDialog(weld::Window* pParent, sal_Int32 nScale)
803
0
    : GenericDialogController(pParent, u"svx/ui/fontworkspacingdialog.ui"_ustr, u"FontworkSpacingDialog"_ustr)
804
0
    , m_xMtrScale(m_xBuilder->weld_metric_spin_button(u"entry"_ustr, FieldUnit::PERCENT))
805
0
{
806
0
    m_xMtrScale->set_value(nScale, FieldUnit::PERCENT);
807
0
}
808
809
FontworkCharacterSpacingDialog::~FontworkCharacterSpacingDialog()
810
0
{
811
0
}
812
813
sal_Int32 FontworkCharacterSpacingDialog::getScale() const
814
0
{
815
0
    sal_Int64 ret = m_xMtrScale->get_value(FieldUnit::PERCENT);
816
0
    o3tl::untaint_for_overrun(ret);
817
0
    return static_cast<sal_Int32>(ret);
818
0
}
819
820
}
821
822
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */