1
/***************************************************************************
2
 *   Copyright (c) 2008  Nikolaj Hald Nielsen <nhnFreespirit@gmail.com>    *
3
 *             (c) 2008  Jeff Mitchell <kde-dev@emailgoeshere.com>         *
4
 *                                                                         *
5
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   it under the terms of the GNU General Public License as published by  *
7
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 *   (at your option) any later version.                                   *
9
 *                                                                         *
10
 *   This program is distributed in the hope that it will be useful,       *
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
 *   GNU General Public License for more details.                          *
14
 *                                                                         *
15
 *   You should have received a copy of the GNU General Public License     *
16
 *   along with this program; if not, write to the                         *
17
 *   Free Software Foundation, Inc.,                                       *
18
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19
 ***************************************************************************/
20
 
21
#include "SvgHandler.h"
22
23
#include "App.h"
24
#include "Debug.h"
25
#include "MainWindow.h"
26
#include "PaletteHandler.h"
27
#include "SvgTinter.h"
28
29
#include <KStandardDirs>
30
31
#include <QHash>
32
#include <QPainter>
33
#include <QPalette>
34
#include <QReadLocker>
35
#include <QWriteLocker>
36
37
38
namespace The {
39
    static SvgHandler* s_SvgHandler_instance = 0;
40
41
    SvgHandler* svgHandler()
42
    {
43
        if( !s_SvgHandler_instance )
44
            s_SvgHandler_instance = new SvgHandler();
45
46
        return s_SvgHandler_instance;
47
    }
48
}
49
50
51
SvgHandler::SvgHandler( QObject* parent )
52
    : QObject( parent )
53
    , m_cache( new KPixmapCache( "Amarok-pixmaps" ) )
54
    , m_themeFile( "amarok/images/default-theme-clean.svg" )  // //use default theme
55
    , m_customTheme( false )
56
{
57
    DEBUG_BLOCK
58
    connect( The::paletteHandler(), SIGNAL( newPalette( const QPalette& ) ), this, SLOT( reTint() ) );
59
}
60
61
SvgHandler::~SvgHandler()
62
{
63
    DEBUG_BLOCK
64
65
    m_cache->deleteCache( "Amarok-pixmaps" ); 
66
    delete m_cache;
67
68
    The::s_SvgHandler_instance = 0;
69
}
70
71
72
bool SvgHandler::loadSvg( const QString& name )
73
{
74
    QString svgFilename;
75
    
76
    if ( !m_customTheme )
77
        svgFilename = KStandardDirs::locate( "data", name );
78
    else
79
        svgFilename = name;
80
    
81
    KSvgRenderer *renderer = new KSvgRenderer( The::svgTinter()->tint( svgFilename ).toAscii() );
82
83
    if ( !renderer->isValid() )
84
    {
85
        debug() << "Bluddy 'ell mateys, aye canna' load ya Ess Vee Gee at " << svgFilename;
86
        delete renderer;
87
        return false;
88
    }
89
    QWriteLocker writeLocker( &m_lock );
90
91
    if( m_renderers[name] )
92
        delete m_renderers[name];
93
94
    m_renderers[name] = renderer;
95
    return true;
96
}
97
98
KSvgRenderer* SvgHandler::getRenderer( const QString& name )
99
{
100
    QReadLocker readLocker( &m_lock );
101
    if( ! m_renderers[name] )
102
    {
103
        readLocker.unlock();
104
        if( !loadSvg( name ) )
105
        {
106
            QWriteLocker writeLocker( &m_lock );
107
            m_renderers[name] = new KSvgRenderer();
108
        }
109
        readLocker.relock();
110
    }
111
    return m_renderers[name];
112
}
113
114
KSvgRenderer * SvgHandler::getRenderer()
115
{
116
    return getRenderer( m_themeFile );
117
}
118
119
QPixmap SvgHandler::renderSvg( const QString &name, const QString& keyname, int width, int height, const QString& element )
120
{
121
    QPixmap pixmap( width, height );
122
    pixmap.fill( Qt::transparent );
123
124
    QReadLocker readLocker( &m_lock );
125
    if( ! m_renderers[name] )
126
    {
127
        readLocker.unlock();
128
        if( !loadSvg( name ) )
129
            return pixmap;
130
        readLocker.relock();
131
    }
132
133
    const QString key = QString("%1:%2x%3")
134
        .arg( keyname )
135
        .arg( width )
136
        .arg( height );
137
138
139
    if ( !m_cache->find( key, pixmap ) ) {
140
//         debug() << QString("svg %1 not in cache...").arg( key );
141
142
        QPainter pt( &pixmap );
143
        if ( element.isEmpty() )
144
            m_renderers[name]->render( &pt, QRectF( 0, 0, width, height ) );
145
        else
146
            m_renderers[name]->render( &pt, element, QRectF( 0, 0, width, height ) );
147
  
148
        m_cache->insert( key, pixmap );
149
    }
150
151
    return pixmap;
152
}
153
154
QPixmap SvgHandler::renderSvg(const QString & keyname, int width, int height, const QString & element)
155
{
156
    return renderSvg( m_themeFile, keyname, width, height, element );
157
}
158
159
QPixmap SvgHandler::renderSvgWithDividers(const QString & keyname, int width, int height, const QString & element)
160
{
161
162
    QString name = m_themeFile;
163
    
164
    QPixmap pixmap( width, height );
165
    pixmap.fill( Qt::transparent );
166
167
    QReadLocker readLocker( &m_lock );
168
    if( ! m_renderers[name] )
169
    {
170
        readLocker.unlock();
171
        if( ! loadSvg( name ) )
172
            return pixmap;
173
        readLocker.relock();
174
    }
175
176
    const QString key = QString("%1:%2x%3-div")
177
            .arg( keyname )
178
            .arg( width )
179
            .arg( height );
180
181
182
    if ( !m_cache->find( key, pixmap ) ) {
183
//         debug() << QString("svg %1 not in cache...").arg( key );
184
185
        QPainter pt( &pixmap );
186
        if ( element.isEmpty() )
187
            m_renderers[name]->render( &pt, QRectF( 0, 0, width, height ) );
188
        else
189
            m_renderers[name]->render( &pt, element, QRectF( 0, 0, width, height ) );
190
191
192
        //add dividers. 5% spacing on each side
193
        int margin = width / 20;
194
        
195
        m_renderers[name]->render( &pt, "divider_top", QRectF( margin, 0 , width - 1 * margin, 1 ) );
196
        m_renderers[name]->render( &pt, "divider_bottom", QRectF( margin, height - 1 , width - 2 * margin, 1 ) );
197
    
198
        m_cache->insert( key, pixmap );
199
    }
200
201
    return pixmap;
202
203
}
204
205
206
void SvgHandler::reTint()
207
{
208
    The::svgTinter()->init();
209
    if ( !loadSvg( m_themeFile ))
210
        warning() << "Unable to load theme file: " << m_themeFile;
211
}
212
213
QString SvgHandler::themeFile()
214
{
215
    return m_themeFile;
216
}
217
218
void SvgHandler::setThemeFile( const QString & themeFile )
219
{
220
    DEBUG_BLOCK
221
    debug() << "got new theme file: " << themeFile;
222
    m_themeFile = themeFile;
223
    m_customTheme = true;
224
    reTint();
225
    
226
    //redraw entire app....
227
    m_cache->discard();
228
    App::instance()->mainWindow()->update();
229
}
230
231
232
QPixmap SvgHandler::addBordersToPixmap( QPixmap orgPixmap, int borderWidth, const QString &name, bool skipCache )
233
{
234
    int newWidth = orgPixmap.width() + borderWidth * 2;
235
    int newHeight = orgPixmap.height() + borderWidth *2;
236
237
    QPixmap pixmap( newWidth, newHeight );
238
    pixmap.fill( Qt::transparent );
239
    
240
    QReadLocker readLocker( &m_lock );
241
    if( !m_renderers[m_themeFile] )
242
    {
243
        readLocker.unlock();
244
        if( !loadSvg( m_themeFile ) )
245
            return pixmap;
246
        readLocker.relock();
247
    }
248
249
    const QString key = QString("%1:%2x%3b%4")
250
            .arg( name )
251
            .arg( newWidth )
252
            .arg( newHeight )
253
            .arg( borderWidth );
254
255
    if( !m_cache->find( key, pixmap ) || skipCache )
256
    {
257
        // Cache miss! We need to create the pixmap
258
259
        //whoops... if skipCache is true, we might actually already have fetched the image, including borders from the cache....
260
        //so we really need to create a blank pixmap here so we don't paint several layers of borders on top of each other
261
        if ( skipCache ) {
262
            pixmap = QPixmap( newWidth, newHeight );
263
            pixmap.fill( Qt::transparent );
264
        }
265
        
266
        QPainter pt( &pixmap );
267
268
        pt.drawPixmap( borderWidth, borderWidth, orgPixmap.width(), orgPixmap.height(), orgPixmap );
269
270
        m_renderers[m_themeFile]->render( &pt, "cover_border_topleft", QRectF( 0, 0, borderWidth, borderWidth ) );
271
        m_renderers[m_themeFile]->render( &pt, "cover_border_top", QRectF( borderWidth, 0, orgPixmap.width(), borderWidth ) );
272
        m_renderers[m_themeFile]->render( &pt, "cover_border_topright", QRectF( newWidth - borderWidth , 0, borderWidth, borderWidth ) );
273
        m_renderers[m_themeFile]->render( &pt, "cover_border_right", QRectF( newWidth - borderWidth, borderWidth, borderWidth, orgPixmap.height() ) );
274
        m_renderers[m_themeFile]->render( &pt, "cover_border_bottomright", QRectF( newWidth - borderWidth, newHeight - borderWidth, borderWidth, borderWidth ) );
275
        m_renderers[m_themeFile]->render( &pt, "cover_border_bottom", QRectF( borderWidth, newHeight - borderWidth, orgPixmap.width(), borderWidth ) );
276
        m_renderers[m_themeFile]->render( &pt, "cover_border_bottomleft", QRectF( 0, newHeight - borderWidth, borderWidth, borderWidth ) );
277
        m_renderers[m_themeFile]->render( &pt, "cover_border_left", QRectF( 0, borderWidth, borderWidth, orgPixmap.height() ) );
278
    
279
        m_cache->insert( key, pixmap );
280
    }
281
282
    return pixmap;
283
}
284
285
#include "SvgHandler.moc"