Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/vcl/source/control/throbber.cxx
Line
Count
Source (jump to first uncovered line)
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 <comphelper/namedvaluecollection.hxx>
21
#include <comphelper/processfactory.hxx>
22
23
#include <vcl/svapp.hxx>
24
#include <vcl/toolkit/throbber.hxx>
25
26
#include <com/sun/star/graphic/GraphicProvider.hpp>
27
#include <com/sun/star/awt/ImageScaleMode.hpp>
28
29
#include <limits>
30
31
using ::com::sun::star::uno::Reference;
32
using ::com::sun::star::graphic::XGraphic;
33
using ::com::sun::star::graphic::XGraphicProvider;
34
using ::com::sun::star::uno::Exception;
35
namespace ImageScaleMode = css::awt::ImageScaleMode;
36
37
Throbber::Throbber(vcl::Window* pParentWindow, WinBits eStyle )
38
0
    :ImageControl(pParentWindow, eStyle )
39
0
    ,mbRepeat( true )
40
0
    ,mnStepTime( 100 )
41
0
    ,mnCurStep( 0 )
42
0
    ,maWaitTimer("Throbber maWaitTimer")
43
0
{
44
0
    maWaitTimer.SetTimeout( mnStepTime );
45
0
    maWaitTimer.SetInvokeHandler( LINK( this, Throbber, TimeOutHdl ) );
46
47
0
    SetScaleMode( ImageScaleMode::NONE );
48
0
    initImages();
49
0
}
Unexecuted instantiation: Throbber::Throbber(vcl::Window*, long)
Unexecuted instantiation: Throbber::Throbber(vcl::Window*, long)
50
51
Throbber::~Throbber()
52
0
{
53
0
    disposeOnce();
54
0
}
55
56
void Throbber::dispose()
57
0
{
58
0
    maWaitTimer.Stop();
59
0
    ImageControl::dispose();
60
0
}
61
62
namespace
63
{
64
    ::std::vector< Image > lcl_loadImageSet( const Throbber::ImageSet i_imageSet )
65
0
    {
66
0
        ::std::vector< Image > aImages;
67
68
0
        const Reference< css::uno::XComponentContext >& aContext( ::comphelper::getProcessComponentContext() );
69
0
        const Reference< XGraphicProvider > xGraphicProvider( css::graphic::GraphicProvider::create(aContext) );
70
71
0
        ::std::vector< OUString > aImageURLs( Throbber::getDefaultImageURLs( i_imageSet ) );
72
0
        aImages.reserve( aImageURLs.size() );
73
74
0
        ::comphelper::NamedValueCollection aMediaProperties;
75
0
        for ( const auto& rImageURL : aImageURLs )
76
0
        {
77
0
            Reference< XGraphic > xGraphic;
78
0
            aMediaProperties.put( u"URL"_ustr, rImageURL );
79
0
            xGraphic = xGraphicProvider->queryGraphic( aMediaProperties.getPropertyValues() );
80
0
            aImages.emplace_back( xGraphic );
81
0
        }
82
83
0
        return aImages;
84
0
    }
85
}
86
87
void Throbber::Resize()
88
0
{
89
0
    ImageControl::Resize();
90
0
    initImages();
91
0
}
92
93
void Throbber::initImages()
94
0
{
95
0
    try
96
0
    {
97
0
        ::std::vector< ::std::vector< Image > > aImageSets
98
0
        {
99
0
            lcl_loadImageSet( ImageSet::N16px ),
100
0
            lcl_loadImageSet( ImageSet::N32px ),
101
0
            lcl_loadImageSet( ImageSet::N64px )
102
0
        };
103
104
        // find the best matching image set (size-wise)
105
0
        const ::Size aWindowSizePixel = GetSizePixel();
106
0
        size_t nPreferredSet = 0;
107
0
        if ( aImageSets.size() > 1 )
108
0
        {
109
0
            tools::Long nMinimalDistance = ::std::numeric_limits< tools::Long >::max();
110
0
            for (   ::std::vector< ::std::vector< Image > >::const_iterator check = aImageSets.begin();
111
0
                    check != aImageSets.end();
112
0
                    ++check
113
0
                )
114
0
            {
115
0
                if ( check->empty() )
116
0
                {
117
0
                    SAL_WARN( "vcl.control", "Throbber::initImages: illegal image!" );
118
0
                    continue;
119
0
                }
120
121
0
                const Size aImageSize = (*check)[0].GetSizePixel();
122
123
0
                if  (   ( aImageSize.Width() > aWindowSizePixel.Width() )
124
0
                    ||  ( aImageSize.Height() > aWindowSizePixel.Height() )
125
0
                    )
126
                    // do not use an image set which doesn't fit into the window
127
0
                    continue;
128
129
0
                const sal_Int64 distance =
130
0
                        ( aWindowSizePixel.Width() - aImageSize.Width() ) * ( aWindowSizePixel.Width() - aImageSize.Width() )
131
0
                    +   ( aWindowSizePixel.Height() - aImageSize.Height() ) * ( aWindowSizePixel.Height() - aImageSize.Height() );
132
0
                if ( distance < nMinimalDistance )
133
0
                {
134
0
                    nMinimalDistance = distance;
135
0
                    nPreferredSet = check - aImageSets.begin();
136
0
                }
137
0
            }
138
0
        }
139
140
0
        if ( nPreferredSet < aImageSets.size() )
141
0
            setImageList( std::vector(aImageSets[nPreferredSet]) );
142
0
    }
143
0
    catch( const Exception& )
144
0
    {
145
0
    }
146
0
}
147
148
void Throbber::start()
149
0
{
150
0
    maWaitTimer.SetTimeout(mnStepTime);
151
0
    maWaitTimer.Start();
152
0
}
153
154
void Throbber::stop()
155
0
{
156
0
    maWaitTimer.Stop();
157
0
}
158
159
bool Throbber::isRunning() const
160
0
{
161
0
    return maWaitTimer.IsActive();
162
0
}
163
164
void Throbber::setImageList( ::std::vector< Image > && i_images )
165
0
{
166
0
    SAL_WARN_IF( i_images.size()>=SAL_MAX_INT32, "vcl.control", "Throbber::setImageList: too many images!" );
167
168
0
    maImageList = std::move(i_images);
169
170
0
    const Image aInitialImage( !maImageList.empty() ? maImageList[ 0 ] : Image() );
171
0
    SetImage( aInitialImage );
172
0
}
173
174
::std::vector< OUString > Throbber::getDefaultImageURLs( const ImageSet i_imageSet )
175
0
{
176
0
    ::std::vector< OUString > aImageURLs;
177
178
0
    sal_Unicode const* const pResolutions[] = { u"16", u"32", u"64" };
179
0
    size_t const nImageCounts[] = { 6, 12, 12 };
180
181
0
    size_t index = 0;
182
0
    switch ( i_imageSet )
183
0
    {
184
0
    case ImageSet::N16px:  index = 0;  break;
185
0
    case ImageSet::N32px:  index = 1;  break;
186
0
    case ImageSet::N64px:  index = 2;  break;
187
0
    }
188
189
0
    aImageURLs.reserve( nImageCounts[index] );
190
0
    for ( size_t i=0; i<nImageCounts[index]; ++i )
191
0
    {
192
0
        OUStringBuffer aURL( OUString::Concat("private:graphicrepository/vcl/res/spinner-")
193
0
            + pResolutions[index]
194
0
            + "-" );
195
0
        if ( i < 9 )
196
0
            aURL.append( "0" );
197
0
        aURL.append( OUString::number( sal_Int32( i + 1 ) ) + ".png" );
198
199
0
        aImageURLs.push_back( aURL.makeStringAndClear() );
200
0
    }
201
202
0
    return aImageURLs;
203
0
}
204
205
IMPL_LINK_NOARG(Throbber, TimeOutHdl, Timer *, void)
206
0
{
207
0
    SolarMutexGuard aGuard;
208
0
    if ( maImageList.empty() )
209
0
        return;
210
211
0
    if ( mnCurStep < static_cast<sal_Int32>(maImageList.size()-1) )
212
0
        ++mnCurStep;
213
0
    else
214
0
    {
215
0
        if ( mbRepeat )
216
0
        {
217
            // start over
218
0
            mnCurStep = 0;
219
0
        }
220
0
        else
221
0
        {
222
0
            stop();
223
0
        }
224
0
    }
225
226
0
    SetImage( maImageList[ mnCurStep ] );
227
0
}
228
229
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */