Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svtools/source/control/valueset.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 <o3tl/safeint.hxx>
23
#include <basegfx/matrix/b2dhommatrix.hxx>
24
#include <basegfx/polygon/b2dpolygontools.hxx>
25
#include <tools/debug.hxx>
26
#include <vcl/bitmap.hxx>
27
#include <vcl/canvastools.hxx>
28
#include <vcl/decoview.hxx>
29
#include <vcl/event.hxx>
30
#include <vcl/svapp.hxx>
31
#include <vcl/settings.hxx>
32
#include <vcl/virdev.hxx>
33
#include <vcl/lineinfo.hxx>
34
#include <vcl/weld/ScrolledWindow.hxx>
35
36
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
37
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
38
#include <com/sun/star/lang/XComponent.hpp>
39
#include <rtl/ustring.hxx>
40
#include <sal/log.hxx>
41
#include "valueimp.hxx"
42
43
#include <svtools/valueset.hxx>
44
45
#include <uiobject.hxx>
46
#include <vcl/uitest/logger.hxx>
47
#include <vcl/uitest/eventdescription.hxx>
48
49
using namespace css::uno;
50
using namespace css::accessibility;
51
52
namespace
53
{
54
void collectUIInformation( const OUString& aID , const OUString& aParentID , const OUString& aPos )
55
0
{
56
0
    EventDescription aDescription;
57
0
    aDescription.aID = aID ;
58
0
    aDescription.aParameters = {{"POS", aPos }};
59
0
    aDescription.aAction = "SELECT";
60
0
    aDescription.aKeyWord = "ValueSet";
61
0
    aDescription.aParent = aParentID;
62
0
    UITestLogger::getInstance().logEvent(aDescription);
63
0
}
64
65
enum
66
{
67
    ITEM_OFFSET = 4,
68
    ITEM_OFFSET_DOUBLE = 6,
69
    NAME_LINE_OFF_X = 2,
70
    NAME_LINE_OFF_Y = 2,
71
    NAME_LINE_HEIGHT = 2,
72
    NAME_OFFSET = 2,
73
};
74
75
}
76
77
ValueSet::ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
78
0
    : maVirDev( VclPtr<VirtualDevice>::Create(DeviceFormat::WITH_ALPHA))
79
0
    , mxScrolledWindow(std::move(pScrolledWindow))
80
0
    , mnHighItemId(0)
81
0
    , maColor(COL_TRANSPARENT)
82
0
    , mnStyle(0)
83
0
    , mbFormat(true)
84
0
    , mbHighlight(false)
85
0
{
86
0
    mnItemWidth         = 0;
87
0
    mnItemHeight        = 0;
88
0
    mnTextOffset        = 0;
89
0
    mnVisLines          = 0;
90
0
    mnLines             = 0;
91
0
    mnUserItemWidth     = 0;
92
0
    mnUserItemHeight    = 0;
93
0
    mnFirstLine         = 0;
94
0
    mnSelItemId         = 0;
95
0
    mnSavedItemId       = -1;
96
0
    mnCols              = 0;
97
0
    mnCurCol            = 0;
98
0
    mnUserCols          = 0;
99
0
    mnUserVisLines      = 0;
100
0
    mnSpacing           = 0;
101
0
    mnMargin            = 0;
102
0
    mnFrameStyle        = DrawFrameStyle::NONE;
103
0
    mbNoSelection       = true;
104
0
    mbDoubleSel         = false;
105
0
    mbFullMode          = true;
106
0
    mbEdgeBlending      = false;
107
0
    mbHasVisibleItems   = false;
108
109
0
    if (mxScrolledWindow)
110
0
        mxScrolledWindow->connect_vadjustment_value_changed(LINK(this, ValueSet, ImplScrollHdl));
111
0
}
112
113
void ValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
114
0
{
115
0
    CustomWidgetController::SetDrawingArea(pDrawingArea);
116
    // #106446#, #106601# force mirroring of virtual device
117
0
    maVirDev->EnableRTL(pDrawingArea->get_direction());
118
0
}
119
120
rtl::Reference<comphelper::OAccessible> ValueSet::CreateAccessible()
121
0
{
122
0
    if (!mxAccessible)
123
0
        mxAccessible.set(new ValueSetAcc(this));
124
0
    return mxAccessible;
125
0
}
126
127
ValueSet::~ValueSet()
128
0
{
129
0
    ImplDeleteItems();
130
131
0
    if (mxAccessible)
132
0
        mxAccessible->Invalidate();
133
0
}
134
135
void ValueSet::ImplDeleteItems()
136
0
{
137
0
    const size_t n = mItemList.size();
138
139
0
    for ( size_t i = 0; i < n; ++i )
140
0
    {
141
0
        if (ValueSetItem* pItem = mItemList[i].get())
142
0
        {
143
0
            rtl::Reference<ValueItemAcc> xItemAcc = pItem->GetAccessible(false);
144
0
            if (xItemAcc.is())
145
0
            {
146
0
                Any aOldAny;
147
0
                Any aNewAny;
148
0
                aOldAny <<= Reference<XAccessible>(xItemAcc);
149
0
                ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
150
151
0
                xItemAcc->dispose();
152
0
            }
153
0
        }
154
155
0
        mItemList[i].reset();
156
0
    }
157
158
0
    mItemList.clear();
159
0
}
160
161
void ValueSet::Select()
162
0
{
163
0
    collectUIInformation(GetDrawingArea()->get_buildable_name() , GetDrawingArea()->get_help_id() , OUString::number(GetSelectedItemId()));
164
0
    maSelectHdl.Call( this );
165
0
}
166
167
void ValueSet::UserDraw( const UserDrawEvent& )
168
0
{
169
0
}
170
171
size_t ValueSet::ImplGetItem( const Point& rPos ) const
172
0
{
173
0
    if (!mbHasVisibleItems)
174
0
    {
175
0
        return VALUESET_ITEM_NOTFOUND;
176
0
    }
177
178
0
    if (maItemListRect.Contains(rPos))
179
0
    {
180
0
        const int xc = rPos.X() - maItemListRect.Left();
181
0
        const int yc = rPos.Y() - maItemListRect.Top();
182
        // The point is inside the area of item list,
183
        // let's find the containing item.
184
0
        const int col = xc / (mnItemWidth + mnSpacing);
185
0
        const int x = xc % (mnItemWidth + mnSpacing);
186
0
        const int row = yc / (mnItemHeight + mnSpacing);
187
0
        const int y = yc % (mnItemHeight + mnSpacing);
188
189
0
        if (x < mnItemWidth && y < mnItemHeight)
190
0
        {
191
            // the point is inside item rect and not inside spacing
192
0
            const size_t item = (mnFirstLine + row) * static_cast<size_t>(mnCols) + col;
193
0
            if (item < mItemList.size())
194
0
            {
195
0
                return item;
196
0
            }
197
0
        }
198
0
    }
199
200
0
    return VALUESET_ITEM_NOTFOUND;
201
0
}
202
203
ValueSetItem* ValueSet::ImplGetItem( size_t nPos )
204
0
{
205
0
    return (nPos < mItemList.size()) ? mItemList[nPos].get() : nullptr;
206
0
}
207
208
ValueSetItem* ValueSet::ImplGetFirstItem()
209
0
{
210
0
    return !mItemList.empty() ? mItemList[0].get() : nullptr;
211
0
}
212
213
sal_uInt16 ValueSet::ImplGetVisibleItemCount() const
214
0
{
215
0
    sal_uInt16 nRet = 0;
216
0
    const size_t nItemCount = mItemList.size();
217
218
0
    for ( size_t n = 0; n < nItemCount; ++n )
219
0
    {
220
0
        if ( mItemList[n]->mbVisible )
221
0
            ++nRet;
222
0
    }
223
224
0
    return nRet;
225
0
}
226
227
void ValueSet::ImplFireAccessibleEvent( short nEventId, const Any& rOldValue, const Any& rNewValue )
228
0
{
229
0
    if( mxAccessible )
230
0
        mxAccessible->FireAccessibleEvent( nEventId, rOldValue, rNewValue );
231
0
}
232
233
bool ValueSet::ImplHasAccessibleListeners() const
234
0
{
235
0
    return mxAccessible && mxAccessible->HasAccessibleListeners();
236
0
}
237
238
IMPL_LINK(ValueSet, ImplScrollHdl, weld::ScrolledWindow&, rScrollWin, void)
239
0
{
240
0
    auto nNewFirstLine = rScrollWin.vadjustment_get_value();
241
0
    if ( nNewFirstLine != mnFirstLine )
242
0
    {
243
0
        mnFirstLine = nNewFirstLine;
244
0
        mbFormat = true;
245
0
        Invalidate();
246
0
    }
247
0
}
248
249
void ValueSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
250
0
{
251
0
    rRenderContext.SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
252
0
    rRenderContext.Erase();
253
0
    ImplDraw(rRenderContext);
254
0
}
255
256
void ValueSet::GetFocus()
257
0
{
258
0
    SAL_INFO("svtools", "value set getting focus");
259
0
    Invalidate();
260
0
    CustomWidgetController::GetFocus();
261
262
    // Tell the accessible object that we got the focus.
263
0
    if (mxAccessible)
264
0
        mxAccessible->GetFocus();
265
0
}
266
267
void ValueSet::LoseFocus()
268
0
{
269
0
    SAL_INFO("svtools", "value set losing focus");
270
0
    Invalidate();
271
0
    CustomWidgetController::LoseFocus();
272
273
    // Tell the accessible object that we lost the focus.
274
0
    if( mxAccessible )
275
0
        mxAccessible->LoseFocus();
276
0
}
277
278
void ValueSet::Resize()
279
0
{
280
0
    mbFormat = true;
281
0
    if (IsReallyVisible())
282
0
        Invalidate();
283
0
    CustomWidgetController::Resize();
284
0
}
285
286
bool ValueSet::KeyInput( const KeyEvent& rKeyEvent )
287
0
{
288
0
    size_t nLastItem = mItemList.size();
289
290
0
    if ( !nLastItem || !ImplGetFirstItem() )
291
0
        return CustomWidgetController::KeyInput(rKeyEvent);
292
293
0
    if (mbFormat)
294
0
        Invalidate();
295
296
0
    --nLastItem;
297
298
0
    const size_t nCurPos
299
0
        = mnSelItemId ? GetItemPos(mnSelItemId) : 0;
300
0
    size_t nItemPos = VALUESET_ITEM_NOTFOUND;
301
0
    size_t nVStep = mnCols;
302
303
0
    switch (rKeyEvent.GetKeyCode().GetCode())
304
0
    {
305
0
        case KEY_HOME:
306
0
            nItemPos = 0;
307
0
            break;
308
309
0
        case KEY_END:
310
0
            nItemPos = nLastItem;
311
0
            break;
312
313
0
        case KEY_LEFT:
314
0
            if (nCurPos)
315
0
                nItemPos = nCurPos - 1;
316
0
            break;
317
318
0
        case KEY_RIGHT:
319
0
            if (nCurPos < nLastItem)
320
0
                nItemPos = nCurPos + 1;
321
0
            break;
322
323
0
        case KEY_PAGEUP:
324
0
            if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
325
0
            {
326
0
                return CustomWidgetController::KeyInput(rKeyEvent);
327
0
            }
328
0
            nVStep *= mnVisLines;
329
0
            [[fallthrough]];
330
0
        case KEY_UP:
331
0
            if (nCurPos == nLastItem)
332
0
            {
333
0
                const size_t nCol = mnCols ? nLastItem % mnCols : 0;
334
0
                if (nCol < mnCurCol)
335
0
                {
336
                    // Move to previous row/page, keeping the old column
337
0
                    nVStep -= mnCurCol - nCol;
338
0
                }
339
0
            }
340
0
            if (nCurPos >= nVStep)
341
0
            {
342
                // Go up of a whole page
343
0
                nItemPos = nCurPos - nVStep;
344
0
            }
345
0
            else if (nCurPos > mnCols)
346
0
            {
347
                // Go to same column in first row
348
0
                nItemPos = nCurPos % mnCols;
349
0
            }
350
0
            break;
351
352
0
        case KEY_PAGEDOWN:
353
0
            if (rKeyEvent.GetKeyCode().IsShift() || rKeyEvent.GetKeyCode().IsMod1() || rKeyEvent.GetKeyCode().IsMod2())
354
0
            {
355
0
                return CustomWidgetController::KeyInput(rKeyEvent);
356
0
            }
357
0
            nVStep *= mnVisLines;
358
0
            [[fallthrough]];
359
0
        case KEY_DOWN:
360
0
            if (nCurPos != nLastItem)
361
0
            {
362
0
                nItemPos = nCurPos + nVStep;
363
0
                if (nItemPos > nLastItem)
364
0
                {
365
0
                    nItemPos = nLastItem;
366
0
                }
367
0
            }
368
0
            break;
369
370
0
        case KEY_RETURN:
371
0
            if (GetStyle() & WB_NO_DIRECTSELECT)
372
0
            {
373
                // tdf#142479 on return select the entry the cursor is in
374
                // before calling Select
375
0
                const sal_uInt16 nItemId = GetItemId(nCurPos);
376
0
                if (nItemId != mnSelItemId)
377
0
                    SelectItem(nItemId);
378
0
                Select();
379
0
                break;
380
0
            }
381
0
            [[fallthrough]];
382
0
        default:
383
0
            return CustomWidgetController::KeyInput(rKeyEvent);
384
0
    }
385
386
0
    if ( nItemPos == VALUESET_ITEM_NOTFOUND )
387
0
        return true;
388
389
0
    if (nItemPos < nLastItem)
390
0
    {
391
        // update current column only in case of a new position
392
        // which is also not a "specially" handled one.
393
0
        mnCurCol = mnCols ? nItemPos % mnCols : 0;
394
0
    }
395
0
    const sal_uInt16 nItemId = GetItemId(nItemPos);
396
0
    if ( nItemId != mnSelItemId )
397
0
    {
398
0
        SelectItem( nItemId );
399
0
        if (!(GetStyle() & WB_NO_DIRECTSELECT))
400
0
        {
401
            // select only if WB_NO_DIRECTSELECT is not set
402
0
            Select();
403
0
        }
404
0
    }
405
406
0
    return true;
407
0
}
408
409
void ValueSet::ImplTracking(bool bLeaveWindow, const Point& rPos)
410
0
{
411
0
    if (GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET)
412
0
        mbHighlight = true;
413
414
0
    if (ValueSetItem* pItem = bLeaveWindow ? nullptr : ImplGetItem(ImplGetItem(rPos)))
415
0
        ImplHighlightItem(pItem->mnId);
416
0
    else
417
0
        ImplHighlightItem(0);
418
0
}
419
420
bool ValueSet::MouseButtonDown( const MouseEvent& rMouseEvent )
421
0
{
422
0
    if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2())
423
0
    {
424
0
        bool bConsumed = false;
425
0
        ValueSetItem* pItem = ImplGetItem( ImplGetItem( rMouseEvent.GetPosPixel() ) );
426
0
        if (rMouseEvent.GetClicks() == 1)
427
0
        {
428
0
            if (pItem)
429
0
                SelectItem(pItem->mnId);
430
0
            GrabFocus();
431
0
            bConsumed = true;
432
0
        }
433
0
        else if (pItem && rMouseEvent.GetClicks() == 2)
434
0
        {
435
0
            maDoubleClickHdl.Call(this);
436
0
            bConsumed = true;
437
0
        }
438
0
        return bConsumed;
439
0
    }
440
441
0
    return CustomWidgetController::MouseButtonDown( rMouseEvent );
442
0
}
443
444
bool ValueSet::MouseButtonUp( const MouseEvent& rMouseEvent )
445
0
{
446
0
    if (rMouseEvent.IsLeft() && !rMouseEvent.IsMod2())
447
0
    {
448
        // tdf#165881 MouseUp may be seen without previous MouseDown.  Select
449
        // what's under the mouse on mouse release when in menu-alike modes.
450
0
        const bool bMenuAlike = GetStyle() & WB_MENUSTYLEVALUESET || GetStyle() & WB_FLATVALUESET;
451
0
        if (bMenuAlike)
452
0
        {
453
0
            if (ValueSetItem* pItem = ImplGetItem(ImplGetItem(rMouseEvent.GetPosPixel())))
454
0
                SelectItem(pItem->mnId);
455
0
        }
456
457
        // tdf#142150 MouseUp seen without previous MouseDown
458
0
        if (mnSelItemId)
459
0
            Select();
460
0
        return true;
461
0
    }
462
463
0
    return CustomWidgetController::MouseButtonUp( rMouseEvent );
464
0
}
465
466
bool ValueSet::MouseMove(const MouseEvent& rMouseEvent)
467
0
{
468
    // because of SelectionMode
469
0
    if ((GetStyle() & WB_MENUSTYLEVALUESET) || (GetStyle() & WB_FLATVALUESET))
470
0
        ImplTracking(rMouseEvent.IsLeaveWindow(), rMouseEvent.GetPosPixel());
471
0
    return CustomWidgetController::MouseMove(rMouseEvent);
472
0
}
473
474
void ValueSet::QueueReformat()
475
0
{
476
0
    queue_resize();
477
0
    RecalcScrollBar();
478
0
    mbFormat = true;
479
0
    if (IsReallyVisible())
480
0
        Invalidate();
481
0
}
482
483
void ValueSet::RemoveItem( sal_uInt16 nItemId )
484
0
{
485
0
    size_t nPos = GetItemPos( nItemId );
486
487
0
    if ( nPos == VALUESET_ITEM_NOTFOUND )
488
0
        return;
489
490
0
    mItemList.erase( mItemList.begin() + nPos );
491
492
    // reset variables
493
0
    if (mnHighItemId == nItemId || mnSelItemId == nItemId)
494
0
    {
495
0
        mnCurCol        = 0;
496
0
        mnHighItemId    = 0;
497
0
        mnSelItemId     = 0;
498
0
        mbNoSelection   = true;
499
0
    }
500
501
0
    QueueReformat();
502
0
}
503
504
bool ValueSet::TurnOffScrollBar()
505
0
{
506
0
    if (mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
507
0
        return false;
508
0
    mxScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
509
0
    weld::DrawingArea* pDrawingArea = GetDrawingArea();
510
0
    Size aPrefSize(pDrawingArea->get_preferred_size());
511
0
    pDrawingArea->set_size_request(aPrefSize.Width() + GetScrollWidth(), aPrefSize.Height());
512
0
    return true;
513
0
}
514
515
void ValueSet::TurnOnScrollBar()
516
0
{
517
0
    if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
518
0
        return;
519
0
    mxScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
520
0
    weld::DrawingArea* pDrawingArea = GetDrawingArea();
521
0
    Size aPrefSize(pDrawingArea->get_preferred_size());
522
0
    pDrawingArea->set_size_request(aPrefSize.Width() - GetScrollWidth(), aPrefSize.Height());
523
0
}
524
525
void ValueSet::RecalcScrollBar()
526
0
{
527
0
    if (!mxScrolledWindow)
528
0
        return;
529
0
    const bool bScrollAllowed = GetStyle() & WB_VSCROLL;
530
0
    if (!bScrollAllowed)
531
0
        return;
532
    // reset scrolled window state to initial value so it will get configured
533
    // to the right adjustment on the next format which we toggle on to happen
534
    // if the scrolledwindow wasn't in its initial state already
535
0
    if (TurnOffScrollBar())
536
0
        mbFormat = true;
537
0
}
538
539
void ValueSet::Clear()
540
0
{
541
0
    ImplDeleteItems();
542
543
    // reset variables
544
0
    mnFirstLine     = 0;
545
0
    mnCurCol        = 0;
546
0
    mnHighItemId    = 0;
547
0
    mnSelItemId     = 0;
548
0
    mbNoSelection   = true;
549
550
0
    RecalcScrollBar();
551
552
0
    mbFormat = true;
553
0
    if (IsReallyVisible())
554
0
        Invalidate();
555
0
}
556
557
size_t ValueSet::GetItemCount() const
558
0
{
559
0
    return mItemList.size();
560
0
}
561
562
size_t ValueSet::GetItemPos( sal_uInt16 nItemId ) const
563
0
{
564
0
    for ( size_t i = 0, n = mItemList.size(); i < n; ++i ) {
565
0
        if ( mItemList[i]->mnId == nItemId ) {
566
0
            return i;
567
0
        }
568
0
    }
569
0
    return VALUESET_ITEM_NOTFOUND;
570
0
}
571
572
sal_uInt16 ValueSet::GetItemId( size_t nPos ) const
573
0
{
574
0
    return ( nPos < mItemList.size() ) ? mItemList[nPos]->mnId : 0 ;
575
0
}
576
577
sal_uInt16 ValueSet::GetItemId( const Point& rPos ) const
578
0
{
579
0
    size_t nItemPos = ImplGetItem( rPos );
580
0
    if ( nItemPos != VALUESET_ITEM_NOTFOUND )
581
0
        return GetItemId( nItemPos );
582
583
0
    return 0;
584
0
}
585
586
tools::Rectangle ValueSet::GetItemRect( sal_uInt16 nItemId ) const
587
0
{
588
0
    const size_t nPos = GetItemPos( nItemId );
589
590
0
    if ( nPos!=VALUESET_ITEM_NOTFOUND && mItemList[nPos]->mbVisible )
591
0
        return ImplGetItemRect( nPos );
592
593
0
    return tools::Rectangle();
594
0
}
595
596
tools::Rectangle ValueSet::ImplGetItemRect( size_t nPos ) const
597
0
{
598
0
    const size_t nVisibleBegin = static_cast<size_t>(mnFirstLine)*mnCols;
599
0
    const size_t nVisibleEnd = nVisibleBegin + static_cast<size_t>(mnVisLines)*mnCols;
600
601
    // Check if the item is inside the range of the displayed ones,
602
    // taking into account that last row could be incomplete
603
0
    if ( nPos<nVisibleBegin || nPos>=nVisibleEnd || nPos>=mItemList.size() )
604
0
        return tools::Rectangle();
605
606
0
    nPos -= nVisibleBegin;
607
608
0
    const size_t row = mnCols ? nPos/mnCols : 0;
609
0
    const size_t col = mnCols ? nPos%mnCols : 0;
610
0
    const tools::Long x = maItemListRect.Left()+col*(mnItemWidth+mnSpacing);
611
0
    const tools::Long y = maItemListRect.Top()+row*(mnItemHeight+mnSpacing);
612
613
0
    return tools::Rectangle( Point(x, y), Size(mnItemWidth, mnItemHeight) );
614
0
}
615
616
void ValueSet::ImplHighlightItem(sal_uInt16 nItemId)
617
0
{
618
0
    if ( mnHighItemId == nItemId )
619
0
        return;
620
621
    // remember the old item to delete the previous selection
622
0
    mnHighItemId = nItemId;
623
624
    // remove the old selection and draw the new one
625
0
    Invalidate();
626
0
}
627
628
void ValueSet::ImplDraw(vcl::RenderContext& rRenderContext)
629
0
{
630
0
    if (mbFormat)
631
0
        Format(rRenderContext);
632
633
0
    Point aDefPos;
634
0
    Size aSize = maVirDev->GetOutputSizePixel();
635
636
0
    rRenderContext.DrawOutDev(aDefPos, aSize, aDefPos, aSize, *maVirDev);
637
638
    // draw parting line to the Namefield
639
0
    if (GetStyle() & WB_NAMEFIELD)
640
0
    {
641
0
        if (!(GetStyle() & WB_FLATVALUESET))
642
0
        {
643
0
            const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
644
0
            Size aWinSize(GetOutputSizePixel());
645
0
            Point aPos1(NAME_LINE_OFF_X, mnTextOffset + NAME_LINE_OFF_Y);
646
0
            Point aPos2(aWinSize.Width() - (NAME_LINE_OFF_X * 2), mnTextOffset + NAME_LINE_OFF_Y);
647
0
            if (!(rStyleSettings.GetOptions() & StyleSettingsOptions::Mono))
648
0
            {
649
0
                rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
650
0
                rRenderContext.DrawLine(aPos1, aPos2);
651
0
                aPos1.AdjustY( 1 );
652
0
                aPos2.AdjustY( 1 );
653
0
                rRenderContext.SetLineColor(rStyleSettings.GetLightColor());
654
0
            }
655
0
            else
656
0
                rRenderContext.SetLineColor(rStyleSettings.GetWindowTextColor());
657
0
            rRenderContext.DrawLine(aPos1, aPos2);
658
0
        }
659
0
    }
660
661
0
    ImplDrawSelect(rRenderContext);
662
0
}
663
664
void ValueSet::SetFirstLine(sal_uInt16 nNewFirstLine)
665
0
{
666
0
    if (nNewFirstLine != mnFirstLine)
667
0
    {
668
0
        mnFirstLine = nNewFirstLine;
669
0
        if (mxScrolledWindow)
670
0
            mxScrolledWindow->vadjustment_set_value(mnFirstLine);
671
0
    }
672
0
}
673
674
void ValueSet::SelectItem( sal_uInt16 nItemId )
675
0
{
676
0
    size_t nItemPos = 0;
677
678
0
    if ( nItemId )
679
0
    {
680
0
        nItemPos = GetItemPos( nItemId );
681
0
        if ( nItemPos == VALUESET_ITEM_NOTFOUND )
682
0
            return;
683
0
    }
684
685
0
    if ( !((mnSelItemId != nItemId) || mbNoSelection) )
686
0
        return;
687
688
0
    const sal_uInt16 nOldItem = mnSelItemId;
689
0
    mnSelItemId = nItemId;
690
0
    mbNoSelection = false;
691
692
0
    bool bNewOut = !mbFormat && IsReallyVisible();
693
0
    bool bNewLine = false;
694
695
0
    if (weld::DrawingArea* pNeedsFormatToScroll = !mnCols ? GetDrawingArea() : nullptr)
696
0
    {
697
0
        Format(pNeedsFormatToScroll->get_ref_device());
698
        // reset scrollbar so it's set to the later calculated mnFirstLine on
699
        // the next Format
700
0
        RecalcScrollBar();
701
0
    }
702
703
    // if necessary scroll to the visible area
704
0
    if (nItemId && mnCols)
705
0
    {
706
0
        sal_uInt16 nNewLine = static_cast<sal_uInt16>(nItemPos / mnCols);
707
0
        if ( nNewLine < mnFirstLine )
708
0
        {
709
0
            SetFirstLine(nNewLine);
710
0
            bNewLine = true;
711
0
        }
712
0
        else if (mnFirstLine + mnVisLines - 1 >= 0
713
0
                 && nNewLine > o3tl::make_unsigned(mnFirstLine + mnVisLines - 1))
714
0
        {
715
0
            SetFirstLine(static_cast<sal_uInt16>(nNewLine-mnVisLines+1));
716
0
            bNewLine = true;
717
0
        }
718
0
    }
719
720
0
    if ( bNewOut )
721
0
    {
722
0
        if ( bNewLine )
723
0
        {
724
            // redraw everything if the visible area has changed
725
0
            mbFormat = true;
726
0
        }
727
0
        Invalidate();
728
0
    }
729
730
0
    if( !ImplHasAccessibleListeners() )
731
0
        return;
732
733
    // focus event (deselect)
734
0
    if( nOldItem )
735
0
    {
736
0
        const size_t nPos = GetItemPos( nItemId );
737
738
0
        if( nPos != VALUESET_ITEM_NOTFOUND )
739
0
        {
740
0
            rtl::Reference<ValueItemAcc> pItemAcc =
741
0
                mItemList[nPos]->GetAccessible();
742
743
0
            if( pItemAcc )
744
0
            {
745
0
                Any aOldAny;
746
0
                Any aNewAny;
747
0
                aOldAny <<= Reference(getXWeak(pItemAcc.get()));
748
0
                ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny );
749
0
            }
750
0
        }
751
0
    }
752
753
0
    if (mxAccessible->getAccessibleStateSet() & css::accessibility::AccessibleStateType::FOCUSED)
754
0
    {
755
        // focus event (select)
756
0
        const size_t nPos = GetItemPos(mnSelItemId);
757
758
0
        ValueSetItem* pItem = nullptr;
759
0
        if (nPos != VALUESET_ITEM_NOTFOUND)
760
0
            pItem = mItemList[nPos].get();
761
762
0
        ValueItemAcc* pItemAcc = nullptr;
763
0
        if (pItem != nullptr)
764
0
            pItemAcc =
765
0
                pItem->GetAccessible().get();
766
767
0
        if (pItemAcc)
768
0
        {
769
0
            Any aOldAny;
770
0
            Any aNewAny;
771
0
            aNewAny <<= Reference(getXWeak(pItemAcc));
772
0
            ImplFireAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
773
0
        }
774
0
    }
775
776
    // selection event
777
0
    Any aOldAny;
778
0
    Any aNewAny;
779
0
    ImplFireAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, aOldAny, aNewAny);
780
0
}
781
782
void ValueSet::SetNoSelection()
783
0
{
784
0
    mbNoSelection   = true;
785
0
    mbHighlight     = false;
786
787
0
    if (IsReallyVisible())
788
0
        Invalidate();
789
0
}
790
791
void ValueSet::SetStyle(WinBits nStyle)
792
0
{
793
0
    if (nStyle != mnStyle)
794
0
    {
795
0
        mnStyle = nStyle;
796
0
        mbFormat = true;
797
0
        Invalidate();
798
0
    }
799
0
}
800
801
void ValueSet::Format(vcl::RenderContext const & rRenderContext)
802
0
{
803
0
    Size aWinSize(GetOutputSizePixel());
804
0
    size_t nItemCount = mItemList.size();
805
0
    WinBits nStyle = GetStyle();
806
0
    tools::Long nTxtHeight = rRenderContext.GetTextHeight();
807
808
0
    if (mxScrolledWindow && !(nStyle & WB_VSCROLL) && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
809
0
        TurnOffScrollBar();
810
811
0
    if ( mnMargin )
812
0
    {
813
0
        aWinSize.AdjustWidth(-mnMargin * 2);
814
0
        aWinSize.AdjustHeight(-mnMargin * 2);
815
0
    }
816
817
    // consider size, if NameField does exist
818
0
    if (nStyle & WB_NAMEFIELD)
819
0
    {
820
0
        mnTextOffset = aWinSize.Height() - nTxtHeight - NAME_OFFSET;
821
0
        aWinSize.AdjustHeight( -(nTxtHeight + NAME_OFFSET) );
822
823
0
        if (!(nStyle & WB_FLATVALUESET))
824
0
        {
825
0
            mnTextOffset -= NAME_LINE_HEIGHT + NAME_LINE_OFF_Y;
826
0
            aWinSize.AdjustHeight( -(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y) );
827
0
        }
828
0
    }
829
0
    else
830
0
        mnTextOffset = 0;
831
832
0
    mnTextOffset += mnMargin;
833
834
    // calculate number of columns
835
0
    if (!mnUserCols)
836
0
    {
837
0
        if (mnUserItemWidth)
838
0
        {
839
0
            mnCols = static_cast<sal_uInt16>((aWinSize.Width() - mnSpacing) / (mnUserItemWidth + mnSpacing));
840
0
            if (mnCols <= 0)
841
0
                mnCols = 1;
842
0
        }
843
0
        else
844
0
        {
845
0
            mnCols = 1;
846
0
        }
847
0
    }
848
0
    else
849
0
    {
850
0
        mnCols = mnUserCols;
851
0
    }
852
853
    // calculate number of rows
854
0
    auto nOldLines = mnLines;
855
    // Floor( (M+N-1)/N )==Ceiling( M/N )
856
0
    mnLines = (static_cast<tools::Long>(nItemCount) + mnCols - 1) / mnCols;
857
0
    if (mnLines <= 0)
858
0
        mnLines = 1;
859
860
0
    bool bAdjustmentOutOfDate = nOldLines != mnLines;
861
862
0
    auto nOldVisLines = mnVisLines;
863
864
0
    tools::Long nCalcHeight = aWinSize.Height();
865
0
    if (mnUserVisLines)
866
0
    {
867
0
        mnVisLines = mnUserVisLines;
868
0
    }
869
0
    else if (mnUserItemHeight)
870
0
    {
871
0
        mnVisLines = (nCalcHeight + mnSpacing) / (mnUserItemHeight + mnSpacing);
872
0
        if (!mnVisLines)
873
0
            mnVisLines = 1;
874
0
    }
875
0
    else
876
0
    {
877
0
        mnVisLines = mnLines;
878
0
    }
879
880
0
    bAdjustmentOutOfDate |= nOldVisLines != mnVisLines;
881
882
0
    if (mnLines <= mnVisLines)
883
0
    {
884
0
        SetFirstLine(0);
885
0
    }
886
0
    else
887
0
    {
888
0
        if (mnFirstLine > o3tl::make_unsigned(mnLines - mnVisLines))
889
0
            SetFirstLine(static_cast<sal_uInt16>(mnLines - mnVisLines));
890
0
    }
891
892
    // calculate item size
893
0
    const tools::Long nColSpace  = (mnCols - 1) * static_cast<tools::Long>(mnSpacing);
894
0
    const tools::Long nLineSpace = (mnVisLines - 1) * mnSpacing;
895
0
    if (mnUserItemWidth && !mnUserCols)
896
0
    {
897
0
        mnItemWidth = mnUserItemWidth;
898
0
        if (mnItemWidth > aWinSize.Width() - nColSpace)
899
0
            mnItemWidth = aWinSize.Width() - nColSpace;
900
0
    }
901
0
    else
902
0
        mnItemWidth = (aWinSize.Width() - nColSpace) / mnCols;
903
0
    if (mnUserItemHeight && !mnUserVisLines)
904
0
    {
905
0
        mnItemHeight = mnUserItemHeight;
906
0
        if (mnItemHeight > nCalcHeight)
907
0
            mnItemHeight = nCalcHeight;
908
0
    }
909
0
    else
910
0
    {
911
0
        nCalcHeight -= nLineSpace;
912
0
        mnItemHeight = nCalcHeight / mnVisLines;
913
0
    }
914
915
    // Init VirDev
916
0
    maVirDev->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor());
917
0
    Size aDevSize(aWinSize);
918
0
    aDevSize.AdjustWidth(mnMargin * 2);
919
0
    aDevSize.AdjustHeight(mnMargin * 2);
920
0
    maVirDev->SetOutputSizePixel(aDevSize);
921
0
    maVirDev->Erase();
922
923
    // nothing is changed in case of too small items
924
0
    if ((mnItemWidth <= 0) ||
925
0
        (mnItemHeight <= ((nStyle & WB_ITEMBORDER) ? 4 : 2)) ||
926
0
        !nItemCount)
927
0
    {
928
0
        mbHasVisibleItems = false;
929
930
0
        for (size_t i = 0; i < nItemCount; i++)
931
0
        {
932
0
            mItemList[i]->mbVisible = false;
933
0
        }
934
935
0
        if (mxScrolledWindow && mxScrolledWindow->get_vpolicy() != VclPolicyType::NEVER)
936
0
            TurnOffScrollBar();
937
0
    }
938
0
    else
939
0
    {
940
0
        mbHasVisibleItems = true;
941
942
        // determine Frame-Style
943
0
        if (nStyle & WB_DOUBLEBORDER)
944
0
            mnFrameStyle = DrawFrameStyle::DoubleIn;
945
0
        else
946
0
            mnFrameStyle = DrawFrameStyle::In;
947
948
        // draw the selection with double width if the items are bigger
949
0
        if ((nStyle & WB_DOUBLEBORDER) &&
950
0
            ((mnItemWidth >= 25) && (mnItemHeight >= 20)))
951
0
        {
952
0
            mbDoubleSel = true;
953
0
        }
954
0
        else
955
0
        {
956
0
            mbDoubleSel = false;
957
0
        }
958
959
        // calculate offsets
960
0
        tools::Long nStartX;
961
0
        tools::Long nStartY;
962
0
        if (mbFullMode)
963
0
        {
964
0
            tools::Long nAllItemWidth = (mnItemWidth * mnCols) + nColSpace;
965
0
            tools::Long nAllItemHeight = (mnItemHeight * mnVisLines) + nLineSpace;
966
0
            nStartX = (aWinSize.Width() - nAllItemWidth) / 2;
967
0
            nStartY = (aWinSize.Height() - nAllItemHeight) / 2;
968
0
        }
969
0
        else
970
0
        {
971
0
            nStartX = 0;
972
0
            nStartY = 0;
973
0
        }
974
975
0
        nStartX += mnMargin;
976
0
        nStartY += mnMargin;
977
978
        // calculate and draw items
979
0
        maVirDev->SetLineColor();
980
0
        tools::Long x = nStartX;
981
0
        tools::Long y = nStartY;
982
983
        // draw items
984
0
        size_t nFirstItem = static_cast<size_t>(mnFirstLine) * mnCols;
985
0
        size_t nLastItem = nFirstItem + (mnVisLines * mnCols);
986
987
0
        maItemListRect.SetLeft( x );
988
0
        maItemListRect.SetTop( y );
989
0
        maItemListRect.SetRight( x + mnCols * (mnItemWidth + mnSpacing) - mnSpacing - 1 );
990
0
        maItemListRect.SetBottom( y + mnVisLines * (mnItemHeight + mnSpacing) - mnSpacing - 1 );
991
992
0
        if (!mbFullMode)
993
0
        {
994
            // If want also draw parts of items in the last line,
995
            // then we add one more line if parts of these line are
996
            // visible
997
0
            if (y + (mnVisLines * (mnItemHeight + mnSpacing)) < aWinSize.Height())
998
0
                nLastItem += mnCols;
999
0
            maItemListRect.SetBottom( aWinSize.Height() - y );
1000
0
        }
1001
0
        for (size_t i = 0; i < nItemCount; i++)
1002
0
        {
1003
0
            ValueSetItem* pItem = mItemList[i].get();
1004
1005
0
            if (i >= nFirstItem && i < nLastItem)
1006
0
            {
1007
0
                if (!pItem->mbVisible && ImplHasAccessibleListeners())
1008
0
                {
1009
0
                    Any aOldAny;
1010
0
                    Any aNewAny;
1011
1012
0
                    aNewAny <<= Reference<XAccessible>(pItem->GetAccessible());
1013
0
                    ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1014
0
                }
1015
1016
0
                pItem->mbVisible = true;
1017
0
                ImplFormatItem(rRenderContext, *pItem,
1018
0
                               tools::Rectangle(Point(x, y), Size(mnItemWidth, mnItemHeight)));
1019
1020
0
                if (!((i + 1) % mnCols))
1021
0
                {
1022
0
                    x = nStartX;
1023
0
                    y += mnItemHeight + mnSpacing;
1024
0
                }
1025
0
                else
1026
0
                    x += mnItemWidth + mnSpacing;
1027
0
            }
1028
0
            else
1029
0
            {
1030
0
                if (pItem->mbVisible && ImplHasAccessibleListeners())
1031
0
                {
1032
0
                    Any aOldAny;
1033
0
                    Any aNewAny;
1034
1035
0
                    aOldAny <<= Reference<XAccessible>(pItem->GetAccessible());
1036
0
                    ImplFireAccessibleEvent(AccessibleEventId::CHILD, aOldAny, aNewAny);
1037
0
                }
1038
1039
0
                pItem->mbVisible = false;
1040
0
            }
1041
0
        }
1042
1043
        // arrange ScrollBar, set values and show it
1044
0
        if (mxScrolledWindow && (nStyle & WB_VSCROLL))
1045
0
        {
1046
0
            bool bTurnScrollbarOn = mxScrolledWindow->get_vpolicy() != VclPolicyType::ALWAYS;
1047
0
            if (bAdjustmentOutOfDate || bTurnScrollbarOn)
1048
0
            {
1049
0
                tools::Long nPageSize = mnVisLines;
1050
0
                if (nPageSize < 1)
1051
0
                    nPageSize = 1;
1052
0
                mxScrolledWindow->vadjustment_configure(mnFirstLine, mnLines, 1, mnVisLines,
1053
0
                                                        nPageSize);
1054
0
            }
1055
1056
0
            if (bTurnScrollbarOn)
1057
0
                TurnOnScrollBar();
1058
0
        }
1059
0
    }
1060
1061
    // waiting for the next since the formatting is finished
1062
0
    mbFormat = false;
1063
0
}
1064
1065
void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext)
1066
0
{
1067
0
    if (!IsReallyVisible())
1068
0
        return;
1069
1070
0
    const bool bFocus = HasFocus();
1071
1072
0
    if (!bFocus && mbNoSelection && !mbHighlight)
1073
0
        return;
1074
1075
0
    tools::Rectangle aSelectedRect, aHoverRect;
1076
0
    ValueSetItem* pSelectedItem = ImplGetDrawSelectItem(mnSelItemId, bFocus, aSelectedRect);
1077
0
    ValueSetItem* pHighlightItem = mnHighItemId ? ImplGetDrawSelectItem(mnHighItemId, false, aHoverRect) : nullptr;
1078
1079
0
    if (pSelectedItem)
1080
0
    {
1081
0
        const bool bHover = pSelectedItem == pHighlightItem;
1082
0
        ImplDrawSelect(rRenderContext, aSelectedRect, pSelectedItem, bFocus, !mbNoSelection, true, bHover);
1083
0
    }
1084
0
    if (pHighlightItem && (pSelectedItem != pHighlightItem || mbNoSelection))
1085
0
    {
1086
        // For the case that there isn't a selected item, but due to wanting to
1087
        // show focus is in the valueset, the above block will have drawn the
1088
        // first item with a focus rect. For that situation; if the valueset is
1089
        // the thin WB_MENUSTYLEVALUESET case then blend this highlight border
1090
        // on top of that focus rect and it will appear with a highlighted
1091
        // focus rect. If it's the other case of a thicker border then redraw
1092
        // the focus rect highlighted with the hover color.
1093
0
        bool bDrawFocus;
1094
0
        WinBits nStyle = GetStyle();
1095
0
        if (nStyle & WB_MENUSTYLEVALUESET)
1096
0
            bDrawFocus = false;
1097
0
        else
1098
0
            bDrawFocus = pSelectedItem == pHighlightItem && mbNoSelection;
1099
1100
0
        ImplDrawSelect(rRenderContext, aHoverRect, pHighlightItem, bDrawFocus, mbHighlight, false, true);
1101
0
    }
1102
0
}
1103
1104
ValueSetItem* ValueSet::ImplGetDrawSelectItem(sal_uInt16 nItemId, const bool bFocus, tools::Rectangle& rRect)
1105
0
{
1106
0
    ValueSetItem* pItem = nullptr;
1107
0
    if (nItemId)
1108
0
    {
1109
0
        const size_t nPos = GetItemPos( nItemId );
1110
0
        pItem = mItemList[ nPos ].get();
1111
0
        rRect = ImplGetItemRect( nPos );
1112
0
    }
1113
0
    else if (bFocus && (pItem = ImplGetFirstItem()))
1114
0
    {
1115
0
        rRect = ImplGetItemRect(0);
1116
0
    }
1117
0
    return pItem;
1118
0
}
1119
1120
void ValueSet::ImplDrawSelect(vcl::RenderContext& rRenderContext,
1121
                              const tools::Rectangle& rRect, const ValueSetItem* pItem,
1122
                              const bool bFocus, const bool bDrawSel,
1123
                              const bool bSelected, const bool bHover)
1124
0
{
1125
0
    tools::Rectangle aRect(rRect);
1126
1127
    // draw selection
1128
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1129
0
    rRenderContext.SetFillColor();
1130
1131
0
    Color aDoubleColor;
1132
0
    Color aSingleColor;
1133
1134
0
    sal_uInt16 nTransparencePercent = 0;
1135
1136
0
    if (bSelected && bHover)
1137
0
    {
1138
0
        aDoubleColor = rStyleSettings.GetActiveColor();
1139
0
        aSingleColor = rStyleSettings.GetActiveTextColor();
1140
0
    }
1141
0
    else if (bSelected || bHover)
1142
0
    {
1143
0
        aDoubleColor = rStyleSettings.GetHighlightColor();
1144
0
        aSingleColor = rStyleSettings.GetHighlightTextColor();
1145
0
        if (bHover)
1146
0
        {
1147
0
            nTransparencePercent = 55;
1148
0
        }
1149
0
    }
1150
1151
    // specify selection output
1152
0
    WinBits nStyle = GetStyle();
1153
0
    if (nStyle & WB_MENUSTYLEVALUESET)
1154
0
    {
1155
0
        if (bFocus)
1156
0
            InvertFocusRect(rRenderContext, aRect);
1157
0
        if (bDrawSel)
1158
0
        {
1159
0
            rRenderContext.SetLineColor(aDoubleColor);
1160
0
            aRect.AdjustLeft( -1 );
1161
0
            aRect.AdjustTop( -1 );
1162
0
            aRect.AdjustRight( -2 );
1163
0
            aRect.AdjustBottom( -2 );
1164
1165
0
            const tools::Polygon aPoly(aRect);
1166
0
            LineInfo aLineInfo;
1167
0
            aLineInfo.SetWidth(3);
1168
0
            rRenderContext.DrawPolyLine(aPoly, aLineInfo); // tdf#136917
1169
0
        }
1170
0
    }
1171
0
    else
1172
0
    {
1173
0
        rRenderContext.SetLineColor(aDoubleColor);
1174
0
        tools::Rectangle aFocusRect;
1175
1176
0
        if (!mbDoubleSel)
1177
0
        {
1178
            // an outer rectangle surrounding a "focus" rectangle, surrounding
1179
            // an inner rectangle. Focus rectangle is always drawn, but rendered
1180
            // empty when there is no focus. e.g. as seen in color valuesets
1181
0
            if (bDrawSel)
1182
0
            {
1183
0
                tools::PolyPolygon aPolyPoly(1);
1184
0
                aPolyPoly.Insert(tools::Polygon(aRect));
1185
0
                rRenderContext.DrawTransparent(aPolyPoly, nTransparencePercent);
1186
0
            }
1187
1188
0
            aRect.AdjustLeft( 1 );
1189
0
            aRect.AdjustTop( 1 );
1190
0
            aRect.AdjustRight( -1 );
1191
0
            aRect.AdjustBottom( -1 );
1192
1193
0
            aFocusRect = aRect;
1194
1195
0
            aRect.AdjustLeft( 1 );
1196
0
            aRect.AdjustTop( 1 );
1197
0
            aRect.AdjustRight( -1 );
1198
0
            aRect.AdjustBottom( -1 );
1199
1200
0
            if (bDrawSel)
1201
0
            {
1202
0
                tools::PolyPolygon aPolyPoly(1);
1203
0
                aPolyPoly.Insert(tools::Polygon(aRect));
1204
0
                rRenderContext.DrawTransparent(aPolyPoly, nTransparencePercent);
1205
0
            }
1206
1207
0
            if (bDrawSel)
1208
0
                rRenderContext.SetLineColor(aSingleColor);
1209
0
            else
1210
0
                rRenderContext.SetLineColor(COL_LIGHTGRAY);
1211
1212
0
            rRenderContext.DrawRect(aFocusRect);
1213
0
        }
1214
0
        else
1215
0
        {
1216
            // a thick bordered rectangle surrounding an optional "focus"
1217
            // rectangle which is only drawn when focused, as seen in format,
1218
            // bullets and numbering in writer
1219
0
            const int nAdjust = 2;
1220
1221
0
            aRect.AdjustLeft(nAdjust);
1222
0
            aRect.AdjustTop(nAdjust);
1223
0
            aRect.AdjustRight(-nAdjust);
1224
0
            aRect.AdjustBottom(-nAdjust);
1225
1226
0
            aFocusRect = aRect;
1227
1228
0
            if (bDrawSel)
1229
0
            {
1230
0
                const basegfx::B2DPolygon aRectPoly(
1231
0
                    basegfx::utils::createPolygonFromRect(
1232
0
                            vcl::unotools::b2DRectangleFromRectangle(aRect)));
1233
1234
0
                const int nThickness = nAdjust * 2;
1235
1236
0
                if (!rRenderContext.DrawPolyLineDirect(basegfx::B2DHomMatrix(),
1237
0
                                                       aRectPoly,
1238
0
                                                       nThickness,
1239
0
                                                       nTransparencePercent / 100.0,
1240
0
                                                       nullptr,
1241
0
                                                       basegfx::B2DLineJoin::Miter))
1242
0
                {
1243
0
                    SAL_WARN("svtools", "presumably impossible in practice, but fallback to see something");
1244
0
                    rRenderContext.DrawPolyLine(aRectPoly, nThickness, basegfx::B2DLineJoin::Miter);
1245
0
                }
1246
0
            }
1247
1248
0
            if (bFocus)
1249
0
            {
1250
0
                if (bDrawSel)
1251
0
                    rRenderContext.SetLineColor(aSingleColor);
1252
0
                else
1253
0
                    rRenderContext.SetLineColor(COL_LIGHTGRAY);
1254
1255
0
                rRenderContext.DrawRect(aFocusRect);
1256
0
            }
1257
0
        }
1258
1259
0
        if (bFocus)
1260
0
            InvertFocusRect(rRenderContext, aFocusRect);
1261
0
    }
1262
1263
0
    ImplDrawItemText(rRenderContext, pItem->maText);
1264
0
}
1265
1266
void ValueSet::ImplFormatItem(vcl::RenderContext const& rRenderContext, ValueSetItem& rItem,
1267
                              tools::Rectangle aRect)
1268
0
{
1269
0
    WinBits nStyle = GetStyle();
1270
0
    if (nStyle & WB_ITEMBORDER)
1271
0
    {
1272
0
        aRect.AdjustLeft(1 );
1273
0
        aRect.AdjustTop(1 );
1274
0
        aRect.AdjustRight( -1 );
1275
0
        aRect.AdjustBottom( -1 );
1276
1277
0
        if (nStyle & WB_FLATVALUESET)
1278
0
        {
1279
0
            sal_Int32 nBorder = (nStyle & WB_DOUBLEBORDER) ? 2 : 1;
1280
1281
0
            aRect.AdjustLeft(nBorder );
1282
0
            aRect.AdjustTop(nBorder );
1283
0
            aRect.AdjustRight( -nBorder );
1284
0
            aRect.AdjustBottom( -nBorder );
1285
0
        }
1286
0
        else
1287
0
        {
1288
0
            DecorationView aView(maVirDev.get());
1289
0
            aRect = aView.DrawFrame(aRect, mnFrameStyle);
1290
0
        }
1291
0
    }
1292
1293
0
    if ((aRect.GetHeight() <= 0) || (aRect.GetWidth() <= 0))
1294
0
        return;
1295
1296
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1297
1298
0
    if (rItem.meType == ValueSetItemType::Color)
1299
0
    {
1300
0
        maVirDev->SetFillColor(rItem.maColor);
1301
0
        maVirDev->DrawRect(aRect);
1302
0
    }
1303
0
    else
1304
0
    {
1305
0
        if (IsColor())
1306
0
            maVirDev->SetFillColor(maColor);
1307
0
        else if (nStyle & WB_MENUSTYLEVALUESET)
1308
0
            maVirDev->SetFillColor(rStyleSettings.GetMenuColor());
1309
0
        else if (IsEnabled())
1310
0
            maVirDev->SetFillColor(rStyleSettings.GetWindowColor());
1311
0
        else
1312
0
            maVirDev->SetFillColor(rStyleSettings.GetFaceColor());
1313
0
        maVirDev->DrawRect(aRect);
1314
1315
0
        if (rItem.meType == ValueSetItemType::UserDraw)
1316
0
        {
1317
0
            UserDrawEvent aUDEvt(maVirDev.get(), aRect, rItem.mnId);
1318
0
            UserDraw(aUDEvt);
1319
0
        }
1320
0
        else
1321
0
        {
1322
0
            Size aImageSize = rItem.maImage.GetSizePixel();
1323
0
            Size  aRectSize = aRect.GetSize();
1324
0
            Point aPos(aRect.Left(), aRect.Top());
1325
0
            aPos.AdjustX((aRectSize.Width() - aImageSize.Width()) / 2 );
1326
1327
0
            if (rItem.meType != ValueSetItemType::ImageAndText)
1328
0
                aPos.AdjustY((aRectSize.Height() - aImageSize.Height()) / 2 );
1329
1330
0
            DrawImageFlags  nImageStyle  = DrawImageFlags::NONE;
1331
0
            if (!IsEnabled())
1332
0
                nImageStyle  |= DrawImageFlags::Disable;
1333
1334
0
            if (aImageSize.Width()  > aRectSize.Width() ||
1335
0
                aImageSize.Height() > aRectSize.Height())
1336
0
            {
1337
0
                maVirDev->SetClipRegion(vcl::Region(aRect));
1338
0
                maVirDev->DrawImage(aPos, rItem.maImage, nImageStyle);
1339
0
                maVirDev->SetClipRegion();
1340
0
            }
1341
0
            else
1342
0
                maVirDev->DrawImage(aPos, rItem.maImage, nImageStyle);
1343
1344
0
            if (rItem.meType == ValueSetItemType::ImageAndText)
1345
0
            {
1346
0
                maVirDev->SetFont(rRenderContext.GetFont());
1347
0
                maVirDev->SetTextColor((nStyle & WB_MENUSTYLEVALUESET) ? rStyleSettings.GetMenuTextColor() : rStyleSettings.GetWindowTextColor());
1348
0
                maVirDev->SetTextFillColor();
1349
1350
0
                tools::Long nTxtWidth = maVirDev->GetTextWidth(rItem.maText);
1351
1352
0
                if (nTxtWidth > aRect.GetWidth())
1353
0
                    maVirDev->SetClipRegion(vcl::Region(aRect));
1354
1355
0
                maVirDev->DrawText(Point(aRect.Left() + (aRect.GetWidth() - nTxtWidth) / 2,
1356
0
                                         aRect.Bottom() - maVirDev->GetTextHeight()),
1357
0
                                   rItem.maText);
1358
1359
0
                if (nTxtWidth > aRect.GetWidth())
1360
0
                    maVirDev->SetClipRegion();
1361
0
            }
1362
0
        }
1363
0
    }
1364
1365
0
    const sal_uInt16 nEdgeBlendingPercent = mbEdgeBlending ? rStyleSettings.GetEdgeBlending() : 0;
1366
1367
0
    if (nEdgeBlendingPercent)
1368
0
    {
1369
0
        const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
1370
0
        const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
1371
0
        const sal_uInt8 nAlpha(255 - ((nEdgeBlendingPercent * 255) / 100));
1372
0
        const Bitmap aBlendFrame(createAlphaBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
1373
1374
0
        if (!aBlendFrame.IsEmpty())
1375
0
        {
1376
0
            maVirDev->DrawBitmap(aRect.TopLeft(), aBlendFrame);
1377
0
        }
1378
0
    }
1379
0
}
1380
1381
void ValueSet::ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rText)
1382
0
{
1383
0
    if (!(GetStyle() & WB_NAMEFIELD))
1384
0
        return;
1385
1386
0
    Size aWinSize(GetOutputSizePixel());
1387
0
    tools::Long nTxtWidth = rRenderContext.GetTextWidth(rText);
1388
0
    tools::Long nTxtOffset = mnTextOffset;
1389
1390
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::TEXTCOLOR);
1391
1392
    // delete rectangle and show text
1393
0
    const bool bFlat(GetStyle() & WB_FLATVALUESET);
1394
0
    if (!bFlat)
1395
0
        nTxtOffset += NAME_LINE_HEIGHT+NAME_LINE_OFF_Y;
1396
1397
0
    rRenderContext.SetTextColor(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
1398
    // tdf#153787 highlighted entry text is drawn in the same Paint as the selected text, so can
1399
    // overwrite already rendered text
1400
0
    rRenderContext.Erase(tools::Rectangle(Point(0, nTxtOffset), Point(aWinSize.Width(), aWinSize.Height())));
1401
0
    rRenderContext.DrawText(Point((aWinSize.Width() - nTxtWidth) / 2, nTxtOffset + (NAME_OFFSET / 2)), rText);
1402
0
}
1403
1404
void ValueSet::StyleUpdated()
1405
0
{
1406
0
    mbFormat = true;
1407
0
    CustomWidgetController::StyleUpdated();
1408
0
}
1409
1410
void ValueSet::EnableFullItemMode( bool bFullMode )
1411
0
{
1412
0
    mbFullMode = bFullMode;
1413
0
}
1414
1415
void ValueSet::SetColCount( sal_uInt16 nNewCols )
1416
0
{
1417
0
    if ( mnUserCols != nNewCols )
1418
0
    {
1419
0
        mnUserCols = nNewCols;
1420
0
        QueueReformat();
1421
0
    }
1422
0
}
1423
1424
void ValueSet::SetItemImage( sal_uInt16 nItemId, const Image& rImage )
1425
0
{
1426
0
    size_t nPos = GetItemPos( nItemId );
1427
1428
0
    if ( nPos == VALUESET_ITEM_NOTFOUND )
1429
0
        return;
1430
1431
0
    ValueSetItem* pItem = mItemList[nPos].get();
1432
0
    pItem->meType  = ValueSetItemType::Image;
1433
0
    pItem->maImage = rImage;
1434
1435
0
    if (!mbFormat && IsReallyVisible())
1436
0
    {
1437
0
        const tools::Rectangle aRect = ImplGetItemRect(nPos);
1438
0
        Invalidate(aRect);
1439
0
    }
1440
0
    else
1441
0
        mbFormat = true;
1442
0
}
1443
1444
void ValueSet::SetItemColor( sal_uInt16 nItemId, const Color& rColor )
1445
0
{
1446
0
    size_t nPos = GetItemPos( nItemId );
1447
1448
0
    if ( nPos == VALUESET_ITEM_NOTFOUND )
1449
0
        return;
1450
1451
0
    ValueSetItem* pItem = mItemList[nPos].get();
1452
0
    pItem->meType  = ValueSetItemType::Color;
1453
0
    pItem->maColor = rColor;
1454
1455
0
    if (!mbFormat && IsReallyVisible())
1456
0
    {
1457
0
        const tools::Rectangle aRect = ImplGetItemRect(nPos);
1458
0
        Invalidate( aRect );
1459
0
    }
1460
0
    else
1461
0
        mbFormat = true;
1462
0
}
1463
1464
Color ValueSet::GetItemColor( sal_uInt16 nItemId ) const
1465
0
{
1466
0
    size_t nPos = GetItemPos( nItemId );
1467
1468
0
    if ( nPos != VALUESET_ITEM_NOTFOUND )
1469
0
        return mItemList[nPos]->maColor;
1470
0
    else
1471
0
        return Color();
1472
0
}
1473
1474
Size ValueSet::CalcWindowSizePixel( const Size& rItemSize, sal_uInt16 nDesireCols,
1475
                                    sal_uInt16 nDesireLines ) const
1476
0
{
1477
0
    size_t nCalcCols = nDesireCols;
1478
0
    size_t nCalcLines = nDesireLines;
1479
1480
0
    if ( !nCalcCols )
1481
0
    {
1482
0
        if ( mnUserCols )
1483
0
            nCalcCols = mnUserCols;
1484
0
        else
1485
0
            nCalcCols = 1;
1486
0
    }
1487
1488
0
    if ( !nCalcLines )
1489
0
    {
1490
0
        nCalcLines = mnVisLines;
1491
1492
0
        if ( mbFormat )
1493
0
        {
1494
0
            if ( mnUserVisLines )
1495
0
                nCalcLines = mnUserVisLines;
1496
0
            else
1497
0
            {
1498
                // Floor( (M+N-1)/N )==Ceiling( M/N )
1499
0
                nCalcLines = (mItemList.size()+nCalcCols-1) / nCalcCols;
1500
0
                if ( !nCalcLines )
1501
0
                    nCalcLines = 1;
1502
0
            }
1503
0
        }
1504
0
    }
1505
1506
0
    Size        aSize( rItemSize.Width() * nCalcCols, rItemSize.Height() * nCalcLines );
1507
0
    WinBits     nStyle = GetStyle();
1508
0
    tools::Long        nTxtHeight = GetTextHeight();
1509
0
    tools::Long        n;
1510
1511
0
    if ( nStyle & WB_ITEMBORDER )
1512
0
    {
1513
0
        if ( nStyle & WB_DOUBLEBORDER )
1514
0
            n = ITEM_OFFSET_DOUBLE;
1515
0
        else
1516
0
            n = ITEM_OFFSET;
1517
1518
0
        aSize.AdjustWidth(n * nCalcCols );
1519
0
        aSize.AdjustHeight(n * nCalcLines );
1520
0
    }
1521
0
    else
1522
0
        n = 0;
1523
1524
0
    if ( mnSpacing )
1525
0
    {
1526
0
        aSize.AdjustWidth(mnSpacing * (nCalcCols - 1) );
1527
0
        aSize.AdjustHeight(mnSpacing * (nCalcLines - 1) );
1528
0
    }
1529
1530
0
    if ( nStyle & WB_NAMEFIELD )
1531
0
    {
1532
0
        aSize.AdjustHeight(nTxtHeight + NAME_OFFSET );
1533
0
        if ( !(nStyle & WB_FLATVALUESET) )
1534
0
            aSize.AdjustHeight(NAME_LINE_HEIGHT + NAME_LINE_OFF_Y );
1535
0
    }
1536
1537
0
    if ( mnMargin )
1538
0
    {
1539
0
        aSize.AdjustWidth(mnMargin * 2);
1540
0
        aSize.AdjustHeight(mnMargin * 2);
1541
0
    }
1542
1543
0
    return aSize;
1544
0
}
1545
1546
void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage )
1547
0
{
1548
0
    std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1549
0
    pItem->mnId     = nItemId;
1550
0
    pItem->meType = ValueSetItemType::Image;
1551
0
    pItem->maImage  = rImage;
1552
0
    ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1553
0
}
1554
1555
void ValueSet::InsertItem( sal_uInt16 nItemId, const Image& rImage,
1556
                           const OUString& rText, size_t nPos,
1557
                           bool bShowLegend )
1558
0
{
1559
0
    std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1560
0
    pItem->mnId     = nItemId;
1561
0
    pItem->meType   = bShowLegend ? ValueSetItemType::ImageAndText : ValueSetItemType::Image;
1562
0
    pItem->maImage  = rImage;
1563
0
    pItem->maText   = rText;
1564
0
    ImplInsertItem( std::move(pItem), nPos );
1565
0
}
1566
1567
void ValueSet::InsertItem( sal_uInt16 nItemId, size_t nPos )
1568
0
{
1569
0
    std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1570
0
    pItem->mnId     = nItemId;
1571
0
    pItem->meType = ValueSetItemType::UserDraw;
1572
0
    ImplInsertItem( std::move(pItem), nPos );
1573
0
}
1574
1575
void ValueSet::InsertItem( sal_uInt16 nItemId, const Color& rColor,
1576
                           const OUString& rText )
1577
0
{
1578
0
    std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1579
0
    pItem->mnId     = nItemId;
1580
0
    pItem->meType   = ValueSetItemType::Color;
1581
0
    pItem->maColor  = rColor;
1582
0
    pItem->maText   = rText;
1583
0
    ImplInsertItem( std::move(pItem), VALUESET_APPEND );
1584
0
}
1585
1586
void ValueSet::ImplInsertItem( std::unique_ptr<ValueSetItem> pItem, const size_t nPos )
1587
0
{
1588
0
    DBG_ASSERT( pItem->mnId, "ValueSet::InsertItem(): ItemId == 0" );
1589
0
    DBG_ASSERT( GetItemPos( pItem->mnId ) == VALUESET_ITEM_NOTFOUND,
1590
0
                "ValueSet::InsertItem(): ItemId already exists" );
1591
1592
0
    if ( nPos < mItemList.size() ) {
1593
0
        mItemList.insert( mItemList.begin() + nPos, std::move(pItem) );
1594
0
    } else {
1595
0
        mItemList.push_back( std::move(pItem) );
1596
0
    }
1597
1598
0
    QueueReformat();
1599
0
}
1600
1601
int ValueSet::GetScrollWidth() const
1602
0
{
1603
0
    if (mxScrolledWindow)
1604
0
        return mxScrolledWindow->get_scroll_thickness();
1605
0
    return 0;
1606
0
}
1607
1608
void ValueSet::SetEdgeBlending(bool bNew)
1609
0
{
1610
0
    if(mbEdgeBlending != bNew)
1611
0
    {
1612
0
        mbEdgeBlending = bNew;
1613
0
        mbFormat = true;
1614
1615
0
        if (GetDrawingArea() && IsReallyVisible())
1616
0
        {
1617
0
            Invalidate();
1618
0
        }
1619
0
    }
1620
0
}
1621
1622
Size ValueSet::CalcItemSizePixel( const Size& rItemSize) const
1623
0
{
1624
0
    Size aSize = rItemSize;
1625
1626
0
    WinBits nStyle = GetStyle();
1627
0
    if ( nStyle & WB_ITEMBORDER )
1628
0
    {
1629
0
        tools::Long n;
1630
1631
0
        if ( nStyle & WB_DOUBLEBORDER )
1632
0
            n = ITEM_OFFSET_DOUBLE;
1633
0
        else
1634
0
            n = ITEM_OFFSET;
1635
1636
0
        aSize.AdjustWidth(n );
1637
0
        aSize.AdjustHeight(n );
1638
0
    }
1639
1640
0
    return aSize;
1641
0
}
1642
1643
void ValueSet::SetLineCount( sal_uInt16 nNewLines )
1644
0
{
1645
0
    if ( mnUserVisLines != nNewLines )
1646
0
    {
1647
0
        mnUserVisLines = nNewLines;
1648
0
        QueueReformat();
1649
0
    }
1650
0
}
1651
1652
void ValueSet::SetItemWidth( tools::Long nNewItemWidth )
1653
0
{
1654
0
    if ( mnUserItemWidth != nNewItemWidth )
1655
0
    {
1656
0
        mnUserItemWidth = nNewItemWidth;
1657
0
        QueueReformat();
1658
0
    }
1659
0
}
1660
1661
//method to set accessible when the style is user draw.
1662
void ValueSet::InsertItem( sal_uInt16 nItemId, const OUString& rText, size_t nPos  )
1663
0
{
1664
0
    DBG_ASSERT( nItemId, "ValueSet::InsertItem(): ItemId == 0" );
1665
0
    DBG_ASSERT( GetItemPos( nItemId ) == VALUESET_ITEM_NOTFOUND,
1666
0
                "ValueSet::InsertItem(): ItemId already exists" );
1667
0
    std::unique_ptr<ValueSetItem> pItem(new ValueSetItem( *this ));
1668
0
    pItem->mnId     = nItemId;
1669
0
    pItem->meType = ValueSetItemType::UserDraw;
1670
0
    pItem->maText   = rText;
1671
0
    ImplInsertItem( std::move(pItem), nPos );
1672
0
}
1673
1674
void ValueSet::SetItemHeight( tools::Long nNewItemHeight )
1675
0
{
1676
0
    if ( mnUserItemHeight != nNewItemHeight )
1677
0
    {
1678
0
        mnUserItemHeight = nNewItemHeight;
1679
0
        QueueReformat();
1680
0
    }
1681
0
}
1682
1683
OUString ValueSet::RequestHelp(tools::Rectangle& rHelpRect)
1684
0
{
1685
0
    Point aPos = rHelpRect.TopLeft();
1686
0
    const size_t nItemPos = ImplGetItem( aPos );
1687
0
    OUString sRet;
1688
0
    if (nItemPos != VALUESET_ITEM_NOTFOUND)
1689
0
    {
1690
0
        rHelpRect = ImplGetItemRect(nItemPos);
1691
0
        sRet = GetItemText(ImplGetItem(nItemPos)->mnId);
1692
0
    }
1693
0
    return sRet;
1694
0
}
1695
1696
const OUString & ValueSet::GetItemText(sal_uInt16 nItemId) const
1697
0
{
1698
0
    const size_t nPos = GetItemPos(nItemId);
1699
1700
0
    if ( nPos != VALUESET_ITEM_NOTFOUND )
1701
0
        return mItemList[nPos]->maText;
1702
1703
0
    return EMPTY_OUSTRING;
1704
0
}
1705
1706
void ValueSet::SetExtraSpacing( sal_uInt16 nNewSpacing )
1707
0
{
1708
0
    if ( GetStyle() & WB_ITEMBORDER )
1709
0
    {
1710
0
        mnSpacing = nNewSpacing;
1711
0
        QueueReformat();
1712
0
    }
1713
0
}
1714
1715
void ValueSet::SetMargin( sal_uInt16 nNewMargin )
1716
0
{
1717
0
    mnMargin = nNewMargin;
1718
0
    QueueReformat();
1719
0
}
1720
1721
void ValueSet::SetFormat()
1722
0
{
1723
0
    mbFormat = true;
1724
0
}
1725
1726
void ValueSet::SetItemData( sal_uInt16 nItemId, void* pData )
1727
0
{
1728
0
    size_t nPos = GetItemPos( nItemId );
1729
1730
0
    if ( nPos == VALUESET_ITEM_NOTFOUND )
1731
0
        return;
1732
1733
0
    ValueSetItem* pItem = mItemList[nPos].get();
1734
0
    pItem->mpData = pData;
1735
1736
0
    if (pItem->meType == ValueSetItemType::UserDraw)
1737
0
    {
1738
0
        if (!mbFormat && IsReallyVisible())
1739
0
        {
1740
0
            const tools::Rectangle aRect = ImplGetItemRect(nPos);
1741
0
            Invalidate(aRect);
1742
0
        }
1743
0
        else
1744
0
            mbFormat = true;
1745
0
    }
1746
0
}
1747
1748
void* ValueSet::GetItemData( sal_uInt16 nItemId ) const
1749
0
{
1750
0
    size_t nPos = GetItemPos( nItemId );
1751
1752
0
    if ( nPos != VALUESET_ITEM_NOTFOUND )
1753
0
        return mItemList[nPos]->mpData;
1754
0
    else
1755
0
        return nullptr;
1756
0
}
1757
1758
void ValueSet::SetItemText(sal_uInt16 nItemId, const OUString& rText)
1759
0
{
1760
0
    size_t nPos = GetItemPos( nItemId );
1761
1762
0
    if ( nPos == VALUESET_ITEM_NOTFOUND )
1763
0
        return;
1764
1765
0
    ValueSetItem* pItem = mItemList[nPos].get();
1766
1767
    // Remember old and new name for accessibility event.
1768
0
    Any aOldName;
1769
0
    Any aNewName;
1770
0
    OUString sString (pItem->maText);
1771
0
    aOldName <<= sString;
1772
0
    sString = rText;
1773
0
    aNewName <<= sString;
1774
1775
0
    pItem->maText = rText;
1776
1777
0
    if (!mbFormat && IsReallyVisible())
1778
0
    {
1779
0
        sal_uInt16 nTempId = mnSelItemId;
1780
1781
0
        if (mbHighlight)
1782
0
            nTempId = mnHighItemId;
1783
1784
0
        if (nTempId == nItemId)
1785
0
            Invalidate();
1786
0
    }
1787
1788
0
    if (ImplHasAccessibleListeners())
1789
0
    {
1790
0
        rtl::Reference<ValueItemAcc> xAccessible(pItem->GetAccessible());
1791
0
        xAccessible->FireAccessibleEvent(AccessibleEventId::NAME_CHANGED, aOldName, aNewName);
1792
0
    }
1793
0
}
1794
1795
Size ValueSet::GetLargestItemSize()
1796
0
{
1797
0
    Size aLargestItem;
1798
1799
0
    for (const std::unique_ptr<ValueSetItem>& pItem : mItemList)
1800
0
    {
1801
0
        if (!pItem->mbVisible)
1802
0
            continue;
1803
1804
0
        if (pItem->meType != ValueSetItemType::Image &&
1805
0
            pItem->meType != ValueSetItemType::ImageAndText)
1806
0
        {
1807
            // handle determining an optimal size for this case
1808
0
            continue;
1809
0
        }
1810
1811
0
        Size aSize = pItem->maImage.GetSizePixel();
1812
0
        if (pItem->meType == ValueSetItemType::ImageAndText)
1813
0
        {
1814
0
            aSize.AdjustHeight(3 * NAME_LINE_HEIGHT +
1815
0
                maVirDev->GetTextHeight() );
1816
0
            aSize.setWidth( std::max(aSize.Width(),
1817
0
                                     maVirDev->GetTextWidth(pItem->maText) + NAME_OFFSET) );
1818
0
        }
1819
1820
0
        aLargestItem.setWidth( std::max(aLargestItem.Width(), aSize.Width()) );
1821
0
        aLargestItem.setHeight( std::max(aLargestItem.Height(), aSize.Height()) );
1822
0
    }
1823
1824
0
    return aLargestItem;
1825
0
}
1826
1827
void ValueSet::SetOptimalSize()
1828
0
{
1829
0
    Size aLargestSize(GetLargestItemSize());
1830
0
    aLargestSize.setWidth(std::max(aLargestSize.Width(), mnUserItemWidth));
1831
0
    aLargestSize.setHeight(std::max(aLargestSize.Height(), mnUserItemHeight));
1832
0
    Size aPrefSize(CalcWindowSizePixel(aLargestSize));
1833
0
    GetDrawingArea()->set_size_request(aPrefSize.Width(), aPrefSize.Height());
1834
0
}
1835
1836
Image ValueSet::GetItemImage(sal_uInt16 nItemId) const
1837
0
{
1838
0
    size_t nPos = GetItemPos( nItemId );
1839
1840
0
    if ( nPos != VALUESET_ITEM_NOTFOUND )
1841
0
        return mItemList[nPos]->maImage;
1842
0
    else
1843
0
        return Image();
1844
0
}
1845
1846
void ValueSet::SetColor(const Color& rColor)
1847
0
{
1848
0
    maColor  = rColor;
1849
0
    mbFormat = true;
1850
0
    if (IsReallyVisible())
1851
0
        Invalidate();
1852
0
}
1853
1854
void ValueSet::Show()
1855
0
{
1856
0
    if (mxScrolledWindow)
1857
0
        mxScrolledWindow->show();
1858
0
    CustomWidgetController::Show();
1859
0
}
1860
1861
void ValueSet::Hide()
1862
0
{
1863
0
    CustomWidgetController::Hide();
1864
0
    if (mxScrolledWindow)
1865
0
        mxScrolledWindow->hide();
1866
0
}
1867
1868
FactoryFunction ValueSet::GetUITestFactory() const
1869
0
{
1870
0
    return ValueSetUIObject::create;
1871
0
}
1872
1873
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */