1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include "precompiled_vcl.hxx" 23 24 #include "vcl/throbber.hxx" 25 #include "vcl/svapp.hxx" 26 27 #include <com/sun/star/graphic/XGraphicProvider.hpp> 28 #include <com/sun/star/awt/ImageScaleMode.hpp> 29 30 #include <comphelper/componentcontext.hxx> 31 #include <comphelper/namedvaluecollection.hxx> 32 #include <comphelper/processfactory.hxx> 33 #include <rtl/ustrbuf.hxx> 34 #include <tools/diagnose_ex.h> 35 #include <tools/urlobj.hxx> 36 37 #include <limits> 38 39 using ::com::sun::star::uno::Sequence; 40 using ::com::sun::star::uno::Reference; 41 using ::com::sun::star::graphic::XGraphic; 42 using ::com::sun::star::graphic::XGraphicProvider; 43 using ::com::sun::star::uno::UNO_QUERY_THROW; 44 using ::com::sun::star::uno::UNO_QUERY; 45 using ::com::sun::star::uno::Exception; 46 namespace ImageScaleMode = ::com::sun::star::awt::ImageScaleMode; 47 48 //---------------------------------------------------------------------------------------------------------------------- 49 Throbber::Throbber( Window* i_parentWindow, WinBits i_style, const ImageSet i_imageSet ) 50 :ImageControl( i_parentWindow, i_style ) 51 ,mbRepeat( sal_True ) 52 ,mnStepTime( 100 ) 53 ,mnCurStep( 0 ) 54 ,mnStepCount( 0 ) 55 ,meImageSet( i_imageSet ) 56 { 57 maWaitTimer.SetTimeout( mnStepTime ); 58 maWaitTimer.SetTimeoutHdl( LINK( this, Throbber, TimeOutHdl ) ); 59 60 SetScaleMode( ImageScaleMode::NONE ); 61 initImages(); 62 } 63 64 //-------------------------------------------------------------------- 65 Throbber::Throbber( Window* i_parentWindow, const ResId& i_resId, const ImageSet i_imageSet ) 66 :ImageControl( i_parentWindow, i_resId ) 67 ,mbRepeat( sal_True ) 68 ,mnStepTime( 100 ) 69 ,mnCurStep( 0 ) 70 ,mnStepCount( 0 ) 71 ,meImageSet( i_imageSet ) 72 { 73 maWaitTimer.SetTimeout( mnStepTime ); 74 maWaitTimer.SetTimeoutHdl( LINK( this, Throbber, TimeOutHdl ) ); 75 76 SetScaleMode( ImageScaleMode::NONE ); 77 initImages(); 78 } 79 80 //---------------------------------------------------------------------------------------------------------------------- 81 Throbber::~Throbber() 82 { 83 maWaitTimer.Stop(); 84 } 85 86 //---------------------------------------------------------------------------------------------------------------------- 87 namespace 88 { 89 ::std::vector< Image > lcl_loadImageSet( const Throbber::ImageSet i_imageSet, const bool i_isHiContrast ) 90 { 91 ::std::vector< Image > aImages; 92 ENSURE_OR_RETURN( i_imageSet != Throbber::IMAGES_NONE, "lcl_loadImageSet: illegal image set", aImages ); 93 94 const ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() ); 95 const Reference< XGraphicProvider > xGraphicProvider( aContext.createComponent( "com.sun.star.graphic.GraphicProvider" ), UNO_QUERY_THROW ); 96 97 ::std::vector< ::rtl::OUString > aImageURLs( Throbber::getDefaultImageURLs( i_imageSet ) ); 98 aImages.reserve( aImageURLs.size() ); 99 100 ::comphelper::NamedValueCollection aMediaProperties; 101 for ( ::std::vector< ::rtl::OUString >::const_iterator imageURL = aImageURLs.begin(); 102 imageURL != aImageURLs.end(); 103 ++imageURL 104 ) 105 { 106 Reference< XGraphic > xGraphic; 107 if ( i_isHiContrast ) 108 { 109 INetURLObject aURL( *imageURL ); 110 if ( aURL.GetProtocol() != INET_PROT_PRIV_SOFFICE ) 111 { 112 const sal_Int32 separatorPos = imageURL->lastIndexOf( '/' ); 113 if ( separatorPos != -1 ) 114 { 115 ::rtl::OUStringBuffer composer; 116 composer.append( imageURL->copy( 0, separatorPos ) ); 117 composer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "/hicontrast" ) ); 118 composer.append( imageURL->copy( separatorPos ) ); 119 120 aMediaProperties.put( "URL", composer.makeStringAndClear() ); 121 xGraphic.set( xGraphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); 122 } 123 } 124 } 125 if ( !xGraphic.is() ) 126 { 127 aMediaProperties.put( "URL", *imageURL ); 128 xGraphic.set( xGraphicProvider->queryGraphic( aMediaProperties.getPropertyValues() ), UNO_QUERY ); 129 } 130 aImages.push_back( Image( xGraphic ) ); 131 } 132 133 return aImages; 134 } 135 } 136 137 //---------------------------------------------------------------------------------------------------------------------- 138 void Throbber::Resize() 139 { 140 ImageControl::Resize(); 141 142 if ( meImageSet == IMAGES_AUTO ) 143 initImages(); 144 } 145 146 //---------------------------------------------------------------------------------------------------------------------- 147 void Throbber::initImages() 148 { 149 if ( meImageSet == IMAGES_NONE ) 150 return; 151 152 try 153 { 154 ::std::vector< ::std::vector< Image > > aImageSets; 155 const bool isHiContrast = GetSettings().GetStyleSettings().GetHighContrastMode(); 156 if ( meImageSet == IMAGES_AUTO ) 157 { 158 aImageSets.push_back( lcl_loadImageSet( IMAGES_16_PX, isHiContrast ) ); 159 aImageSets.push_back( lcl_loadImageSet( IMAGES_32_PX, isHiContrast ) ); 160 aImageSets.push_back( lcl_loadImageSet( IMAGES_64_PX, isHiContrast ) ); 161 } 162 else 163 { 164 aImageSets.push_back( lcl_loadImageSet( meImageSet, isHiContrast ) ); 165 } 166 167 // find the best matching image set (size-wise) 168 const ::Size aWindowSizePixel = GetSizePixel(); 169 size_t nPreferredSet = 0; 170 if ( aImageSets.size() > 1 ) 171 { 172 long nMinimalDistance = ::std::numeric_limits< long >::max(); 173 for ( ::std::vector< ::std::vector< Image > >::const_iterator check = aImageSets.begin(); 174 check != aImageSets.end(); 175 ++check 176 ) 177 { 178 ENSURE_OR_CONTINUE( !check->empty(), "Throbber::initImages: illegal image!" ); 179 const Size aImageSize = (*check)[0].GetSizePixel(); 180 181 if ( ( aImageSize.Width() > aWindowSizePixel.Width() ) 182 || ( aImageSize.Height() > aWindowSizePixel.Height() ) 183 ) 184 // do not use an image set which doesn't fit into the window 185 continue; 186 187 const sal_Int64 distance = 188 ( aWindowSizePixel.Width() - aImageSize.Width() ) * ( aWindowSizePixel.Width() - aImageSize.Width() ) 189 + ( aWindowSizePixel.Height() - aImageSize.Height() ) * ( aWindowSizePixel.Height() - aImageSize.Height() ); 190 if ( distance < nMinimalDistance ) 191 { 192 nMinimalDistance = distance; 193 nPreferredSet = check - aImageSets.begin(); 194 } 195 } 196 } 197 198 if ( nPreferredSet < aImageSets.size() ) 199 setImageList( aImageSets[nPreferredSet] ); 200 } 201 catch( const Exception& ) 202 { 203 DBG_UNHANDLED_EXCEPTION(); 204 } 205 } 206 207 //---------------------------------------------------------------------------------------------------------------------- 208 void Throbber::start() 209 { 210 maWaitTimer.Start(); 211 } 212 213 //---------------------------------------------------------------------------------------------------------------------- 214 void Throbber::stop() 215 { 216 maWaitTimer.Stop(); 217 } 218 219 //---------------------------------------------------------------------------------------------------------------------- 220 bool Throbber::isRunning() const 221 { 222 return maWaitTimer.IsActive(); 223 } 224 225 //---------------------------------------------------------------------------------------------------------------------- 226 void Throbber::setImageList( ::std::vector< Image > const& i_images ) 227 { 228 maImageList = i_images; 229 230 mnStepCount = maImageList.size(); 231 const Image aInitialImage( mnStepCount ? maImageList[ 0 ] : Image() ); 232 SetImage( aInitialImage ); 233 } 234 235 //---------------------------------------------------------------------------------------------------------------------- 236 void Throbber::setImageList( const Sequence< Reference< XGraphic > >& rImageList ) 237 { 238 ::std::vector< Image > aImages( rImageList.getLength() ); 239 ::std::copy( 240 rImageList.getConstArray(), 241 rImageList.getConstArray() + rImageList.getLength(), 242 aImages.begin() 243 ); 244 setImageList( aImages ); 245 } 246 247 //---------------------------------------------------------------------------------------------------------------------- 248 ::std::vector< ::rtl::OUString > Throbber::getDefaultImageURLs( const ImageSet i_imageSet ) 249 { 250 ::std::vector< ::rtl::OUString > aImageURLs; 251 252 sal_Char const* const pResolutions[] = { "16", "32", "64" }; 253 size_t const nImageCounts[] = { 12, 12, 12 }; 254 255 size_t index = 0; 256 switch ( i_imageSet ) 257 { 258 case IMAGES_16_PX: index = 0; break; 259 case IMAGES_32_PX: index = 1; break; 260 case IMAGES_64_PX: index = 2; break; 261 case IMAGES_NONE: 262 case IMAGES_AUTO: 263 OSL_ENSURE( false, "Throbber::getDefaultImageURLs: illegal image set!" ); 264 return aImageURLs; 265 } 266 267 aImageURLs.reserve( nImageCounts[index] ); 268 for ( size_t i=0; i<nImageCounts[index]; ++i ) 269 { 270 ::rtl::OUStringBuffer aURL; 271 aURL.appendAscii( "private:graphicrepository/vcl/res/spinner-" ); 272 aURL.appendAscii( pResolutions[index] ); 273 aURL.appendAscii( "-" ); 274 if ( i < 9 ) 275 aURL.appendAscii( "0" ); 276 aURL.append ( sal_Int32( i + 1 ) ); 277 aURL.appendAscii( ".png" ); 278 279 aImageURLs.push_back( aURL.makeStringAndClear() ); 280 } 281 282 return aImageURLs; 283 } 284 285 //---------------------------------------------------------------------------------------------------------------------- 286 IMPL_LINK( Throbber, TimeOutHdl, void*, EMPTYARG ) 287 { 288 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 289 if ( maImageList.empty() ) 290 return 0; 291 292 if ( mnCurStep < mnStepCount - 1 ) 293 mnCurStep += 1; 294 else 295 { 296 if ( mbRepeat ) 297 { 298 // start over 299 mnCurStep = 0; 300 } 301 else 302 { 303 stop(); 304 } 305 } 306 307 SetImage( maImageList[ mnCurStep ] ); 308 309 return 0; 310 } 311 312 /* vim: set noet sw=4 ts=4: */ 313