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 // Some plugins support remote URLs, <protocol, mimetypes> 00077 QHash<QString, QStringList> m_remoteProtocolPlugins; 00078 // Our todo list :) 00079 // We remove the first item at every step, so use QLinkedList 00080 QLinkedList<PreviewItem> items; 00081 // The current item 00082 PreviewItem currentItem; 00083 // The modification time of that URL 00084 time_t tOrig; 00085 // Path to thumbnail cache for the current size 00086 QString thumbPath; 00087 // Original URL of current item in TMS format 00088 // (file:///path/to/file instead of file:/path/to/file) 00089 QString origName; 00090 // Thumbnail file name for current item 00091 QString thumbName; 00092 // Size of thumbnail 00093 int width; 00094 int height; 00095 // Unscaled size of thumbnail (128 or 256 if cache is enabled) 00096 int cacheWidth; 00097 int cacheHeight; 00098 // Whether the thumbnail should be scaled 00099 bool bScale; 00100 // Whether we should save the thumbnail 00101 bool bSave; 00102 bool ignoreMaximumSize; 00103 int sequenceIndex; 00104 bool succeeded; 00105 // If the file to create a thumb for was a temp file, this is its name 00106 QString tempName; 00107 KIO::filesize_t maximumLocalSize; 00108 KIO::filesize_t maximumRemoteSize; 00109 // the size for the icon overlay 00110 int iconSize; 00111 // the transparency of the blended mimetype icon 00112 int iconAlpha; 00113 // Shared memory segment Id. The segment is allocated to a size 00114 // of extent x extent x 4 (32 bit image) on first need. 00115 int shmid; 00116 // And the data area 00117 uchar *shmaddr; 00118 // Root of thumbnail cache 00119 QString thumbRoot; 00120 00121 void getOrCreateThumbnail(); 00122 bool statResultThumbnail(); 00123 void createThumbnail( const QString& ); 00124 void determineNextFile(); 00125 void emitPreview(const QImage &thumb); 00126 00127 void startPreview(); 00128 void slotThumbData(KIO::Job *, const QByteArray &); 00129 00130 Q_DECLARE_PUBLIC(PreviewJob) 00131 }; 00132 00133 #ifndef KDE_NO_DEPRECATED 00134 PreviewJob::PreviewJob( const KFileItemList &items, int width, int height, 00135 int iconSize, int iconAlpha, bool scale, bool save, 00136 const QStringList *enabledPlugins ) 00137 : KIO::Job(*new PreviewJobPrivate) 00138 { 00139 Q_D(PreviewJob); 00140 d->tOrig = 0; 00141 d->shmid = -1; 00142 d->shmaddr = 0; 00143 d->initialItems = items; 00144 d->enabledPlugins = enabledPlugins ? *enabledPlugins : availablePlugins(); 00145 d->width = width; 00146 d->height = height ? height : width; 00147 d->cacheWidth = d->width; 00148 d->cacheHeight = d->height; 00149 d->iconSize = iconSize; 00150 d->iconAlpha = iconAlpha; 00151 d->bScale = scale; 00152 d->bSave = save && scale; 00153 d->succeeded = false; 00154 d->thumbRoot = QDir::homePath() + QLatin1String("/.thumbnails/"); 00155 d->ignoreMaximumSize = false; 00156 d->sequenceIndex = 0; 00157 d->maximumLocalSize = 0; 00158 d->maximumRemoteSize = 0; 00159 00160 // Return to event loop first, determineNextFile() might delete this; 00161 QTimer::singleShot(0, this, SLOT(startPreview())); 00162 } 00163 #endif 00164 00165 PreviewJob::PreviewJob(const KFileItemList &items, 00166 const QSize &size, 00167 const QStringList *enabledPlugins) : 00168 KIO::Job(*new PreviewJobPrivate) 00169 { 00170 Q_D(PreviewJob); 00171 d->tOrig = 0; 00172 d->shmid = -1; 00173 d->shmaddr = 0; 00174 d->initialItems = items; 00175 if (enabledPlugins) { 00176 d->enabledPlugins = *enabledPlugins; 00177 } else { 00178 const KConfigGroup globalConfig(KGlobal::config(), "PreviewSettings"); 00179 d->enabledPlugins = globalConfig.readEntry("Plugins", QStringList() 00180 << "directorythumbnail" 00181 << "imagethumbnail" 00182 << "jpegthumbnail"); 00183 } 00184 d->width = size.width(); 00185 d->height = size.height(); 00186 d->cacheWidth = d->width; 00187 d->cacheHeight = d->height; 00188 d->iconSize = 0; 00189 d->iconAlpha = 70; 00190 d->bScale = true; 00191 d->bSave = true; 00192 d->succeeded = false; 00193 d->thumbRoot = QDir::homePath() + QLatin1String("/.thumbnails/"); 00194 d->ignoreMaximumSize = false; 00195 d->sequenceIndex = 0; 00196 d->maximumLocalSize = 0; 00197 d->maximumRemoteSize = 0; 00198 00199 // Return to event loop first, determineNextFile() might delete this; 00200 QTimer::singleShot(0, this, SLOT(startPreview())); 00201 } 00202 00203 PreviewJob::~PreviewJob() 00204 { 00205 #ifdef Q_OS_UNIX 00206 Q_D(PreviewJob); 00207 if (d->shmaddr) { 00208 shmdt((char*)d->shmaddr); 00209 shmctl(d->shmid, IPC_RMID, 0); 00210 } 00211 #endif 00212 } 00213 00214 void PreviewJob::setOverlayIconSize(int size) 00215 { 00216 Q_D(PreviewJob); 00217 d->iconSize = size; 00218 } 00219 00220 int PreviewJob::overlayIconSize() const 00221 { 00222 Q_D(const PreviewJob); 00223 return d->iconSize; 00224 } 00225 00226 void PreviewJob::setOverlayIconAlpha(int alpha) 00227 { 00228 Q_D(PreviewJob); 00229 d->iconAlpha = qBound(0, alpha, 255); 00230 } 00231 00232 int PreviewJob::overlayIconAlpha() const 00233 { 00234 Q_D(const PreviewJob); 00235 return d->iconAlpha; 00236 } 00237 00238 void PreviewJob::setScaleType(ScaleType type) 00239 { 00240 Q_D(PreviewJob); 00241 switch (type) { 00242 case Unscaled: 00243 d->bScale = false; 00244 d->bSave = false; 00245 break; 00246 case Scaled: 00247 d->bScale = true; 00248 d->bSave = false; 00249 break; 00250 case ScaledAndCached: 00251 d->bScale = true; 00252 d->bSave = true; 00253 break; 00254 default: 00255 break; 00256 } 00257 } 00258 00259 PreviewJob::ScaleType PreviewJob::scaleType() const 00260 { 00261 Q_D(const PreviewJob); 00262 if (d->bScale) { 00263 return d->bSave ? ScaledAndCached : Scaled; 00264 } 00265 return Unscaled; 00266 } 00267 00268 void PreviewJobPrivate::startPreview() 00269 { 00270 Q_Q(PreviewJob); 00271 // Load the list of plugins to determine which mimetypes are supported 00272 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00273 QMap<QString, KService::Ptr> mimeMap; 00274 QHash<QString, QHash<QString, KService::Ptr> > protocolMap; 00275 for (KService::List::ConstIterator it = plugins.constBegin(); it != plugins.constEnd(); ++it) { 00276 QStringList protocols = (*it)->property("X-KDE-Protocols").toStringList(); 00277 const QString p = (*it)->property("X-KDE-Protocol").toString(); 00278 if (!p.isEmpty()) { 00279 protocols.append(p); 00280 } 00281 foreach (const QString &protocol, protocols) { 00282 QStringList mtypes = (*it)->serviceTypes(); 00283 // Filter out non-mimetype servicetypes 00284 // TODO KDE5: use KService::mimeTypes() 00285 foreach (const QString &_mtype, mtypes) { 00286 if (!((*it)->hasMimeType(_mtype))) { 00287 mtypes.removeAll(_mtype); 00288 } 00289 } 00290 // Add supported mimetype for this protocol 00291 QStringList &_ms = m_remoteProtocolPlugins[protocol]; 00292 foreach (const QString &_m, mtypes) { 00293 protocolMap[protocol].insert(_m, *it); 00294 if (!_ms.contains(_m)) { 00295 _ms.append(_m); 00296 } 00297 } 00298 } 00299 if (enabledPlugins.contains((*it)->desktopEntryName())) { 00300 const QStringList mimeTypes = (*it)->serviceTypes(); 00301 for (QStringList::ConstIterator mt = mimeTypes.constBegin(); mt != mimeTypes.constEnd(); ++mt) 00302 mimeMap.insert(*mt, *it); 00303 } 00304 } 00305 00306 // Look for images and store the items in our todo list :) 00307 bool bNeedCache = false; 00308 KFileItemList::const_iterator kit = initialItems.constBegin(); 00309 const KFileItemList::const_iterator kend = initialItems.constEnd(); 00310 for ( ; kit != kend; ++kit ) 00311 { 00312 PreviewItem item; 00313 item.item = *kit; 00314 const QString mimeType = item.item.mimetype(); 00315 KService::Ptr plugin(0); 00316 00317 // look for protocol-specific thumbnail plugins first 00318 QHash<QString, QHash<QString, KService::Ptr> >::const_iterator it = protocolMap.constFind(item.item.url().protocol()); 00319 if (it != protocolMap.constEnd()) { 00320 plugin = it.value().value(mimeType); 00321 } 00322 00323 if (!plugin) { 00324 QMap<QString, KService::Ptr>::ConstIterator pluginIt = mimeMap.constFind(mimeType); 00325 if (pluginIt == mimeMap.constEnd()) { 00326 QString groupMimeType = mimeType; 00327 groupMimeType.replace(QRegExp("/.*"), "/*"); 00328 pluginIt = mimeMap.constFind(groupMimeType); 00329 00330 if (pluginIt == mimeMap.constEnd()) { 00331 // check mime type inheritance, resolve aliases 00332 const KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType); 00333 if (mimeInfo) { 00334 const QStringList parentMimeTypes = mimeInfo->allParentMimeTypes(); 00335 Q_FOREACH(const QString& parentMimeType, parentMimeTypes) { 00336 pluginIt = mimeMap.constFind(parentMimeType); 00337 if (pluginIt != mimeMap.constEnd()) 00338 break; 00339 } 00340 } 00341 } 00342 } 00343 00344 if (pluginIt != mimeMap.constEnd()) { 00345 plugin = *pluginIt; 00346 } 00347 } 00348 00349 if (plugin) { 00350 item.plugin = plugin; 00351 items.append(item); 00352 if (!bNeedCache && bSave && 00353 ((*kit).url().protocol() != "file" || 00354 !(*kit).url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) && 00355 plugin->property("CacheThumbnail").toBool()) { 00356 bNeedCache = true; 00357 } 00358 } else { 00359 emit q->failed( *kit ); 00360 } 00361 } 00362 00363 KConfigGroup cg( KGlobal::config(), "PreviewSettings" ); 00364 maximumLocalSize = cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ ); 00365 maximumRemoteSize = cg.readEntry( "MaximumRemoteSize", 0 ); 00366 00367 if (bNeedCache) 00368 { 00369 if (width <= 128 && height <= 128) cacheWidth = cacheHeight = 128; 00370 else cacheWidth = cacheHeight = 256; 00371 thumbPath = thumbRoot + (cacheWidth == 128 ? "normal/" : "large/"); 00372 KStandardDirs::makeDir(thumbPath, 0700); 00373 } 00374 else 00375 bSave = false; 00376 00377 initialItems.clear(); 00378 determineNextFile(); 00379 } 00380 00381 void PreviewJob::removeItem( const KUrl& url ) 00382 { 00383 Q_D(PreviewJob); 00384 for (QLinkedList<PreviewItem>::Iterator it = d->items.begin(); it != d->items.end(); ++it) 00385 if ((*it).item.url() == url) 00386 { 00387 d->items.erase(it); 00388 break; 00389 } 00390 00391 if (d->currentItem.item.url() == url) 00392 { 00393 KJob* job = subjobs().first(); 00394 job->kill(); 00395 removeSubjob( job ); 00396 d->determineNextFile(); 00397 } 00398 } 00399 00400 void KIO::PreviewJob::setSequenceIndex(int index) { 00401 d_func()->sequenceIndex = index; 00402 } 00403 00404 int KIO::PreviewJob::sequenceIndex() const { 00405 return d_func()->sequenceIndex; 00406 } 00407 00408 void PreviewJob::setIgnoreMaximumSize(bool ignoreSize) 00409 { 00410 d_func()->ignoreMaximumSize = ignoreSize; 00411 } 00412 00413 void PreviewJobPrivate::determineNextFile() 00414 { 00415 Q_Q(PreviewJob); 00416 if (!currentItem.item.isNull()) 00417 { 00418 if (!succeeded) 00419 emit q->failed( currentItem.item ); 00420 } 00421 // No more items ? 00422 if ( items.isEmpty() ) 00423 { 00424 q->emitResult(); 00425 return; 00426 } 00427 else 00428 { 00429 // First, stat the orig file 00430 state = PreviewJobPrivate::STATE_STATORIG; 00431 currentItem = items.first(); 00432 succeeded = false; 00433 items.removeFirst(); 00434 KIO::Job *job = KIO::stat( currentItem.item.url(), KIO::HideProgressInfo ); 00435 job->addMetaData( "no-auth-prompt", "true" ); 00436 q->addSubjob(job); 00437 } 00438 } 00439 00440 void PreviewJob::slotResult( KJob *job ) 00441 { 00442 Q_D(PreviewJob); 00443 00444 removeSubjob(job); 00445 Q_ASSERT ( !hasSubjobs() ); // We should have only one job at a time ... 00446 switch ( d->state ) 00447 { 00448 case PreviewJobPrivate::STATE_STATORIG: 00449 { 00450 if (job->error()) // that's no good news... 00451 { 00452 // Drop this one and move on to the next one 00453 d->determineNextFile(); 00454 return; 00455 } 00456 const KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult(); 00457 d->tOrig = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, 0 ); 00458 00459 bool skipCurrentItem = false; 00460 const KIO::filesize_t size = (KIO::filesize_t)entry.numberValue( KIO::UDSEntry::UDS_SIZE, 0 ); 00461 const KUrl itemUrl = d->currentItem.item.mostLocalUrl(); 00462 00463 if (itemUrl.isLocalFile() || KProtocolInfo::protocolClass(itemUrl.protocol()) == QLatin1String(":local")) 00464 { 00465 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumLocalSize 00466 && !d->currentItem.plugin->property("IgnoreMaximumSize").toBool(); 00467 } 00468 else 00469 { 00470 // For remote items the "IgnoreMaximumSize" plugin property is not respected 00471 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumRemoteSize; 00472 00473 // Remote directories are not supported, don't try to do a file_copy on them 00474 if (!skipCurrentItem) { 00475 // TODO update item.mimeType from the UDS entry, in case it wasn't set initially 00476 KMimeType::Ptr mime = d->currentItem.item.mimeTypePtr(); 00477 if (mime && mime->is("inode/directory")) { 00478 skipCurrentItem = true; 00479 } 00480 } 00481 } 00482 if (skipCurrentItem) 00483 { 00484 d->determineNextFile(); 00485 return; 00486 } 00487 00488 bool pluginHandlesSequences = d->currentItem.plugin->property("HandleSequences", QVariant::Bool).toBool(); 00489 if ( !d->currentItem.plugin->property( "CacheThumbnail" ).toBool() || (d->sequenceIndex && pluginHandlesSequences) ) 00490 { 00491 // This preview will not be cached, no need to look for a saved thumbnail 00492 // Just create it, and be done 00493 d->getOrCreateThumbnail(); 00494 return; 00495 } 00496 00497 if ( d->statResultThumbnail() ) 00498 return; 00499 00500 d->getOrCreateThumbnail(); 00501 return; 00502 } 00503 case PreviewJobPrivate::STATE_GETORIG: 00504 { 00505 if (job->error()) 00506 { 00507 d->determineNextFile(); 00508 return; 00509 } 00510 00511 d->createThumbnail( static_cast<KIO::FileCopyJob*>(job)->destUrl().toLocalFile() ); 00512 return; 00513 } 00514 case PreviewJobPrivate::STATE_CREATETHUMB: 00515 { 00516 if (!d->tempName.isEmpty()) 00517 { 00518 QFile::remove(d->tempName); 00519 d->tempName.clear(); 00520 } 00521 d->determineNextFile(); 00522 return; 00523 } 00524 } 00525 } 00526 00527 bool PreviewJobPrivate::statResultThumbnail() 00528 { 00529 if ( thumbPath.isEmpty() ) 00530 return false; 00531 00532 KUrl url = currentItem.item.mostLocalUrl(); 00533 // Don't include the password if any 00534 url.setPass(QString()); 00535 origName = url.url(); 00536 00537 KMD5 md5( QFile::encodeName( origName ) ); 00538 thumbName = QFile::encodeName( md5.hexDigest() ) + ".png"; 00539 00540 QImage thumb; 00541 if ( !thumb.load( thumbPath + thumbName ) ) return false; 00542 00543 if ( thumb.text( "Thumb::URI", 0 ) != origName || 00544 thumb.text( "Thumb::MTime", 0 ).toInt() != tOrig ) return false; 00545 00546 QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString(); 00547 00548 if (!thumbnailerVersion.isEmpty() && thumb.text("Software", 0).startsWith("KDE Thumbnail Generator")) { 00549 //Check if the version matches 00550 //The software string should read "KDE Thumbnail Generator pluginName (vX)" 00551 QString softwareString = thumb.text("Software", 0).remove("KDE Thumbnail Generator").trimmed(); 00552 if (softwareString.isEmpty()) { 00553 // The thumbnail has been created with an older version, recreating 00554 return false; 00555 } 00556 int versionIndex = softwareString.lastIndexOf("(v"); 00557 if (versionIndex < 0) { 00558 return false; 00559 } 00560 00561 QString cachedVersion = softwareString.remove(0, versionIndex+2); 00562 cachedVersion.chop(1); 00563 uint thumbnailerMajor = thumbnailerVersion.toInt(); 00564 uint cachedMajor = cachedVersion.toInt(); 00565 if (thumbnailerMajor > cachedMajor) { 00566 return false; 00567 } 00568 } 00569 00570 // Found it, use it 00571 emitPreview( thumb ); 00572 succeeded = true; 00573 determineNextFile(); 00574 return true; 00575 } 00576 00577 00578 void PreviewJobPrivate::getOrCreateThumbnail() 00579 { 00580 Q_Q(PreviewJob); 00581 // We still need to load the orig file ! (This is getting tedious) :) 00582 const KFileItem& item = currentItem.item; 00583 const QString localPath = item.localPath(); 00584 if (!localPath.isEmpty()) { 00585 createThumbnail( localPath ); 00586 } else { 00587 const KUrl fileUrl = item.url(); 00588 // heuristics for remote URL support 00589 bool supportsProtocol = false; 00590 if (m_remoteProtocolPlugins.value(fileUrl.scheme()).contains(item.mimetype())) { 00591 // There's a plugin supporting this protocol and mimetype 00592 supportsProtocol = true; 00593 } else if (m_remoteProtocolPlugins.value("KIO").contains(item.mimetype())) { 00594 // Assume KIO understands any URL, ThumbCreator slaves who have 00595 // X-KDE-Protocols=KIO will get fed the remote URL directly. 00596 supportsProtocol = true; 00597 } 00598 00599 if (supportsProtocol) { 00600 createThumbnail(fileUrl.url()); 00601 return; 00602 } 00603 // No plugin support access to this remote content, copy the file 00604 // to the local machine, then create the thumbnail 00605 state = PreviewJobPrivate::STATE_GETORIG; 00606 KTemporaryFile localFile; 00607 localFile.setAutoRemove(false); 00608 localFile.open(); 00609 KUrl localURL; 00610 localURL.setPath( tempName = localFile.fileName() ); 00611 const KUrl currentURL = item.mostLocalUrl(); 00612 KIO::Job * job = KIO::file_copy( currentURL, localURL, -1, KIO::Overwrite | KIO::HideProgressInfo /* No GUI */ ); 00613 job->addMetaData("thumbnail","1"); 00614 q->addSubjob(job); 00615 } 00616 } 00617 00618 void PreviewJobPrivate::createThumbnail( const QString &pixPath ) 00619 { 00620 Q_Q(PreviewJob); 00621 state = PreviewJobPrivate::STATE_CREATETHUMB; 00622 KUrl thumbURL; 00623 thumbURL.setProtocol("thumbnail"); 00624 thumbURL.setPath(pixPath); 00625 KIO::TransferJob *job = KIO::get(thumbURL, NoReload, HideProgressInfo); 00626 q->addSubjob(job); 00627 q->connect(job, SIGNAL(data(KIO::Job*,QByteArray)), SLOT(slotThumbData(KIO::Job*,QByteArray))); 00628 bool save = bSave && currentItem.plugin->property("CacheThumbnail").toBool() && !sequenceIndex; 00629 job->addMetaData("mimeType", currentItem.item.mimetype()); 00630 job->addMetaData("width", QString().setNum(save ? cacheWidth : width)); 00631 job->addMetaData("height", QString().setNum(save ? cacheHeight : height)); 00632 job->addMetaData("iconSize", QString().setNum(save ? 64 : iconSize)); 00633 job->addMetaData("iconAlpha", QString().setNum(iconAlpha)); 00634 job->addMetaData("plugin", currentItem.plugin->library()); 00635 if(sequenceIndex) 00636 job->addMetaData("sequence-index", QString().setNum(sequenceIndex)); 00637 00638 #ifdef Q_OS_UNIX 00639 if (shmid == -1) 00640 { 00641 if (shmaddr) { 00642 shmdt((char*)shmaddr); 00643 shmctl(shmid, IPC_RMID, 0); 00644 } 00645 shmid = shmget(IPC_PRIVATE, cacheWidth * cacheHeight * 4, IPC_CREAT|0600); 00646 if (shmid != -1) 00647 { 00648 shmaddr = (uchar *)(shmat(shmid, 0, SHM_RDONLY)); 00649 if (shmaddr == (uchar *)-1) 00650 { 00651 shmctl(shmid, IPC_RMID, 0); 00652 shmaddr = 0; 00653 shmid = -1; 00654 } 00655 } 00656 else 00657 shmaddr = 0; 00658 } 00659 if (shmid != -1) 00660 job->addMetaData("shmid", QString().setNum(shmid)); 00661 #endif 00662 } 00663 00664 void PreviewJobPrivate::slotThumbData(KIO::Job *, const QByteArray &data) 00665 { 00666 bool save = bSave && 00667 currentItem.plugin->property("CacheThumbnail").toBool() && 00668 (currentItem.item.url().protocol() != "file" || 00669 !currentItem.item.url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) && !sequenceIndex; 00670 QImage thumb; 00671 #ifdef Q_OS_UNIX 00672 if (shmaddr) 00673 { 00674 // Keep this in sync with kdebase/kioslave/thumbnail.cpp 00675 QDataStream str(data); 00676 int width, height; 00677 quint8 iFormat; 00678 str >> width >> height >> iFormat; 00679 QImage::Format format = static_cast<QImage::Format>( iFormat ); 00680 thumb = QImage(shmaddr, width, height, format ).copy(); 00681 } 00682 else 00683 #endif 00684 thumb.loadFromData(data); 00685 00686 if (thumb.isNull()) { 00687 QDataStream s(data); 00688 s >> thumb; 00689 } 00690 00691 QString tempFileName; 00692 bool savedCorrectly = false; 00693 if (save) 00694 { 00695 thumb.setText("Thumb::URI", origName); 00696 thumb.setText("Thumb::MTime", QString::number(tOrig)); 00697 thumb.setText("Thumb::Size", number(currentItem.item.size())); 00698 thumb.setText("Thumb::Mimetype", currentItem.item.mimetype()); 00699 QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString(); 00700 QString signature = QString("KDE Thumbnail Generator "+currentItem.plugin->name()); 00701 if (!thumbnailerVersion.isEmpty()) { 00702 signature.append(" (v"+thumbnailerVersion+')'); 00703 } 00704 thumb.setText("Software", signature); 00705 KTemporaryFile temp; 00706 temp.setPrefix(thumbPath + "kde-tmp-"); 00707 temp.setSuffix(".png"); 00708 temp.setAutoRemove(false); 00709 if (temp.open()) //Only try to write out the thumbnail if we 00710 { //actually created the temp file. 00711 tempFileName = temp.fileName(); 00712 savedCorrectly = thumb.save(tempFileName, "PNG"); 00713 } 00714 } 00715 if(savedCorrectly) 00716 { 00717 Q_ASSERT(!tempFileName.isEmpty()); 00718 KDE::rename(tempFileName, thumbPath + thumbName); 00719 } 00720 emitPreview( thumb ); 00721 succeeded = true; 00722 } 00723 00724 void PreviewJobPrivate::emitPreview(const QImage &thumb) 00725 { 00726 Q_Q(PreviewJob); 00727 QPixmap pix; 00728 if (thumb.width() > width || thumb.height() > height) 00729 pix = QPixmap::fromImage( thumb.scaled(QSize(width, height), Qt::KeepAspectRatio, Qt::SmoothTransformation) ); 00730 else 00731 pix = QPixmap::fromImage( thumb ); 00732 emit q->gotPreview(currentItem.item, pix); 00733 } 00734 00735 QStringList PreviewJob::availablePlugins() 00736 { 00737 QStringList result; 00738 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00739 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it) 00740 if (!result.contains((*it)->desktopEntryName())) 00741 result.append((*it)->desktopEntryName()); 00742 return result; 00743 } 00744 00745 QStringList PreviewJob::supportedMimeTypes() 00746 { 00747 QStringList result; 00748 const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator"); 00749 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it) 00750 result += (*it)->serviceTypes(); 00751 return result; 00752 } 00753 00754 #ifndef KDE_NO_DEPRECATED 00755 PreviewJob *KIO::filePreview( const KFileItemList &items, int width, int height, 00756 int iconSize, int iconAlpha, bool scale, bool save, 00757 const QStringList *enabledPlugins ) 00758 { 00759 return new PreviewJob(items, width, height, iconSize, iconAlpha, 00760 scale, save, enabledPlugins); 00761 } 00762 00763 PreviewJob *KIO::filePreview( const KUrl::List &items, int width, int height, 00764 int iconSize, int iconAlpha, bool scale, bool save, 00765 const QStringList *enabledPlugins ) 00766 { 00767 KFileItemList fileItems; 00768 for (KUrl::List::ConstIterator it = items.begin(); it != items.end(); ++it) { 00769 Q_ASSERT( (*it).isValid() ); // please call us with valid urls only 00770 fileItems.append(KFileItem(KFileItem::Unknown, KFileItem::Unknown, *it, true)); 00771 } 00772 return new PreviewJob(fileItems, width, height, iconSize, iconAlpha, 00773 scale, save, enabledPlugins); 00774 } 00775 #endif 00776 00777 PreviewJob *KIO::filePreview(const KFileItemList &items, const QSize &size, const QStringList *enabledPlugins) 00778 { 00779 return new PreviewJob(items, size, enabledPlugins); 00780 } 00781 00782 #ifndef KDE_NO_DEPRECATED 00783 KIO::filesize_t PreviewJob::maximumFileSize() 00784 { 00785 KConfigGroup cg( KGlobal::config(), "PreviewSettings" ); 00786 return cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ ); 00787 } 00788 #endif 00789 00790 #include "previewjob.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:35:02 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:35:02 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.