Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/tbxctrls/colrctrl.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 <sal/config.h>
21
22
#include <sot/exchange.hxx>
23
#include <svx/strings.hrc>
24
#include <svx/svxids.hrc>
25
26
#include <sfx2/viewsh.hxx>
27
#include <sfx2/objsh.hxx>
28
#include <sfx2/dispatch.hxx>
29
#include <sfx2/viewfrm.hxx>
30
#include <vcl/image.hxx>
31
#include <vcl/transfer.hxx>
32
#include <vcl/weld/Builder.hxx>
33
#include <vcl/weld/ScrolledWindow.hxx>
34
35
#include <colrctrl.hxx>
36
37
#include <svx/svdview.hxx>
38
#include <svx/drawitem.hxx>
39
#include <svx/xfillit0.hxx>
40
#include <svx/xflclit.hxx>
41
#include <editeng/colritem.hxx>
42
#include <svx/xlineit0.hxx>
43
#include <svx/xlnclit.hxx>
44
#include <svx/dialmgr.hxx>
45
#include <helpids.h>
46
#include <vcl/virdev.hxx>
47
48
#include <com/sun/star/beans/NamedValue.hpp>
49
50
using namespace com::sun::star;
51
52
class SvxColorValueSetData final : public TransferDataContainer
53
{
54
private:
55
    uno::Sequence<beans::NamedValue> m_Data;
56
57
    virtual void AddSupportedFormats() override;
58
    virtual bool GetData(const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc) override;
59
60
public:
61
    SvxColorValueSetData()
62
0
    {
63
0
    }
64
65
    void SetData(const uno::Sequence<beans::NamedValue>& rData)
66
0
    {
67
0
        m_Data = rData;
68
0
        ClearFormats(); // invalidate m_aAny so new data will take effect
69
0
    }
70
};
71
72
void SvxColorValueSetData::AddSupportedFormats()
73
0
{
74
0
    AddFormat( SotClipboardFormatId::XFA );
75
0
}
76
77
bool SvxColorValueSetData::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
78
0
{
79
0
    bool bRet = false;
80
81
0
    if( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::XFA )
82
0
    {
83
0
        SetAny(uno::Any(m_Data));
84
0
        bRet = true;
85
0
    }
86
87
0
    return bRet;
88
0
}
89
90
void SvxColorValueSet_docking::SetDrawingArea(weld::DrawingArea* pDrawingArea)
91
0
{
92
0
    SvxColorValueSet::SetDrawingArea(pDrawingArea);
93
0
    SetAccessibleName(SvxResId(STR_COLORTABLE));
94
0
    SetStyle(GetStyle() | WB_ITEMBORDER);
95
96
0
    m_xHelper.set(new SvxColorValueSetData);
97
0
    rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
98
0
    SetDragDataTransferable(xHelper, DND_ACTION_COPY);
99
0
}
100
101
SvxColorValueSet_docking::SvxColorValueSet_docking(std::unique_ptr<weld::ScrolledWindow> xWindow)
102
0
    : SvxColorValueSet(std::move(xWindow))
103
0
    , mbLeftButton(true)
104
0
{
105
0
}
106
107
bool SvxColorValueSet_docking::MouseButtonDown( const MouseEvent& rMEvt )
108
0
{
109
0
    bool bRet;
110
111
    // For Mac still handle differently!
112
0
    if( rMEvt.IsLeft() )
113
0
    {
114
0
        mbLeftButton = true;
115
0
        bRet = SvxColorValueSet::MouseButtonDown( rMEvt );
116
0
    }
117
0
    else
118
0
    {
119
0
        mbLeftButton = false;
120
0
        MouseEvent aMEvt( rMEvt.GetPosPixel(),
121
0
                          rMEvt.GetClicks(),
122
0
                          rMEvt.GetMode(),
123
0
                          MOUSE_LEFT,
124
0
                          rMEvt.GetModifier() );
125
0
        bRet = SvxColorValueSet::MouseButtonDown( aMEvt );
126
0
    }
127
128
0
    return bRet;
129
0
}
130
131
bool SvxColorValueSet_docking::MouseButtonUp( const MouseEvent& rMEvt )
132
0
{
133
0
    bool bRet;
134
135
    // For Mac still handle differently!
136
0
    if( rMEvt.IsLeft() )
137
0
    {
138
0
        mbLeftButton = true;
139
0
        bRet = SvxColorValueSet::MouseButtonUp( rMEvt );
140
0
    }
141
0
    else
142
0
    {
143
0
        mbLeftButton = false;
144
0
        MouseEvent aMEvt( rMEvt.GetPosPixel(),
145
0
                          rMEvt.GetClicks(),
146
0
                          rMEvt.GetMode(),
147
0
                          MOUSE_LEFT,
148
0
                          rMEvt.GetModifier() );
149
0
        bRet = SvxColorValueSet::MouseButtonUp( aMEvt );
150
0
    }
151
0
    SetNoSelection();
152
153
0
    return bRet;
154
0
}
155
156
bool SvxColorValueSet_docking::StartDrag()
157
0
{
158
0
    sal_uInt16 nPos = GetSelectedItemId();
159
0
    Color aItemColor( GetItemColor( nPos ) );
160
0
    OUString sItemText( GetItemText( nPos ) );
161
162
0
    drawing::FillStyle eStyle = (nPos == GetItemCount())
163
0
                            ? drawing::FillStyle_NONE
164
0
                            : drawing::FillStyle_SOLID;
165
166
0
    XFillColorItem const color(sItemText, aItemColor);
167
0
    XFillStyleItem const style(eStyle);
168
0
    uno::Any c, s;
169
0
    color.QueryValue(c, 0);
170
0
    style.QueryValue(s, 0);
171
172
0
    uno::Sequence<beans::NamedValue> props{ { u"FillColor"_ustr, std::move(c) },
173
0
                                            { u"FillStyle"_ustr, std::move(s) } };
174
0
    m_xHelper->SetData(props);
175
176
0
    return false;
177
0
}
178
179
constexpr sal_uInt16 gnLeftSlot = SID_ATTR_FILL_COLOR;
180
constexpr sal_uInt16 gnRightSlot = SID_ATTR_LINE_COLOR;
181
182
SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings* _pBindings, SfxChildWindow* pCW, vcl::Window* _pParent)
183
0
    : SfxDockingWindow(_pBindings, pCW, _pParent,
184
0
        u"DockingColorWindow"_ustr, u"svx/ui/dockingcolorwindow.ui"_ustr)
185
0
    , xColorSet(new SvxColorValueSet_docking(m_xBuilder->weld_scrolled_window(u"valuesetwin"_ustr, true)))
186
0
    , xColorSetWin(new weld::CustomWeld(*m_xBuilder, u"valueset"_ustr, *xColorSet))
187
0
{
188
0
    SetText(SvxResId(STR_COLORTABLE));
189
0
    SetQuickHelpText(SvxResId(RID_SVXSTR_COLORBAR));
190
0
    SetSizePixel(LogicToPixel(Size(150, 22), MapMode(MapUnit::MapAppFont)));
191
0
    SetHelpId(HID_CTRL_COLOR);
192
193
0
    xColorSet->SetSelectHdl( LINK( this, SvxColorDockingWindow, SelectHdl ) );
194
0
    xColorSet->SetHelpId(HID_COLOR_CTL_COLORS);
195
196
    // Get the model from the view shell.  Using SfxObjectShell::Current()
197
    // is unreliable when called at the wrong times.
198
0
    SfxObjectShell* pDocSh = nullptr;
199
0
    if (_pBindings != nullptr)
200
0
    {
201
0
        SfxDispatcher* pDispatcher = _pBindings->GetDispatcher();
202
0
        if (pDispatcher != nullptr)
203
0
        {
204
0
            SfxViewFrame* pFrame = pDispatcher->GetFrame();
205
0
            if (pFrame != nullptr)
206
0
            {
207
0
                SfxViewShell* pViewShell = pFrame->GetViewShell();
208
0
                if (pViewShell != nullptr)
209
0
                    pDocSh = pViewShell->GetObjectShell();
210
0
            }
211
0
        }
212
0
    }
213
214
0
    if ( pDocSh )
215
0
    {
216
0
        if (const SvxColorListItem*  pItem = pDocSh->GetItem( SID_COLOR_TABLE ))
217
0
        {
218
0
            pColorList = pItem->GetColorList();
219
0
            FillValueSet();
220
0
        }
221
0
    }
222
223
0
    Size aItemSize = xColorSet->CalcItemSizePixel(Size(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength()));
224
0
    aItemSize.setWidth( aItemSize.Width() + SvxColorValueSet::getEntryEdgeLength() );
225
0
    aItemSize.setWidth( aItemSize.Width() / 2 );
226
0
    aItemSize.setHeight( aItemSize.Height() + SvxColorValueSet::getEntryEdgeLength() );
227
0
    aItemSize.setHeight( aItemSize.Height() / 2 );
228
229
0
    if (_pBindings != nullptr)
230
0
        StartListening(*_pBindings, DuplicateHandling::Prevent);
231
0
}
Unexecuted instantiation: SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*)
Unexecuted instantiation: SvxColorDockingWindow::SvxColorDockingWindow(SfxBindings*, SfxChildWindow*, vcl::Window*)
232
233
SvxColorDockingWindow::~SvxColorDockingWindow()
234
0
{
235
0
    disposeOnce();
236
0
}
237
238
void SvxColorDockingWindow::dispose()
239
0
{
240
0
    EndListening( GetBindings() );
241
0
    xColorSetWin.reset();
242
0
    xColorSet.reset();
243
0
    SfxDockingWindow::dispose();
244
0
}
245
246
void SvxColorDockingWindow::Notify( SfxBroadcaster& , const SfxHint& rHint )
247
0
{
248
0
    if (rHint.GetId() == SfxHintId::PoolItem)
249
0
    {
250
0
        const SfxPoolItemHint* pPoolItemHint = static_cast<const SfxPoolItemHint*>(&rHint);
251
0
        if (auto pColorListItem = dynamic_cast<const SvxColorListItem*>(pPoolItemHint->GetObject()))
252
0
        {
253
            // The list of colors has changed
254
0
            pColorList = pColorListItem->GetColorList();
255
0
            FillValueSet();
256
0
        }
257
0
    }
258
0
}
259
260
void SvxColorDockingWindow::FillValueSet()
261
0
{
262
0
    if( !pColorList.is() )
263
0
        return;
264
265
0
    xColorSet->Clear();
266
267
0
    xColorSet->addEntriesForXColorList(*pColorList);
268
269
    // create the last entry for 'invisible/none'
270
0
    const Size aColorSize(SvxColorValueSet::getEntryEdgeLength(), SvxColorValueSet::getEntryEdgeLength());
271
0
    tools::Long nPtX = aColorSize.Width() - 1;
272
0
    tools::Long nPtY = aColorSize.Height() - 1;
273
0
    ScopedVclPtrInstance< VirtualDevice > pVD;
274
275
0
    pVD->SetOutputSizePixel( aColorSize );
276
0
    pVD->SetLineColor( COL_BLACK );
277
0
    pVD->SetBackground( Wallpaper( COL_WHITE ) );
278
0
    pVD->DrawLine( Point(), Point( nPtX, nPtY ) );
279
0
    pVD->DrawLine( Point( 0, nPtY ), Point( nPtX, 0 ) );
280
281
0
    Bitmap aBmp( pVD->GetBitmap( Point(), aColorSize ) );
282
283
0
    xColorSet->InsertItem(xColorSet->GetItemCount() + 1, Image(aBmp), SvxResId(RID_SVXSTR_INVISIBLE));
284
0
}
285
286
bool SvxColorDockingWindow::Close()
287
0
{
288
0
    SfxBoolItem aItem( SID_COLOR_CONTROL, false );
289
0
    GetBindings().GetDispatcher()->ExecuteList(SID_COLOR_CONTROL,
290
0
            SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem });
291
0
    SfxDockingWindow::Close();
292
0
    return true;
293
0
}
294
295
IMPL_LINK_NOARG(SvxColorDockingWindow, SelectHdl, ValueSet*, void)
296
0
{
297
0
    SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();
298
0
    sal_uInt16 nPos = xColorSet->GetSelectedItemId();
299
0
    Color  aColor( xColorSet->GetItemColor( nPos ) );
300
0
    OUString aStr( xColorSet->GetItemText( nPos ) );
301
302
    // ID of 'invisible/none' entry, see SvxColorDockingWindow::FillValueSet
303
0
    const sal_uInt16 nIdNone = xColorSet->GetItemCount();
304
0
    if (xColorSet->IsLeftButton())
305
0
    {
306
0
        if ( gnLeftSlot == SID_ATTR_FILL_COLOR )
307
0
        {
308
0
            if (nPos == nIdNone)
309
0
            {
310
0
                XFillStyleItem aXFillStyleItem( drawing::FillStyle_NONE );
311
0
                pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
312
0
                        { &aXFillStyleItem });
313
0
            }
314
0
            else
315
0
            {
316
0
                bool bDone = false;
317
318
                // If we have a DrawView and we are in TextEdit mode, then
319
                // not the area color but the text color is assigned
320
0
                SfxViewShell* pViewSh = SfxViewShell::Current();
321
0
                if ( pViewSh )
322
0
                {
323
0
                    SdrView* pView = pViewSh->GetDrawView();
324
0
                    if ( pView && pView->IsTextEdit() )
325
0
                    {
326
0
                        SvxColorItem aTextColorItem( aColor, SID_ATTR_CHAR_COLOR );
327
0
                        pDispatcher->ExecuteList(SID_ATTR_CHAR_COLOR,
328
0
                                SfxCallMode::RECORD, { &aTextColorItem });
329
0
                        bDone = true;
330
0
                    }
331
0
                }
332
0
                if ( !bDone )
333
0
                {
334
0
                    XFillStyleItem aXFillStyleItem( drawing::FillStyle_SOLID );
335
0
                    XFillColorItem aXFillColorItem( aStr, aColor );
336
0
                    pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
337
0
                            { &aXFillColorItem, &aXFillStyleItem });
338
0
                }
339
0
            }
340
0
        }
341
0
        else if (nPos != nIdNone)
342
0
        {
343
0
            SvxColorItem aLeftColorItem( aColor, gnLeftSlot );
344
0
            pDispatcher->ExecuteList(gnLeftSlot, SfxCallMode::RECORD,
345
0
                    { &aLeftColorItem });
346
0
        }
347
0
    }
348
0
    else
349
0
    {
350
0
        if ( gnRightSlot == SID_ATTR_LINE_COLOR )
351
0
        {
352
0
            if (nPos == nIdNone)
353
0
            {
354
0
                XLineStyleItem aXLineStyleItem( drawing::LineStyle_NONE );
355
0
                pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
356
0
                        { &aXLineStyleItem });
357
0
            }
358
0
            else
359
0
            {
360
                // If the LineStyle is invisible, it is set to SOLID
361
0
                SfxViewShell* pViewSh = SfxViewShell::Current();
362
0
                if ( pViewSh )
363
0
                {
364
0
                    SdrView* pView = pViewSh->GetDrawView();
365
0
                    if ( pView )
366
0
                    {
367
0
                        SfxItemSet aAttrSet(pView->GetModel().GetItemPool());
368
0
                        pView->GetAttributes( aAttrSet );
369
0
                        if ( aAttrSet.GetItemState( XATTR_LINESTYLE ) != SfxItemState::INVALID )
370
0
                        {
371
0
                            drawing::LineStyle eXLS =
372
0
                                aAttrSet.Get( XATTR_LINESTYLE ).GetValue();
373
0
                            if ( eXLS == drawing::LineStyle_NONE )
374
0
                            {
375
0
                                XLineStyleItem aXLineStyleItem( drawing::LineStyle_SOLID );
376
0
                                pDispatcher->ExecuteList(gnRightSlot,
377
0
                                    SfxCallMode::RECORD, { &aXLineStyleItem });
378
0
                            }
379
0
                        }
380
0
                    }
381
0
                }
382
383
0
                XLineColorItem aXLineColorItem( aStr, aColor );
384
0
                pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
385
0
                        { &aXLineColorItem });
386
0
            }
387
0
        }
388
0
        else if (nPos != nIdNone)
389
0
        {
390
0
            SvxColorItem aRightColorItem( aColor, gnRightSlot );
391
0
            pDispatcher->ExecuteList(gnRightSlot, SfxCallMode::RECORD,
392
0
                    { &aRightColorItem });
393
0
        }
394
0
    }
395
0
}
396
397
void SvxColorDockingWindow::GetFocus()
398
0
{
399
0
    SfxDockingWindow::GetFocus();
400
0
    if (xColorSet)
401
0
    {
402
        // Grab the focus to the color value set so that it can be controlled
403
        // with the keyboard.
404
0
        xColorSet->GrabFocus();
405
0
    }
406
0
}
407
408
bool SvxColorDockingWindow::EventNotify( NotifyEvent& rNEvt )
409
0
{
410
0
    bool bRet = false;
411
0
    if( rNEvt.GetType() == NotifyEventType::KEYINPUT )
412
0
    {
413
0
        KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
414
0
        sal_uInt16   nKeyCode = aKeyEvt.GetKeyCode().GetCode();
415
0
        switch( nKeyCode )
416
0
        {
417
0
            case KEY_ESCAPE:
418
0
                GrabFocusToDocument();
419
0
                bRet = true;
420
0
                break;
421
0
        }
422
0
    }
423
424
0
    return bRet || SfxDockingWindow::EventNotify(rNEvt);
425
0
}
426
427
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */