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>
00032 #include <Plasma/PackageMetadata>
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 BackgroundPackageStructure(QObject *parent = 0);
00147 private:
00148 void addResolution(const char *res);
00149 };
00150
00151 BackgroundPackageStructure::BackgroundPackageStructure(QObject *parent)
00152 : PackageStructure(parent, "Background")
00153 {
00154 QStringList mimetypes;
00155 mimetypes << "image/svg" << "image/png" << "image/jpeg" << "image/jpg";
00156 setDefaultMimetypes(mimetypes);
00157
00158 addDirectoryDefinition("images", "images", i18n("Images"));
00159 addFileDefinition("screenshot", "screenshot.png", i18n("Screenshot"));
00160 setAllowExternalPaths(true);
00161 }
00162
00163
00164
00165 BackgroundPackage::BackgroundPackage(const QString &path, float ratio)
00166 : Package(path, KSharedPtr<Plasma::PackageStructure>(new BackgroundPackageStructure(this))),
00167 m_path(path),
00168 m_ratio(ratio)
00169 {
00170 }
00171
00172 QString BackgroundPackage::resString(const QSize &size) const
00173 {
00174 return QString::number(size.width()) + 'x' + QString::number(size.height());
00175 }
00176
00177 QSize BackgroundPackage::resSize(const QString &str) const
00178 {
00179 int index = str.indexOf('x');
00180 if (index != -1) {
00181 return QSize(str.left(index).toInt(),
00182 str.mid(index + 1).toInt());
00183 }
00184 else {
00185 return QSize();
00186 }
00187 }
00188
00189 QString BackgroundPackage::findBackground(const QSize &size,
00190 ResizeMethod method) const
00191 {
00192 QStringList images = entryList("images");
00193 if (images.empty()) {
00194 return QString();
00195 }
00196
00197
00198
00199
00200 float best = FLT_MAX;
00201 QString bestImage;
00202 foreach (const QString &entry, images) {
00203 QSize candidate = resSize(QFileInfo(entry).baseName());
00204 if (candidate == QSize()) {
00205 continue;
00206 }
00207
00208 double dist = distance(candidate, size, method);
00209
00210 if (bestImage.isNull() || dist < best) {
00211 bestImage = filePath("images", entry);
00212 best = dist;
00213
00214 if (dist == 0) {
00215 break;
00216 }
00217 }
00218 }
00219
00220
00221 return bestImage;
00222 }
00223
00224 float BackgroundPackage::distance(const QSize& size,
00225 const QSize& desired,
00226 ResizeMethod method) const
00227 {
00228
00229 float delta = size.width() * size.height() -
00230 desired.width() * desired.height();
00231
00232 delta /= ((desired.width() * desired.height())+(size.width() * size.height()))/2;
00233
00234
00235 switch (method) {
00236 case Scale: {
00237
00238
00239 float deltaRatio = 1.0;
00240 if (size.height() > 0 && desired.height() > 0) {
00241 deltaRatio = float(size.width()) / float(size.height()) -
00242 float(desired.width()) / float(desired.height());
00243 }
00244 return fabs(deltaRatio) * 3.0 + (delta >= 0.0 ? delta : -delta + 5.0);
00245 }
00246 case ScaleCrop:
00247
00248 return delta >= 0.0 ? delta : -delta + 2.0;
00249 case Center:
00250 default:
00251
00252 return fabs(delta);
00253 }
00254 }
00255
00256 QPixmap BackgroundPackage::screenshot() const
00257 {
00258 if (m_screenshot.isNull()) {
00259 QString screenshotPath = filePath("screenshot");
00260 if (!screenshotPath.isEmpty()) {
00261 QImage img = createScreenshot(screenshotPath, m_ratio);
00262 m_screenshot = QPixmap::fromImage(img);
00263 }
00264 }
00265
00266 return m_screenshot;
00267 }
00268
00269 bool BackgroundPackage::screenshotGenerationStarted() const
00270 {
00271 return true;
00272 }
00273
00274 void BackgroundPackage::generateScreenshot(QPersistentModelIndex) const
00275 {
00276 }
00277
00278 QString BackgroundPackage::title() const
00279 {
00280 Plasma::PackageMetadata md = metadata();
00281 QString title = md.name();
00282 if (title.isEmpty()) {
00283 title = md.pluginName();
00284 title.replace("_", " ");
00285 }
00286 return title;
00287 }
00288
00289 QString BackgroundPackage::author() const
00290 {
00291 return metadata().author();
00292 }
00293
00294 QString BackgroundPackage::email() const
00295 {
00296 return metadata().email();
00297 }
00298
00299 QString BackgroundPackage::license() const
00300 {
00301 return metadata().license();
00302 }
00303
00304 bool BackgroundPackage::isValid() const
00305 {
00306 return Package::isValid();
00307 }
00308
00309 QString BackgroundPackage::path() const
00310 {
00311 return m_path;
00312 }
00313
00314
00315 BackgroundFile::BackgroundFile(const QString &file, float ratio)
00316 : m_file(file)
00317 , m_ratio(ratio)
00318 , m_resizer_started(false)
00319 {
00320 }
00321
00322 BackgroundFile::~BackgroundFile()
00323 {
00324 }
00325
00326 QString BackgroundFile::findBackground(const QSize &,
00327 ResizeMethod) const
00328 {
00329 return m_file;
00330 }
00331
00332 QPixmap BackgroundFile::screenshot() const
00333 {
00334 return m_screenshot;
00335 }
00336
00337 bool BackgroundFile::screenshotGenerationStarted() const
00338 {
00339 return m_resizer_started;
00340 }
00341
00342 void BackgroundFile::generateScreenshot(QPersistentModelIndex index) const
00343 {
00344 ResizeThread *resizer = new ResizeThread(m_file, m_ratio);
00345 connect(resizer, SIGNAL(done(ThreadWeaver::Job *)),
00346 this, SLOT(updateScreenshot(ThreadWeaver::Job *)));
00347 m_resizer_started = true;
00348 resizer->start(index);
00349 }
00350
00351 void BackgroundFile::updateScreenshot(ThreadWeaver::Job *job)
00352 {
00353 ResizeThread *resizer = static_cast<ResizeThread *>(job);
00354 m_screenshot = QPixmap::fromImage(resizer->result());
00355 emit screenshotDone(resizer->index());
00356 resizer->deleteLater();
00357 }
00358
00359
00360 QString BackgroundFile::author() const
00361 {
00362 return QString();
00363 }
00364
00365 QString BackgroundFile::title() const
00366 {
00367 return QFileInfo(m_file).completeBaseName();
00368 }
00369
00370
00371 QString BackgroundFile::email() const
00372 {
00373 return QString();
00374 }
00375
00376
00377 QString BackgroundFile::license() const
00378 {
00379 return QString();
00380 }
00381
00382
00383 bool BackgroundFile::isValid() const
00384 {
00385 return true;
00386 }
00387
00388 QString BackgroundFile::path() const
00389 {
00390 return m_file;
00391 }