KIO
previewjob.cpp
Go to the documentation of this file.
00001 // -*- c++ -*- 00002 // vim: ts=4 sw=4 et 00003 /* This file is part of the KDE libraries 00004 Copyright (C) 2000 David Faure <faure@kde.org> 00005 2000 Carsten Pfeiffer <pfeiffer@kde.org> 00006 2001 Malte Starostik <malte.starostik@t-online.de> 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "previewjob.h" 00025 #include <kdebug.h> 00026 00027 #include <sys/stat.h> 00028 #include <sys/types.h> 00029 00030 #ifdef Q_OS_UNIX 00031 #include <sys/ipc.h> 00032 #include <sys/shm.h> 00033 #endif 00034 00035 #include <QtCore/QDir> 00036 #include <QtCore/QFile> 00037 #include <QtGui/QImage> 00038 #include <QtCore/QTimer> 00039 #include <QtCore/QRegExp> 00040 00041 #include <kfileitem.h> 00042 #include <kde_file.h> 00043 #include <ktemporaryfile.h> 00044 #include <kservicetypetrader.h> 00045 #include <kcodecs.h> 00046 #include <kglobal.h> 00047 #include <kstandarddirs.h> 00048 #include <kservice.h> 00049 #include <QtCore/QLinkedList> 00050 #include <kconfiggroup.h> 00051 #include <kprotocolinfo.h> 00052 00053 #include "jobuidelegate.h" 00054 #include "job_p.h" 00055 00056 namespace KIO { struct PreviewItem; } 00057 using namespace KIO; 00058 00059 struct KIO::PreviewItem 00060 { 00061 KFileItem item; 00062 KService::Ptr plugin; 00063 }; 00064 00065 class KIO::PreviewJobPrivate: public KIO::JobPrivate 00066 { 00067 public: 00068 enum { STATE_STATORIG, // if the thumbnail exists 00069 STATE_GETORIG, // if we create it 00070 STATE_CREATETHUMB // thumbnail:/ slave 00071 } state; 00072 PreviewJob *q; 00073 00074 KFileItemList initialItems; 00075 QStringList enabledPlugins; 00076 // Our todo list :) 00077 // We remove the first item at every step, so use QLinkedList 00078 QLinkedList<PreviewItem> items; 00079 // The current item 00080 PreviewItem currentItem; 00081 // The modification time of that URL 00082 time_t tOrig; 00083 // Path to thumbnail cache for the current size 00084 QString thumbPath; 00085 // Original URL of current item in TMS format 00086 // (file:///path/to/file instead of file:/path/to/file) 00087 QString origName; 00088 // Thumbnail file name for current item 00089 QString thumbName; 00090 // Size of thumbnail 00091 int width; 00092 int height; 00093 // Unscaled size of thumbnail (128 or 256 if cache is enabled) 00094 int cacheWidth; 00095 int cacheHeight; 00096 // Whether the thumbnail should be scaled 00097 bool bScale; 00098 // Whether we should save the thumbnail 00099 bool bSave; 00100 bool ignoreMaximumSize; 00101 int sequenceIndex; 00102 bool succeeded; 00103 // If the file to create a thumb for was a temp file, this is its name 00104 QString tempName; 00105 KIO::filesize_t maximumLocalSize; 00106 KIO::filesize_t maximumRemoteSize; 00107 // the size for the icon overlay 00108 int iconSize; 00109 // the transparency of the blended mimetype icon 00110 int iconAlpha; 00111 // Shared memory segment Id. The segment is allocated to a size 00112 // of extent x extent x 4 (32 bit image) on first need. 00113 int shmid; 00114 // And the data area 00115 uchar *shmaddr; 00116 // Root of thumbnail cache 00117 QString thumbRoot; 00118 00119 void getOrCreateThumbnail(); 00120 bool statResultThumbnail(); 00121 void createThumbnail( const QString& ); 00122 void determineNextFile(); 00123 void emitPreview(const QImage &thumb); 00124 00125 void startPreview(); 00126 void slotThumbData(KIO::Job *, const QByteArray &); 00127 00128 Q_DECLARE_PUBLIC(PreviewJob) 00129 }; 00130 00131 #ifndef KDE_NO_DEPRECATED 00132 PreviewJob::PreviewJob( const KFileItemList &items, int width, int height, 00133 int iconSize, int iconAlpha, bool scale, bool save, 00134 const QStringList *enabledPlugins ) 00135 : KIO::Job(*new PreviewJobPrivate) 00136 { 00137 Q_D(PreviewJob); 00138 d->tOrig = 0; 00139 d->shmid = -1; 00140 d->shmaddr = 0; 00141 d->initialItems = items; 00142 d->enabledPlugins = enabledPlugins ? *enabledPlugins : availablePlugins(); 00143 d->width = width; 00144 d->height = height ? height : width; 00145 d->cacheWidth = d->width; 00146 d->cacheHeight = d->height; 00147 d->iconSize = iconSize; 00148 d->iconAlpha = iconAlpha; 00149 d->bScale = scale; 00150 d->bSave = save && scale; 00151 d->succeeded = false; 00152 d->thumbRoot = QDir::homePath() + QLatin1String("/.thumbnails/"); 00153 d->ignoreMaximumSize = false; 00154 d->sequenceIndex = 0; 00155 d->maximumLocalSize = 0; 00156 d->maximumRemoteSize = 0; 00157 00158 // Return to event loop first, determineNextFile() might delete this; 00159 QTimer::singleShot(0, this, SLOT(startPreview())); 00160 } 00161 #endif 00162 00163 PreviewJob::PreviewJob(const KFileItemList &items, 00164 const QSize &size, 00165 const QStringList *enabledPlugins) : 00166 KIO::Job(*new PreviewJobPrivate) 00167 { 00168 Q_D(PreviewJob); 00169 d->tOrig = 0; 00170 d->shmid = -1; 00171 d->shmaddr = 0; 00172 d->initialItems = items; 00173 if (enabledPlugins) { 00174 d->enabledPlugins = *enabledPlugins; 00175 } else { 00176 const KConfigGroup globalConfig(KGlobal::config(), "PreviewSettings"); 00177 d->enabledPlugins = globalConfig.readEntry("Plugins", QStringList() 00178 << "directorythumbnail" 00179 << "imagethumbnail" 00180 << "jpegthumbnail"); 00181 } 00182 d->width = size.width(); 00183 d->height = size.height(); 00184 d->cacheWidth = d->width; 00185 d->cacheHeight = d->height; 00186 d->iconSize = 0; 00187 d->iconAlpha = 70; 00188 d->bScale = true; 00189 d->bSave = true; 00190 d->succeeded = false; 00191 d->thumbRoot = QDir::homePath() + QLatin1String("/.thumbnails/"); 00192 d->ignoreMaximumSize = false; 00193 d->sequenceIndex = 0; 00194 d->maximumLocalSize = 0; 00195 d->maximumRemoteSize = 0; 00196 00197 // Return to event loop first, determineNextFile() might delete this; 00198 QTimer::singleShot(0, this, SLOT(startPreview())); 00199 } 00200 00201 PreviewJob::~PreviewJob() 00202 { 00203 #ifdef Q_OS_UNIX 00204 Q_D(PreviewJob); 00205 if (d->shmaddr) { 00206 shmdt((char*)d->shmaddr); 00207 shmctl(d->shmid, IPC_RMID, 0); 00208 } 00209 #endif 00210 } 00211 00212 void PreviewJob::setOverlayIconSize(int size) 00213 { 00214 Q_D(PreviewJob); 00215 d->iconSize = size; 00216 } 00217 00218 int PreviewJob::overlayIconSize() const 00219 { 00220 Q_D(const PreviewJob); 00221 return d->iconSize; 00222 } 00223 00224 void PreviewJob::setOverlayIconAlpha(int alpha) 00225 { 00226 Q_D(PreviewJob); 00227 d->iconAlpha = qBound(0, alpha, 255); 00228 } 00229 00230 int PreviewJob::overlayIconAlpha() const 00231 { 00232 Q_D(const PreviewJob); 00233 return d->iconAlpha; 00234 } 00235 00236 void PreviewJob::setScaleType(ScaleType type) 00237 { 00238 Q_D(PreviewJob); 00239 switch (type) { 00240 case Unscaled: 00241 d->bScale = false; 00242 d->bSave = false; 00243 break; 00244 case Scaled: 00245 d->bScale = true; 00246 d->bSave = false; 00247 break; 00248 case ScaledAndCached: 00249 d->bScale = true; 00250 d->bSave = true; 00251 break; 00252 default: 00253 break; 00254 } 00255 } 00256 00257 PreviewJob::ScaleType PreviewJob::scaleType() const 00258 { 00259 Q_D(const PreviewJob); 00260 if (d->bScale) { 00261 return d->bSave ? ScaledAndCached : Scaled; 00262 } 00263 return Unscaled; 00264 } 00265 00266 void PreviewJobPrivate::startPreview() 00267 { 00268 Q_Q(PreviewJob); 00269 // Load the list of plugins to determine which mimetypes are supported 00270 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00271 QMap<QString, KService::Ptr> mimeMap; 00272 00273 for (KService::List::ConstIterator it = plugins.constBegin(); it != plugins.constEnd(); ++it) { 00274 if (enabledPlugins.contains((*it)->desktopEntryName())) { 00275 const QStringList mimeTypes = (*it)->serviceTypes(); 00276 for (QStringList::ConstIterator mt = mimeTypes.constBegin(); mt != mimeTypes.constEnd(); ++mt) 00277 mimeMap.insert(*mt, *it); 00278 } 00279 } 00280 00281 // Look for images and store the items in our todo list :) 00282 bool bNeedCache = false; 00283 KFileItemList::const_iterator kit = initialItems.constBegin(); 00284 const KFileItemList::const_iterator kend = initialItems.constEnd(); 00285 for ( ; kit != kend; ++kit ) 00286 { 00287 PreviewItem item; 00288 item.item = *kit; 00289 const QString mimeType = item.item.mimetype(); 00290 QMap<QString, KService::Ptr>::ConstIterator plugin = mimeMap.constFind(mimeType); 00291 if (plugin == mimeMap.constEnd()) 00292 00293 { 00294 QString groupMimeType = mimeType; 00295 groupMimeType.replace(QRegExp("/.*"), "/*"); 00296 plugin = mimeMap.constFind(groupMimeType); 00297 00298 if (plugin == mimeMap.constEnd()) 00299 { 00300 // check mime type inheritance, resolve aliases 00301 const KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases); 00302 if (mimeInfo) { 00303 const QStringList parentMimeTypes = mimeInfo->allParentMimeTypes(); 00304 Q_FOREACH(const QString& parentMimeType, parentMimeTypes) { 00305 plugin = mimeMap.constFind(parentMimeType); 00306 if (plugin != mimeMap.constEnd()) break; 00307 } 00308 } 00309 } 00310 #if 0 // KDE4: should be covered by inheritance above, all text mimetypes inherit from text/plain 00311 // if that's not enough, we need to invent something else 00312 if (plugin == mimeMap.end()) 00313 { 00314 // check X-KDE-Text property 00315 KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType); 00316 QVariant textProperty = mimeInfo->property("X-KDE-text"); 00317 if (textProperty.isValid() && textProperty.type() == QVariant::Bool) 00318 { 00319 if (textProperty.toBool()) 00320 { 00321 plugin = mimeMap.find("text/plain"); 00322 if (plugin == mimeMap.end()) 00323 { 00324 plugin = mimeMap.find( "text/*" ); 00325 } 00326 } 00327 } 00328 } 00329 #endif 00330 } 00331 00332 if (plugin != mimeMap.constEnd()) 00333 { 00334 item.plugin = *plugin; 00335 items.append(item); 00336 if (!bNeedCache && bSave && 00337 ((*kit).url().protocol() != "file" || 00338 !(*kit).url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) && 00339 (*plugin)->property("CacheThumbnail").toBool()) 00340 bNeedCache = true; 00341 } 00342 else 00343 { 00344 emit q->failed( *kit ); 00345 } 00346 } 00347 00348 KConfigGroup cg( KGlobal::config(), "PreviewSettings" ); 00349 maximumLocalSize = cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ ); 00350 maximumRemoteSize = cg.readEntry( "MaximumRemoteSize", 0 ); 00351 00352 if (bNeedCache) 00353 { 00354 if (width <= 128 && height <= 128) cacheWidth = cacheHeight = 128; 00355 else cacheWidth = cacheHeight = 256; 00356 thumbPath = thumbRoot + (cacheWidth == 128 ? "normal/" : "large/"); 00357 KStandardDirs::makeDir(thumbPath, 0700); 00358 } 00359 else 00360 bSave = false; 00361 00362 initialItems.clear(); 00363 determineNextFile(); 00364 } 00365 00366 void PreviewJob::removeItem( const KUrl& url ) 00367 { 00368 Q_D(PreviewJob); 00369 for (QLinkedList<PreviewItem>::Iterator it = d->items.begin(); it != d->items.end(); ++it) 00370 if ((*it).item.url() == url) 00371 { 00372 d->items.erase(it); 00373 break; 00374 } 00375 00376 if (d->currentItem.item.url() == url) 00377 { 00378 KJob* job = subjobs().first(); 00379 job->kill(); 00380 removeSubjob( job ); 00381 d->determineNextFile(); 00382 } 00383 } 00384 00385 void KIO::PreviewJob::setSequenceIndex(int index) { 00386 d_func()->sequenceIndex = index; 00387 } 00388 00389 int KIO::PreviewJob::sequenceIndex() const { 00390 return d_func()->sequenceIndex; 00391 } 00392 00393 void PreviewJob::setIgnoreMaximumSize(bool ignoreSize) 00394 { 00395 d_func()->ignoreMaximumSize = ignoreSize; 00396 } 00397 00398 void PreviewJobPrivate::determineNextFile() 00399 { 00400 Q_Q(PreviewJob); 00401 if (!currentItem.item.isNull()) 00402 { 00403 if (!succeeded) 00404 emit q->failed( currentItem.item ); 00405 } 00406 // No more items ? 00407 if ( items.isEmpty() ) 00408 { 00409 q->emitResult(); 00410 return; 00411 } 00412 else 00413 { 00414 // First, stat the orig file 00415 state = PreviewJobPrivate::STATE_STATORIG; 00416 currentItem = items.first(); 00417 succeeded = false; 00418 items.removeFirst(); 00419 KIO::Job *job = KIO::stat( currentItem.item.url(), KIO::HideProgressInfo ); 00420 job->addMetaData( "no-auth-prompt", "true" ); 00421 q->addSubjob(job); 00422 } 00423 } 00424 00425 void PreviewJob::slotResult( KJob *job ) 00426 { 00427 Q_D(PreviewJob); 00428 00429 removeSubjob(job); 00430 Q_ASSERT ( !hasSubjobs() ); // We should have only one job at a time ... 00431 switch ( d->state ) 00432 { 00433 case PreviewJobPrivate::STATE_STATORIG: 00434 { 00435 if (job->error()) // that's no good news... 00436 { 00437 // Drop this one and move on to the next one 00438 d->determineNextFile(); 00439 return; 00440 } 00441 const KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult(); 00442 d->tOrig = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, 0 ); 00443 00444 bool skipCurrentItem = false; 00445 const KIO::filesize_t size = (KIO::filesize_t)entry.numberValue( KIO::UDSEntry::UDS_SIZE, 0 ); 00446 const KUrl itemUrl = d->currentItem.item.mostLocalUrl(); 00447 if (itemUrl.isLocalFile() || KProtocolInfo::protocolClass(itemUrl.protocol()) == QLatin1String(":local")) 00448 { 00449 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumLocalSize 00450 && !d->currentItem.plugin->property("IgnoreMaximumSize").toBool(); 00451 } 00452 else 00453 { 00454 // For remote items the "IgnoreMaximumSize" plugin property is not respected 00455 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumRemoteSize; 00456 00457 // Remote directories are not supported, don't try to do a file_copy on them 00458 if (!skipCurrentItem) { 00459 // TODO update item.mimeType from the UDS entry, in case it wasn't set initially 00460 KMimeType::Ptr mime = d->currentItem.item.mimeTypePtr(); 00461 if (mime && mime->is("inode/directory")) { 00462 skipCurrentItem = true; 00463 } 00464 } 00465 } 00466 if (skipCurrentItem) 00467 { 00468 d->determineNextFile(); 00469 return; 00470 } 00471 00472 bool pluginHandlesSequences = d->currentItem.plugin->property("HandleSequences", QVariant::Bool).toBool(); 00473 00474 if ( !d->currentItem.plugin->property( "CacheThumbnail" ).toBool() || (d->sequenceIndex && pluginHandlesSequences) ) 00475 { 00476 // This preview will not be cached, no need to look for a saved thumbnail 00477 // Just create it, and be done 00478 d->getOrCreateThumbnail(); 00479 return; 00480 } 00481 00482 if ( d->statResultThumbnail() ) 00483 return; 00484 00485 d->getOrCreateThumbnail(); 00486 return; 00487 } 00488 case PreviewJobPrivate::STATE_GETORIG: 00489 { 00490 if (job->error()) 00491 { 00492 d->determineNextFile(); 00493 return; 00494 } 00495 00496 d->createThumbnail( static_cast<KIO::FileCopyJob*>(job)->destUrl().toLocalFile() ); 00497 return; 00498 } 00499 case PreviewJobPrivate::STATE_CREATETHUMB: 00500 { 00501 if (!d->tempName.isEmpty()) 00502 { 00503 QFile::remove(d->tempName); 00504 d->tempName.clear(); 00505 } 00506 d->determineNextFile(); 00507 return; 00508 } 00509 } 00510 } 00511 00512 bool PreviewJobPrivate::statResultThumbnail() 00513 { 00514 if ( thumbPath.isEmpty() ) 00515 return false; 00516 00517 KUrl url = currentItem.item.mostLocalUrl(); 00518 // Don't include the password if any 00519 url.setPass(QString()); 00520 origName = url.url(); 00521 00522 KMD5 md5( QFile::encodeName( origName ) ); 00523 thumbName = QFile::encodeName( md5.hexDigest() ) + ".png"; 00524 00525 QImage thumb; 00526 if ( !thumb.load( thumbPath + thumbName ) ) return false; 00527 00528 if ( thumb.text( "Thumb::URI", 0 ) != origName || 00529 thumb.text( "Thumb::MTime", 0 ).toInt() != tOrig ) return false; 00530 00531 QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString(); 00532 00533 if (!thumbnailerVersion.isEmpty() && thumb.text("Software", 0).startsWith("KDE Thumbnail Generator")) { 00534 //Check if the version matches 00535 //The software string should read "KDE Thumbnail Generator pluginName (vX)" 00536 QString softwareString = thumb.text("Software", 0).remove("KDE Thumbnail Generator").trimmed(); 00537 if (softwareString.isEmpty()) { 00538 // The thumbnail has been created with an older version, recreating 00539 return false; 00540 } 00541 int versionIndex = softwareString.lastIndexOf("(v"); 00542 if (versionIndex < 0) { 00543 return false; 00544 } 00545 00546 QString cachedVersion = softwareString.remove(0, versionIndex+2); 00547 cachedVersion.chop(1); 00548 uint thumbnailerMajor = thumbnailerVersion.toInt(); 00549 uint cachedMajor = cachedVersion.toInt(); 00550 if (thumbnailerMajor > cachedMajor) { 00551 return false; 00552 } 00553 } 00554 00555 // Found it, use it 00556 emitPreview( thumb ); 00557 succeeded = true; 00558 determineNextFile(); 00559 return true; 00560 } 00561 00562 00563 void PreviewJobPrivate::getOrCreateThumbnail() 00564 { 00565 Q_Q(PreviewJob); 00566 // We still need to load the orig file ! (This is getting tedious) :) 00567 const KFileItem& item = currentItem.item; 00568 const QString localPath = item.localPath(); 00569 if ( !localPath.isEmpty() ) 00570 createThumbnail( localPath ); 00571 else 00572 { 00573 state = PreviewJobPrivate::STATE_GETORIG; 00574 KTemporaryFile localFile; 00575 localFile.setAutoRemove(false); 00576 localFile.open(); 00577 KUrl localURL; 00578 localURL.setPath( tempName = localFile.fileName() ); 00579 const KUrl currentURL = item.mostLocalUrl(); 00580 KIO::Job * job = KIO::file_copy( currentURL, localURL, -1, KIO::Overwrite | KIO::HideProgressInfo /* No GUI */ ); 00581 job->addMetaData("thumbnail","1"); 00582 q->addSubjob(job); 00583 } 00584 } 00585 00586 void PreviewJobPrivate::createThumbnail( const QString &pixPath ) 00587 { 00588 Q_Q(PreviewJob); 00589 state = PreviewJobPrivate::STATE_CREATETHUMB; 00590 KUrl thumbURL; 00591 thumbURL.setProtocol("thumbnail"); 00592 thumbURL.setPath(pixPath); 00593 KIO::TransferJob *job = KIO::get(thumbURL, NoReload, HideProgressInfo); 00594 q->addSubjob(job); 00595 q->connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), SLOT(slotThumbData(KIO::Job *, const QByteArray &))); 00596 bool save = bSave && currentItem.plugin->property("CacheThumbnail").toBool() && !sequenceIndex; 00597 job->addMetaData("mimeType", currentItem.item.mimetype()); 00598 job->addMetaData("width", QString().setNum(save ? cacheWidth : width)); 00599 job->addMetaData("height", QString().setNum(save ? cacheHeight : height)); 00600 job->addMetaData("iconSize", QString().setNum(save ? 64 : iconSize)); 00601 job->addMetaData("iconAlpha", QString().setNum(iconAlpha)); 00602 job->addMetaData("plugin", currentItem.plugin->library()); 00603 if(sequenceIndex) 00604 job->addMetaData("sequence-index", QString().setNum(sequenceIndex)); 00605 00606 #ifdef Q_OS_UNIX 00607 if (shmid == -1) 00608 { 00609 if (shmaddr) { 00610 shmdt((char*)shmaddr); 00611 shmctl(shmid, IPC_RMID, 0); 00612 } 00613 shmid = shmget(IPC_PRIVATE, cacheWidth * cacheHeight * 4, IPC_CREAT|0600); 00614 if (shmid != -1) 00615 { 00616 shmaddr = (uchar *)(shmat(shmid, 0, SHM_RDONLY)); 00617 if (shmaddr == (uchar *)-1) 00618 { 00619 shmctl(shmid, IPC_RMID, 0); 00620 shmaddr = 0; 00621 shmid = -1; 00622 } 00623 } 00624 else 00625 shmaddr = 0; 00626 } 00627 if (shmid != -1) 00628 job->addMetaData("shmid", QString().setNum(shmid)); 00629 #endif 00630 } 00631 00632 void PreviewJobPrivate::slotThumbData(KIO::Job *, const QByteArray &data) 00633 { 00634 bool save = bSave && 00635 currentItem.plugin->property("CacheThumbnail").toBool() && 00636 (currentItem.item.url().protocol() != "file" || 00637 !currentItem.item.url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) && !sequenceIndex; 00638 QImage thumb; 00639 #ifdef Q_OS_UNIX 00640 if (shmaddr) 00641 { 00642 // Keep this in sync with kdebase/kioslave/thumbnail.cpp 00643 QDataStream str(data); 00644 int width, height; 00645 quint8 iFormat; 00646 str >> width >> height >> iFormat; 00647 QImage::Format format = static_cast<QImage::Format>( iFormat ); 00648 thumb = QImage(shmaddr, width, height, format ).copy(); 00649 } 00650 else 00651 #endif 00652 thumb.loadFromData(data); 00653 00654 if (thumb.isNull()) { 00655 QDataStream s(data); 00656 s >> thumb; 00657 } 00658 00659 QString tempFileName; 00660 bool savedCorrectly = false; 00661 if (save) 00662 { 00663 thumb.setText("Thumb::URI", origName); 00664 thumb.setText("Thumb::MTime", QString::number(tOrig)); 00665 thumb.setText("Thumb::Size", number(currentItem.item.size())); 00666 thumb.setText("Thumb::Mimetype", currentItem.item.mimetype()); 00667 QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString(); 00668 QString signature = QString("KDE Thumbnail Generator "+currentItem.plugin->name()); 00669 if (!thumbnailerVersion.isEmpty()) { 00670 signature.append(" (v"+thumbnailerVersion+')'); 00671 } 00672 thumb.setText("Software", signature); 00673 KTemporaryFile temp; 00674 temp.setPrefix(thumbPath + "kde-tmp-"); 00675 temp.setSuffix(".png"); 00676 temp.setAutoRemove(false); 00677 if (temp.open()) //Only try to write out the thumbnail if we 00678 { //actually created the temp file. 00679 tempFileName = temp.fileName(); 00680 savedCorrectly = thumb.save(tempFileName, "PNG"); 00681 } 00682 } 00683 if(savedCorrectly) 00684 { 00685 Q_ASSERT(!tempFileName.isEmpty()); 00686 KDE::rename(tempFileName, thumbPath + thumbName); 00687 } 00688 emitPreview( thumb ); 00689 succeeded = true; 00690 } 00691 00692 void PreviewJobPrivate::emitPreview(const QImage &thumb) 00693 { 00694 Q_Q(PreviewJob); 00695 QPixmap pix; 00696 if (thumb.width() > width || thumb.height() > height) 00697 pix = QPixmap::fromImage( thumb.scaled(QSize(width, height), Qt::KeepAspectRatio, Qt::SmoothTransformation) ); 00698 else 00699 pix = QPixmap::fromImage( thumb ); 00700 emit q->gotPreview(currentItem.item, pix); 00701 } 00702 00703 QStringList PreviewJob::availablePlugins() 00704 { 00705 QStringList result; 00706 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00707 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it) 00708 if (!result.contains((*it)->desktopEntryName())) 00709 result.append((*it)->desktopEntryName()); 00710 return result; 00711 } 00712 00713 QStringList PreviewJob::supportedMimeTypes() 00714 { 00715 QStringList result; 00716 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00717 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it) 00718 result += (*it)->serviceTypes(); 00719 return result; 00720 } 00721 00722 #ifndef KDE_NO_DEPRECATED 00723 PreviewJob *KIO::filePreview( const KFileItemList &items, int width, int height, 00724 int iconSize, int iconAlpha, bool scale, bool save, 00725 const QStringList *enabledPlugins ) 00726 { 00727 return new PreviewJob(items, width, height, iconSize, iconAlpha, 00728 scale, save, enabledPlugins); 00729 } 00730 00731 PreviewJob *KIO::filePreview( const KUrl::List &items, int width, int height, 00732 int iconSize, int iconAlpha, bool scale, bool save, 00733 const QStringList *enabledPlugins ) 00734 { 00735 KFileItemList fileItems; 00736 for (KUrl::List::ConstIterator it = items.begin(); it != items.end(); ++it) { 00737 Q_ASSERT( (*it).isValid() ); // please call us with valid urls only 00738 fileItems.append(KFileItem(KFileItem::Unknown, KFileItem::Unknown, *it, true)); 00739 } 00740 return new PreviewJob(fileItems, width, height, iconSize, iconAlpha, 00741 scale, save, enabledPlugins); 00742 } 00743 #endif 00744 00745 PreviewJob *KIO::filePreview(const KFileItemList &items, const QSize &size, const QStringList *enabledPlugins) 00746 { 00747 return new PreviewJob(items, size, enabledPlugins); 00748 } 00749 00750 #ifndef KDE_NO_DEPRECATED 00751 KIO::filesize_t PreviewJob::maximumFileSize() 00752 { 00753 KConfigGroup cg( KGlobal::config(), "PreviewSettings" ); 00754 return cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ ); 00755 } 00756 #endif 00757 00758 #include "previewjob.moc"
KDE 4.7 API Reference