00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "backgroundpackage.h"
00020 #include <cmath>
00021
00022 #include <math.h>
00023 #include <float.h>
00024
00025 #include <QFileInfo>
00026 #include <QPainter>
00027 #include <KDebug>
00028 #include <KLocalizedString>
00029 #include <KStandardDirs>
00030 #include <KSvgRenderer>
00031 #include <plasma/packagestructure.h>
00032 #include <plasma/packagemetadata.h>
00033 #include <ThreadWeaver/Weaver>
00034
00035 using namespace Plasma;
00036
00037 class ResizeThread : public ThreadWeaver::Job
00038 {
00039 public:
00040 ResizeThread(const QString &path, float ratio, QObject *parent = 0);
00041 virtual ~ResizeThread();
00042
00043 virtual void start(QPersistentModelIndex index);
00044 virtual void run();
00045
00046 QImage result() const;
00047 QPersistentModelIndex index() const;
00048 bool isInitialized() const;
00049 private:
00050 QString m_path;
00051 QImage m_result;
00052 float m_ratio;
00053 QPersistentModelIndex m_index;
00054 };
00055
00056 ResizeThread::ResizeThread(const QString &path, float ratio, QObject *parent)
00057 : ThreadWeaver::Job(parent)
00058 , m_path(path)
00059 , m_ratio(ratio)
00060 {
00061 }
00062
00063 ResizeThread::~ResizeThread() {
00064 }
00065
00066 void ResizeThread::start(QPersistentModelIndex index)
00067 {
00068 m_index = index;
00069 ThreadWeaver::Weaver::instance()->enqueue(this);
00070 }
00071
00072 bool ResizeThread::isInitialized() const
00073 {
00074 return m_index.isValid();
00075 }
00076
00077 void ResizeThread::run()
00078 {
00079 m_result = Background::createScreenshot(m_path, m_ratio);
00080 }
00081
00082 QImage ResizeThread::result() const
00083 {
00084 if (isFinished()) {
00085 return m_result;
00086 }
00087 else {
00088 return QImage();
00089 }
00090 }
00091
00092 QPersistentModelIndex ResizeThread::index() const
00093 {
00094 return m_index;
00095 }
00096
00097 Background::~Background()
00098 {
00099 }
00100
00101 QImage Background::createScreenshot(const QString &path, float ratio)
00102 {
00103 if (path.endsWith("svg") || path.endsWith("svgz")) {
00104 KSvgRenderer renderer(path);
00105 QImage img(QSize(int(SCREENSHOT_HEIGHT * ratio), SCREENSHOT_HEIGHT),
00106 QImage::Format_ARGB32_Premultiplied);
00107 img.fill(0);
00108 QPainter p(&img);
00109 renderer.render(&p);
00110 return img;
00111 }
00112 else {
00113 QImage img(path);
00114 if (!img.isNull()) {
00115 return img.scaled(int(SCREENSHOT_HEIGHT * ratio),
00116 SCREENSHOT_HEIGHT,
00117 Qt::KeepAspectRatio);
00118 }
00119 else {
00120 return defaultScreenshot();
00121 }
00122 }
00123
00124 }
00125
00126 QImage Background::defaultScreenshot()
00127 {
00128 static QImage defaultScreenshotImage;
00129
00130 if (defaultScreenshotImage.isNull()) {
00131 QImage img(QSize(SCREENSHOT_HEIGHT, SCREENSHOT_HEIGHT), QImage::Format_ARGB32_Premultiplied);
00132 img.fill(Qt::white);
00133 QPainter p(&img);
00134 p.drawText(QRect(0, 0, SCREENSHOT_HEIGHT, SCREENSHOT_HEIGHT),
00135 Qt::AlignHCenter | Qt::AlignVCenter,
00136 "Preview\nnot\navailable");
00137 defaultScreenshotImage = img;
00138 }
00139 return defaultScreenshotImage;
00140 }
00141
00142
00143 class BackgroundPackageStructure : public PackageStructure
00144 {
00145 public:
00146 static const PackageStructure::Ptr self();
00147 private:
00148 BackgroundPackageStructure();
00149 void addResolution(const char *res);
00150 };
00151
00152 BackgroundPackageStructure::BackgroundPackageStructure()
00153 : PackageStructure(0, "Background")
00154 {
00155 QStringList mimetypes;
00156 mimetypes << "image/svg" << "image/png" << "image/jpeg" << "image/jpg";
00157 setDefaultMimetypes(mimetypes);
00158
00159 addDirectoryDefinition("images", "images", i18n("Images"));
00160 addFileDefinition("screenshot", "screenshot.png", i18n("Screenshot"));
00161 }
00162
00163
00164 const PackageStructure::Ptr BackgroundPackageStructure::self()
00165 {
00166 static BackgroundPackageStructure::Ptr instance(0);
00167
00168 if (!instance) {
00169 instance = new BackgroundPackageStructure;
00170 }
00171
00172 return instance;
00173 }
00174
00175
00176
00177 BackgroundPackage::BackgroundPackage(const QString &path, float ratio)
00178 : Package(path, BackgroundPackageStructure::self())
00179 , m_path(path)
00180 , m_ratio(ratio)
00181 {
00182 }
00183
00184 QString BackgroundPackage::resString(const QSize &size) const
00185 {
00186 return QString::number(size.width()) + 'x' + QString::number(size.height());
00187 }
00188
00189 QSize BackgroundPackage::resSize(const QString &str) const
00190 {
00191 int index = str.indexOf('x');
00192 if (index != -1) {
00193 return QSize(str.left(index).toInt(),
00194 str.mid(index + 1).toInt());
00195 }
00196 else {
00197 return QSize();
00198 }
00199 }
00200
00201 QString BackgroundPackage::findBackground(const QSize &size,
00202 ResizeMethod method) const
00203 {
00204 QStringList images = entryList("images");
00205 if (images.empty()) {
00206 return QString();
00207 }
00208
00209
00210 float best = FLT_MAX;
00211 QString bestImage;
00212 foreach (const QString &entry, images) {
00213 QSize candidate = resSize(QFileInfo(entry).baseName());
00214 if (candidate == QSize()) {
00215 continue;
00216 }
00217
00218 double dist = distance(candidate, size, method);
00219 kDebug() << "candidate" << candidate << "distance" << dist;
00220 if (bestImage.isNull() || dist < best) {
00221 bestImage = filePath("images", entry);
00222 best = dist;
00223 kDebug() << "best" << bestImage;
00224 if (dist == 0) {
00225 break;
00226 }
00227 }
00228 }
00229
00230 kDebug() << "best image" << bestImage;
00231 return bestImage;
00232 }
00233
00234 float BackgroundPackage::distance(const QSize& size,
00235 const QSize& desired,
00236 ResizeMethod method) const
00237 {
00238
00239 float delta = size.width() * size.height() -
00240 desired.width() * desired.height();
00241
00242 delta /= 1000000.0;
00243
00244 switch (method) {
00245 case Scale: {
00246
00247
00248 float deltaRatio = size.width() / size.height() -
00249 desired.width() / desired.height();
00250 return fabs(deltaRatio) * 3.0 +
00251 (delta >= 0.0 ? delta : -delta + 5.0);
00252 }
00253 case ScaleCrop:
00254
00255 return delta >= 0.0 ? delta : -delta + 2.0;
00256 case Center:
00257 default:
00258
00259 return fabs(delta);
00260 }
00261 }
00262
00263 QPixmap BackgroundPackage::screenshot() const
00264 {
00265 if (m_screenshot.isNull()) {
00266 QString screenshotPath = filePath("screenshot");
00267 if (!screenshotPath.isEmpty()) {
00268 QImage img = createScreenshot(screenshotPath, m_ratio);
00269 m_screenshot = QPixmap::fromImage(img);
00270 }
00271 }
00272
00273 return m_screenshot;
00274 }
00275
00276 bool BackgroundPackage::screenshotGenerationStarted() const
00277 {
00278 return true;
00279 }
00280
00281 void BackgroundPackage::generateScreenshot(QPersistentModelIndex) const
00282 {
00283 }
00284
00285 QString BackgroundPackage::title() const
00286 {
00287 QString title = metadata()->name();
00288 if (title.isEmpty()) {
00289 title = metadata()->pluginName();
00290 title.replace("_", " ");
00291 }
00292 return title;
00293 }
00294
00295 QString BackgroundPackage::author() const
00296 {
00297 return metadata()->author();
00298 }
00299
00300 QString BackgroundPackage::email() const
00301 {
00302 return metadata()->email();
00303 }
00304
00305 QString BackgroundPackage::license() const
00306 {
00307 return metadata()->license();
00308 }
00309
00310 bool BackgroundPackage::isValid() const
00311 {
00312 return Package::isValid();
00313 }
00314
00315 QString BackgroundPackage::path() const
00316 {
00317 return m_path;
00318 }
00319
00320
00321 BackgroundFile::BackgroundFile(const QString &file, float ratio)
00322 : m_file(file)
00323 , m_ratio(ratio)
00324 , m_resizer_started(false)
00325 {
00326 }
00327
00328 BackgroundFile::~BackgroundFile()
00329 {
00330 }
00331
00332 QString BackgroundFile::findBackground(const QSize &,
00333 ResizeMethod) const
00334 {
00335 return m_file;
00336 }
00337
00338 QPixmap BackgroundFile::screenshot() const
00339 {
00340 return m_screenshot;
00341 }
00342
00343 bool BackgroundFile::screenshotGenerationStarted() const
00344 {
00345 return m_resizer_started;
00346 }
00347
00348 void BackgroundFile::generateScreenshot(QPersistentModelIndex index) const
00349 {
00350 ResizeThread *resizer = new ResizeThread(m_file, m_ratio);
00351 connect(resizer, SIGNAL(done(ThreadWeaver::Job *)),
00352 this, SLOT(updateScreenshot(ThreadWeaver::Job *)));
00353 m_resizer_started = true;
00354 resizer->start(index);
00355 }
00356
00357 void BackgroundFile::updateScreenshot(ThreadWeaver::Job *job)
00358 {
00359 ResizeThread *resizer = static_cast<ResizeThread *>(job);
00360 m_screenshot = QPixmap::fromImage(resizer->result());
00361 emit screenshotDone(resizer->index());
00362 resizer->deleteLater();
00363 }
00364
00365 QString BackgroundFile::author() const
00366 {
00367 return QString();
00368 }
00369
00370 QString BackgroundFile::title() const
00371 {
00372 return QFileInfo(m_file).baseName();
00373 }
00374
00375 QString BackgroundFile::email() const
00376 {
00377 return QString();
00378 }
00379
00380 QString BackgroundFile::license() const
00381 {
00382 return QString();
00383 }
00384
00385 bool BackgroundFile::isValid() const
00386 {
00387 return true;
00388 }
00389
00390 QString BackgroundFile::path() const
00391 {
00392 return m_file;
00393 }