Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / plasma / containments / desktop / backgroundpackage.cpp
blob4813f3af5a2c029350fa2085e9fd5015fc54c6e7
1 /*
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"
20 #include <cmath>
21 // <cmath> does not define fabs (by the standard, even if it does with gcc)
22 #include <math.h>
24 #include <QFileInfo>
25 #include <QPainter>
26 #include <KDebug>
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
38 public:
39 ResizeThread(const QString &path, float ratio, QObject *parent = 0);
40 virtual ~ResizeThread();
42 virtual void start(QPersistentModelIndex index);
43 virtual void run();
45 QImage result() const;
46 QPersistentModelIndex index() const;
47 bool isInitialized() const;
48 private:
49 QString m_path;
50 QImage m_result;
51 float m_ratio;
52 QPersistentModelIndex m_index;
55 ResizeThread::ResizeThread(const QString &path, float ratio, QObject *parent)
56 : ThreadWeaver::Job(parent)
57 , m_path(path)
58 , m_ratio(ratio)
62 ResizeThread::~ResizeThread() {
65 void ResizeThread::start(QPersistentModelIndex index)
67 m_index = 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
83 if (isFinished()) {
84 return m_result;
86 else {
87 return QImage();
91 QPersistentModelIndex ResizeThread::index() const
93 return m_index;
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);
106 img.fill(0);
107 QPainter p(&img);
108 renderer.render(&p);
109 return img;
111 else {
112 QImage img(path);
113 if (!img.isNull()) {
114 return img.scaled(int(SCREENSHOT_HEIGHT * ratio),
115 SCREENSHOT_HEIGHT,
116 Qt::KeepAspectRatio);
118 else {
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);
131 img.fill(Qt::white);
132 QPainter p(&img);
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
144 public:
145 static const PackageStructure::Ptr self();
146 private:
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);
167 if (!instance) {
168 instance = new BackgroundPackageStructure;
171 return instance;
176 BackgroundPackage::BackgroundPackage(const QString &path, float ratio)
177 : Package(path, BackgroundPackageStructure::self())
178 , m_path(path)
179 , m_ratio(ratio)
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');
191 if (index != -1) {
192 return QSize(str.left(index).toInt(),
193 str.mid(index + 1).toInt());
195 else {
196 return QSize();
200 QString BackgroundPackage::findBackground(const QSize &size,
201 ResizeMethod method) const
203 QStringList images = entryList("images");
204 if (images.empty()) {
205 return QString();
208 // choose the nearest resolution
209 float best;
210 QString bestImage;
211 foreach (const QString &entry, images) {
212 QSize candidate = resSize(QFileInfo(entry).baseName());
213 if (candidate == QSize()) {
214 continue;
217 double dist = distance(candidate, size, method);
218 kDebug() << "candidate" << candidate << "distance" << dist;
219 if (bestImage.isNull() || dist < best) {
220 bestImage = filePath("images", entry);
221 best = dist;
222 kDebug() << "best" << bestImage;
226 kDebug() << "best image" << bestImage;
227 return 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
238 delta /= 1000000.0;
240 switch (method) {
241 case Scale: {
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);
249 case ScaleCrop:
250 // Difference of areas, slight preference to scale down
251 return delta >= 0.0 ? delta : -delta + 2.0;
252 case Center:
253 default:
254 // Difference in areas
255 return fabs(delta);
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);
269 return m_screenshot;
272 bool BackgroundPackage::screenshotGenerationStarted() const
274 return true;
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
308 return m_path;
312 BackgroundFile::BackgroundFile(const QString &file, float ratio)
313 : m_file(file)
314 , m_ratio(ratio)
315 , m_resizer_started(false)
319 BackgroundFile::~BackgroundFile()
323 QString BackgroundFile::findBackground(const QSize &,
324 ResizeMethod) const
326 return m_file;
329 QPixmap BackgroundFile::screenshot() const
331 return m_screenshot;
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
358 return QString();
361 QString BackgroundFile::title() const
363 return QFileInfo(m_file).baseName();
366 QString BackgroundFile::email() const
368 return QString();
371 QString BackgroundFile::license() const
373 return QString();
376 bool BackgroundFile::isValid() const
378 return true;
381 QString BackgroundFile::path() const
383 return m_file;