2 * Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2,
6 * or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
13 * You should have received a copy of the GNU Library General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "backgroundpackage.h"
21 // <cmath> does not define fabs (by the standard, even if it does with gcc)
27 #include <KLocalizedString>
28 #include <KStandardDirs>
29 #include <KSvgRenderer>
30 #include <plasma/packagestructure.h>
31 #include <plasma/packagemetadata.h>
32 #include <ThreadWeaver/Weaver>
34 using namespace Plasma
;
36 class ResizeThread
: public ThreadWeaver::Job
39 ResizeThread(const QString
&path
, float ratio
, QObject
*parent
= 0);
40 virtual ~ResizeThread();
42 virtual void start(QPersistentModelIndex index
);
45 QImage
result() const;
46 QPersistentModelIndex
index() const;
47 bool isInitialized() const;
52 QPersistentModelIndex m_index
;
55 ResizeThread::ResizeThread(const QString
&path
, float ratio
, QObject
*parent
)
56 : ThreadWeaver::Job(parent
)
62 ResizeThread::~ResizeThread() {
65 void ResizeThread::start(QPersistentModelIndex index
)
68 ThreadWeaver::Weaver::instance()->enqueue(this);
71 bool ResizeThread::isInitialized() const
73 return m_index
.isValid();
76 void ResizeThread::run()
78 m_result
= Background::createScreenshot(m_path
, m_ratio
);
81 QImage
ResizeThread::result() const
91 QPersistentModelIndex
ResizeThread::index() const
96 Background::~Background()
100 QImage
Background::createScreenshot(const QString
&path
, float ratio
)
102 if (path
.endsWith("svg") || path
.endsWith("svgz")) {
103 KSvgRenderer
renderer(path
);
104 QImage
img(QSize(int(SCREENSHOT_HEIGHT
* ratio
), SCREENSHOT_HEIGHT
),
105 QImage::Format_ARGB32_Premultiplied
);
114 return img
.scaled(int(SCREENSHOT_HEIGHT
* ratio
),
116 Qt::KeepAspectRatio
);
119 return defaultScreenshot();
125 QImage
Background::defaultScreenshot()
127 static QImage defaultScreenshotImage
;
129 if (defaultScreenshotImage
.isNull()) {
130 QImage
img(QSize(SCREENSHOT_HEIGHT
, SCREENSHOT_HEIGHT
), QImage::Format_ARGB32_Premultiplied
);
133 p
.drawText(QRect(0, 0, SCREENSHOT_HEIGHT
, SCREENSHOT_HEIGHT
),
134 Qt::AlignHCenter
| Qt::AlignVCenter
,
135 "Preview\nnot\navailable");
136 defaultScreenshotImage
= img
;
138 return defaultScreenshotImage
;
142 class BackgroundPackageStructure
: public PackageStructure
145 static const PackageStructure::Ptr
self();
147 BackgroundPackageStructure(); // should be used as a singleton
148 void addResolution(const char *res
);
151 BackgroundPackageStructure::BackgroundPackageStructure()
152 : PackageStructure(0, "Background")
154 QStringList mimetypes
;
155 mimetypes
<< "image/svg" << "image/png" << "image/jpeg" << "image/jpg";
156 setDefaultMimetypes(mimetypes
);
158 addDirectoryDefinition("images", "images", i18n("Images"));
159 addFileDefinition("screenshot", "screenshot.png", i18n("Screenshot"));
163 const PackageStructure::Ptr
BackgroundPackageStructure::self()
165 static BackgroundPackageStructure::Ptr
instance(0);
168 instance
= new BackgroundPackageStructure
;
176 BackgroundPackage::BackgroundPackage(const QString
&path
, float ratio
)
177 : Package(path
, BackgroundPackageStructure::self())
183 QString
BackgroundPackage::resString(const QSize
&size
) const
185 return QString::number(size
.width()) + 'x' + QString::number(size
.height());
188 QSize
BackgroundPackage::resSize(const QString
&str
) const
190 int index
= str
.indexOf('x');
192 return QSize(str
.left(index
).toInt(),
193 str
.mid(index
+ 1).toInt());
200 QString
BackgroundPackage::findBackground(const QSize
&size
,
201 ResizeMethod method
) const
203 QStringList images
= entryList("images");
204 if (images
.empty()) {
208 // choose the nearest resolution
211 foreach (const QString
&entry
, images
) {
212 QSize candidate
= resSize(QFileInfo(entry
).baseName());
213 if (candidate
== QSize()) {
217 double dist
= distance(candidate
, size
, method
);
218 kDebug() << "candidate" << candidate
<< "distance" << dist
;
219 if (bestImage
.isNull() || dist
< best
) {
220 bestImage
= filePath("images", entry
);
222 kDebug() << "best" << bestImage
;
226 kDebug() << "best image" << bestImage
;
230 float BackgroundPackage::distance(const QSize
& size
,
231 const QSize
& desired
,
232 ResizeMethod method
) const
234 // compute difference of areas
235 float delta
= size
.width() * size
.height() -
236 desired
.width() * desired
.height();
237 // scale down to about 1.0
242 // Consider first the difference in aspect ratio,
243 // then in areas. Prefer scaling down.
244 float deltaRatio
= size
.width() / size
.height() -
245 desired
.width() / desired
.height();
246 return fabs(deltaRatio
) * 3.0 +
247 (delta
>= 0.0 ? delta
: -delta
+ 5.0);
250 // Difference of areas, slight preference to scale down
251 return delta
>= 0.0 ? delta
: -delta
+ 2.0;
254 // Difference in areas
259 QPixmap
BackgroundPackage::screenshot() const
261 if (m_screenshot
.isNull()) {
262 QString screenshotPath
= filePath("screenshot");
263 if (!screenshotPath
.isEmpty()) {
264 QImage img
= createScreenshot(screenshotPath
, m_ratio
);
265 m_screenshot
= QPixmap::fromImage(img
);
272 bool BackgroundPackage::screenshotGenerationStarted() const
277 void BackgroundPackage::generateScreenshot(QPersistentModelIndex
) const
281 QString
BackgroundPackage::title() const
283 return metadata()->name();
286 QString
BackgroundPackage::author() const
288 return metadata()->author();
291 QString
BackgroundPackage::email() const
293 return metadata()->email();
296 QString
BackgroundPackage::license() const
298 return metadata()->license();
301 bool BackgroundPackage::isValid() const
303 return Package::isValid();
306 QString
BackgroundPackage::path() const
312 BackgroundFile::BackgroundFile(const QString
&file
, float ratio
)
315 , m_resizer_started(false)
319 BackgroundFile::~BackgroundFile()
323 QString
BackgroundFile::findBackground(const QSize
&,
329 QPixmap
BackgroundFile::screenshot() const
334 bool BackgroundFile::screenshotGenerationStarted() const
336 return m_resizer_started
;
339 void BackgroundFile::generateScreenshot(QPersistentModelIndex index
) const
341 ResizeThread
*resizer
= new ResizeThread(m_file
, m_ratio
);
342 connect(resizer
, SIGNAL(done(ThreadWeaver::Job
*)),
343 this, SLOT(updateScreenshot(ThreadWeaver::Job
*)));
344 m_resizer_started
= true;
345 resizer
->start(index
);
348 void BackgroundFile::updateScreenshot(ThreadWeaver::Job
*job
)
350 ResizeThread
*resizer
= static_cast<ResizeThread
*>(job
);
351 m_screenshot
= QPixmap::fromImage(resizer
->result());
352 emit
screenshotDone(resizer
->index());
353 resizer
->deleteLater();
356 QString
BackgroundFile::author() const
361 QString
BackgroundFile::title() const
363 return QFileInfo(m_file
).baseName();
366 QString
BackgroundFile::email() const
371 QString
BackgroundFile::license() const
376 bool BackgroundFile::isValid() const
381 QString
BackgroundFile::path() const