not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / wallpapers / image / backgroundpackage.cpp
blob680f657032b1356a326a03cb73ce1e5ca8f6e400
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>
23 #include <float.h> // FLT_MAX
25 #include <QFileInfo>
26 #include <QPainter>
27 #include <KDebug>
28 #include <KLocalizedString>
29 #include <KStandardDirs>
30 #include <KSvgRenderer>
31 #include <Plasma/PackageStructure>
32 #include <Plasma/PackageMetadata>
33 #include <ThreadWeaver/Weaver>
35 using namespace Plasma;
37 class ResizeThread : public ThreadWeaver::Job
39 public:
40 ResizeThread(const QString &path, float ratio, QObject *parent = 0);
41 virtual ~ResizeThread();
43 virtual void start(QPersistentModelIndex index);
44 virtual void run();
46 QImage result() const;
47 QPersistentModelIndex index() const;
48 bool isInitialized() const;
49 private:
50 QString m_path;
51 QImage m_result;
52 float m_ratio;
53 QPersistentModelIndex m_index;
56 ResizeThread::ResizeThread(const QString &path, float ratio, QObject *parent)
57 : ThreadWeaver::Job(parent),
58 m_path(path),
59 m_ratio(ratio)
63 ResizeThread::~ResizeThread() {
66 void ResizeThread::start(QPersistentModelIndex index)
68 m_index = index;
69 ThreadWeaver::Weaver::instance()->enqueue(this);
72 bool ResizeThread::isInitialized() const
74 return m_index.isValid();
77 void ResizeThread::run()
79 m_result = Background::createScreenshot(m_path, m_ratio);
82 QImage ResizeThread::result() const
84 if (isFinished()) {
85 return m_result;
87 else {
88 return QImage();
92 QPersistentModelIndex ResizeThread::index() const
94 return m_index;
97 Background::~Background()
101 QImage Background::createScreenshot(const QString &path, float ratio)
103 if (path.endsWith("svg") || path.endsWith("svgz")) {
104 KSvgRenderer renderer(path);
105 QImage img(QSize(int(SCREENSHOT_HEIGHT * ratio), SCREENSHOT_HEIGHT),
106 QImage::Format_ARGB32_Premultiplied);
107 img.fill(0);
108 QPainter p(&img);
109 renderer.render(&p);
110 return img;
112 else {
113 QImage img(path);
114 if (!img.isNull()) {
115 return img.scaled(int(SCREENSHOT_HEIGHT * ratio),
116 SCREENSHOT_HEIGHT,
117 Qt::KeepAspectRatio);
119 else {
120 return defaultScreenshot();
126 QImage Background::defaultScreenshot()
128 static QImage defaultScreenshotImage;
130 if (defaultScreenshotImage.isNull()) {
131 QImage img(QSize(SCREENSHOT_HEIGHT, SCREENSHOT_HEIGHT), QImage::Format_ARGB32_Premultiplied);
132 img.fill(Qt::white);
133 QPainter p(&img);
134 p.drawText(QRect(0, 0, SCREENSHOT_HEIGHT, SCREENSHOT_HEIGHT),
135 Qt::AlignHCenter | Qt::AlignVCenter,
136 "Preview\nnot\navailable");
137 defaultScreenshotImage = img;
139 return defaultScreenshotImage;
143 class BackgroundPackageStructure : public PackageStructure
145 public:
146 BackgroundPackageStructure(QObject *parent = 0);
147 private:
148 void addResolution(const char *res);
151 BackgroundPackageStructure::BackgroundPackageStructure(QObject *parent)
152 : PackageStructure(parent, "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"));
160 setAllowExternalPaths(true);
165 BackgroundPackage::BackgroundPackage(const QString &path, float ratio)
166 : Package(path, KSharedPtr<Plasma::PackageStructure>(new BackgroundPackageStructure(this))),
167 m_path(path),
168 m_ratio(ratio)
172 QString BackgroundPackage::resString(const QSize &size) const
174 return QString::number(size.width()) + 'x' + QString::number(size.height());
177 QSize BackgroundPackage::resSize(const QString &str) const
179 int index = str.indexOf('x');
180 if (index != -1) {
181 return QSize(str.left(index).toInt(),
182 str.mid(index + 1).toInt());
184 else {
185 return QSize();
189 QString BackgroundPackage::findBackground(const QSize &size,
190 ResizeMethod method) const
192 QStringList images = entryList("images");
193 if (images.empty()) {
194 return QString();
197 //kDebug() << "wanted" << size;
199 // choose the nearest resolution
200 float best = FLT_MAX;
201 QString bestImage;
202 foreach (const QString &entry, images) {
203 QSize candidate = resSize(QFileInfo(entry).baseName());
204 if (candidate == QSize()) {
205 continue;
208 double dist = distance(candidate, size, method);
209 //kDebug() << "candidate" << candidate << "distance" << dist;
210 if (bestImage.isNull() || dist < best) {
211 bestImage = filePath("images", entry);
212 best = dist;
213 //kDebug() << "best" << bestImage;
214 if (dist == 0) {
215 break;
220 //kDebug() << "best image" << bestImage;
221 return bestImage;
224 float BackgroundPackage::distance(const QSize& size,
225 const QSize& desired,
226 ResizeMethod method) const
228 // compute difference of areas
229 float delta = size.width() * size.height() -
230 desired.width() * desired.height();
231 // scale down to about 1.0
232 delta /= ((desired.width() * desired.height())+(size.width() * size.height()))/2;
235 switch (method) {
236 case Scale: {
237 // Consider first the difference in aspect ratio,
238 // then in areas. Prefer scaling down.
239 float deltaRatio = 1.0;
240 if (size.height() > 0 && desired.height() > 0) {
241 deltaRatio = float(size.width()) / float(size.height()) -
242 float(desired.width()) / float(desired.height());
244 return fabs(deltaRatio) * 3.0 + (delta >= 0.0 ? delta : -delta + 5.0);
246 case ScaleCrop:
247 // Difference of areas, slight preference to scale down
248 return delta >= 0.0 ? delta : -delta + 2.0;
249 case Center:
250 default:
251 // Difference in areas
252 return fabs(delta);
256 QPixmap BackgroundPackage::screenshot() const
258 if (m_screenshot.isNull()) {
259 QString screenshotPath = filePath("screenshot");
260 if (!screenshotPath.isEmpty()) {
261 QImage img = createScreenshot(screenshotPath, m_ratio);
262 m_screenshot = QPixmap::fromImage(img);
266 return m_screenshot;
269 bool BackgroundPackage::screenshotGenerationStarted() const
271 return true;
274 void BackgroundPackage::generateScreenshot(QPersistentModelIndex) const
278 QString BackgroundPackage::title() const
280 Plasma::PackageMetadata md = metadata();
281 QString title = md.name();
282 if (title.isEmpty()) {
283 title = md.pluginName();
284 title.replace("_", " ");
286 return title;
289 QString BackgroundPackage::author() const
291 return metadata().author();
294 QString BackgroundPackage::email() const
296 return metadata().email();
299 QString BackgroundPackage::license() const
301 return metadata().license();
304 bool BackgroundPackage::isValid() const
306 return Package::isValid();
309 QString BackgroundPackage::path() const
311 return m_path;
315 BackgroundFile::BackgroundFile(const QString &file, float ratio)
316 : m_file(file)
317 , m_ratio(ratio)
318 , m_resizer_started(false)
322 BackgroundFile::~BackgroundFile()
326 QString BackgroundFile::findBackground(const QSize &,
327 ResizeMethod) const
329 return m_file;
332 QPixmap BackgroundFile::screenshot() const
334 return m_screenshot;
337 bool BackgroundFile::screenshotGenerationStarted() const
339 return m_resizer_started;
342 void BackgroundFile::generateScreenshot(QPersistentModelIndex index) const
344 ResizeThread *resizer = new ResizeThread(m_file, m_ratio);
345 connect(resizer, SIGNAL(done(ThreadWeaver::Job *)),
346 this, SLOT(updateScreenshot(ThreadWeaver::Job *)));
347 m_resizer_started = true;
348 resizer->start(index);
351 void BackgroundFile::updateScreenshot(ThreadWeaver::Job *job)
353 ResizeThread *resizer = static_cast<ResizeThread *>(job);
354 m_screenshot = QPixmap::fromImage(resizer->result());
355 emit screenshotDone(resizer->index());
356 resizer->deleteLater();
359 //TODO: impl
360 QString BackgroundFile::author() const
362 return QString();
365 QString BackgroundFile::title() const
367 return QFileInfo(m_file).completeBaseName();
370 //TODO: impl
371 QString BackgroundFile::email() const
373 return QString();
376 //TODO: impl
377 QString BackgroundFile::license() const
379 return QString();
382 //TODO: impl
383 bool BackgroundFile::isValid() const
385 return true;
388 QString BackgroundFile::path() const
390 return m_file;