• Skip to content
  • Skip to link menu
KDE 4.8 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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     for (KService::List::ConstIterator it = plugins.constBegin(); it != plugins.constEnd(); ++it) {
00275         const QStringList protocols = (*it)->property("X-KDE-Protocol").toStringList();
00276         foreach (const QString &protocol, protocols) {
00277             QStringList mtypes = (*it)->serviceTypes();
00278             // Filter out non-mimetype servicetypes
00279             // TODO KDE5: use KService::mimeTypes()
00280             foreach (const QString &_mtype, mtypes) {
00281                 if (!((*it)->hasMimeType(_mtype))) {
00282                     mtypes.removeAll(_mtype);
00283                 }
00284             }
00285             // Add already existing protocols, so more than one plugin can
00286             // support a given scheme + mimetype
00287             QStringList &_ms = m_remoteProtocolPlugins[protocol];
00288             foreach (const QString &_m, mtypes) {
00289                 if (!_ms.contains(_m)) {
00290                     _ms.append(_m);
00291                 }
00292             }
00293         }
00294         if (enabledPlugins.contains((*it)->desktopEntryName())) {
00295             const QStringList mimeTypes = (*it)->serviceTypes();
00296             for (QStringList::ConstIterator mt = mimeTypes.constBegin(); mt != mimeTypes.constEnd(); ++mt)
00297                 mimeMap.insert(*mt, *it);
00298         }
00299     }
00300 
00301     // Look for images and store the items in our todo list :)
00302     bool bNeedCache = false;
00303     KFileItemList::const_iterator kit = initialItems.constBegin();
00304     const KFileItemList::const_iterator kend = initialItems.constEnd();
00305     for ( ; kit != kend; ++kit )
00306     {
00307         PreviewItem item;
00308         item.item = *kit;
00309         const QString mimeType = item.item.mimetype();
00310         QMap<QString, KService::Ptr>::ConstIterator plugin = mimeMap.constFind(mimeType);
00311         if (plugin == mimeMap.constEnd())
00312 
00313         {
00314             QString groupMimeType = mimeType;
00315             groupMimeType.replace(QRegExp("/.*"), "/*");
00316             plugin = mimeMap.constFind(groupMimeType);
00317 
00318             if (plugin == mimeMap.constEnd())
00319             {
00320                 // check mime type inheritance, resolve aliases
00321                 const KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
00322                 if (mimeInfo) {
00323                     const QStringList parentMimeTypes = mimeInfo->allParentMimeTypes();
00324                     Q_FOREACH(const QString& parentMimeType, parentMimeTypes) {
00325                         plugin = mimeMap.constFind(parentMimeType);
00326                         if (plugin != mimeMap.constEnd()) break;
00327                     }
00328                 }
00329             }
00330 #if 0 // KDE4: should be covered by inheritance above, all text mimetypes inherit from text/plain
00331             // if that's not enough, we need to invent something else
00332             if (plugin == mimeMap.end())
00333             {
00334                 // check X-KDE-Text property
00335                 KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType);
00336                 QVariant textProperty = mimeInfo->property("X-KDE-text");
00337                 if (textProperty.isValid() && textProperty.type() == QVariant::Bool)
00338                 {
00339                     if (textProperty.toBool())
00340                     {
00341                         plugin = mimeMap.find("text/plain");
00342                         if (plugin == mimeMap.end())
00343                         {
00344                             plugin = mimeMap.find( "text/*" );
00345                         }
00346                     }
00347                 }
00348             }
00349 #endif
00350         }
00351 
00352         if (plugin != mimeMap.constEnd())
00353         {
00354             item.plugin = *plugin;
00355             items.append(item);
00356             if (!bNeedCache && bSave &&
00357                 ((*kit).url().protocol() != "file" ||
00358                  !(*kit).url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) &&
00359                 (*plugin)->property("CacheThumbnail").toBool())
00360                 bNeedCache = true;
00361         }
00362         else
00363         {
00364             emit q->failed( *kit );
00365         }
00366     }
00367 
00368     KConfigGroup cg( KGlobal::config(), "PreviewSettings" );
00369     maximumLocalSize = cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ );
00370     maximumRemoteSize = cg.readEntry( "MaximumRemoteSize", 0 );
00371 
00372     if (bNeedCache)
00373     {
00374         if (width <= 128 && height <= 128) cacheWidth = cacheHeight = 128;
00375         else cacheWidth = cacheHeight = 256;
00376         thumbPath = thumbRoot + (cacheWidth == 128 ? "normal/" : "large/");
00377         KStandardDirs::makeDir(thumbPath, 0700);
00378     }
00379     else
00380         bSave = false;
00381 
00382     initialItems.clear();
00383     determineNextFile();
00384 }
00385 
00386 void PreviewJob::removeItem( const KUrl& url )
00387 {
00388     Q_D(PreviewJob);
00389     for (QLinkedList<PreviewItem>::Iterator it = d->items.begin(); it != d->items.end(); ++it)
00390         if ((*it).item.url() == url)
00391         {
00392             d->items.erase(it);
00393             break;
00394         }
00395 
00396     if (d->currentItem.item.url() == url)
00397     {
00398         KJob* job = subjobs().first();
00399         job->kill();
00400         removeSubjob( job );
00401         d->determineNextFile();
00402     }
00403 }
00404 
00405 void KIO::PreviewJob::setSequenceIndex(int index) {
00406     d_func()->sequenceIndex = index;
00407 }
00408 
00409 int KIO::PreviewJob::sequenceIndex() const {
00410     return d_func()->sequenceIndex;
00411 }
00412 
00413 void PreviewJob::setIgnoreMaximumSize(bool ignoreSize)
00414 {
00415     d_func()->ignoreMaximumSize = ignoreSize;
00416 }
00417 
00418 void PreviewJobPrivate::determineNextFile()
00419 {
00420     Q_Q(PreviewJob);
00421     if (!currentItem.item.isNull())
00422     {
00423         if (!succeeded)
00424             emit q->failed( currentItem.item );
00425     }
00426     // No more items ?
00427     if ( items.isEmpty() )
00428     {
00429         q->emitResult();
00430         return;
00431     }
00432     else
00433     {
00434         // First, stat the orig file
00435         state = PreviewJobPrivate::STATE_STATORIG;
00436         currentItem = items.first();
00437         succeeded = false;
00438         items.removeFirst();
00439         KIO::Job *job = KIO::stat( currentItem.item.url(), KIO::HideProgressInfo );
00440         job->addMetaData( "no-auth-prompt", "true" );
00441         q->addSubjob(job);
00442     }
00443 }
00444 
00445 void PreviewJob::slotResult( KJob *job )
00446 {
00447     Q_D(PreviewJob);
00448 
00449     removeSubjob(job);
00450     Q_ASSERT ( !hasSubjobs() ); // We should have only one job at a time ...
00451     switch ( d->state )
00452     {
00453         case PreviewJobPrivate::STATE_STATORIG:
00454         {
00455             if (job->error()) // that's no good news...
00456             {
00457                 // Drop this one and move on to the next one
00458                 d->determineNextFile();
00459                 return;
00460             }
00461             const KIO::UDSEntry entry = static_cast<KIO::StatJob*>(job)->statResult();
00462             d->tOrig = entry.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME, 0 );
00463 
00464             bool skipCurrentItem = false;
00465             const KIO::filesize_t size = (KIO::filesize_t)entry.numberValue( KIO::UDSEntry::UDS_SIZE, 0 );
00466             const KUrl itemUrl = d->currentItem.item.mostLocalUrl();
00467 
00468             if (itemUrl.isLocalFile() || KProtocolInfo::protocolClass(itemUrl.protocol()) == QLatin1String(":local"))
00469             {
00470                 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumLocalSize
00471                                   && !d->currentItem.plugin->property("IgnoreMaximumSize").toBool();
00472             }
00473             else
00474             {
00475                 // For remote items the "IgnoreMaximumSize" plugin property is not respected
00476                 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumRemoteSize;
00477 
00478                 // Remote directories are not supported, don't try to do a file_copy on them
00479                 if (!skipCurrentItem) {
00480                     // TODO update item.mimeType from the UDS entry, in case it wasn't set initially
00481                     KMimeType::Ptr mime = d->currentItem.item.mimeTypePtr();
00482                     if (mime && mime->is("inode/directory")) {
00483                         skipCurrentItem = true;
00484                     }
00485                 }
00486             }
00487             if (skipCurrentItem)
00488             {
00489                 d->determineNextFile();
00490                 return;
00491             }
00492 
00493             bool pluginHandlesSequences = d->currentItem.plugin->property("HandleSequences", QVariant::Bool).toBool();
00494             if ( !d->currentItem.plugin->property( "CacheThumbnail" ).toBool()  || (d->sequenceIndex && pluginHandlesSequences) )
00495             {
00496                 // This preview will not be cached, no need to look for a saved thumbnail
00497                 // Just create it, and be done
00498                 d->getOrCreateThumbnail();
00499                 return;
00500             }
00501 
00502             if ( d->statResultThumbnail() )
00503                 return;
00504 
00505             d->getOrCreateThumbnail();
00506             return;
00507         }
00508         case PreviewJobPrivate::STATE_GETORIG:
00509         {
00510             if (job->error())
00511             {
00512                 d->determineNextFile();
00513                 return;
00514             }
00515 
00516             d->createThumbnail( static_cast<KIO::FileCopyJob*>(job)->destUrl().toLocalFile() );
00517             return;
00518         }
00519         case PreviewJobPrivate::STATE_CREATETHUMB:
00520         {
00521             if (!d->tempName.isEmpty())
00522             {
00523                 QFile::remove(d->tempName);
00524                 d->tempName.clear();
00525             }
00526             d->determineNextFile();
00527             return;
00528         }
00529     }
00530 }
00531 
00532 bool PreviewJobPrivate::statResultThumbnail()
00533 {
00534     if ( thumbPath.isEmpty() )
00535         return false;
00536 
00537     KUrl url = currentItem.item.mostLocalUrl();
00538     // Don't include the password if any
00539     url.setPass(QString());
00540     origName = url.url();
00541 
00542     KMD5 md5( QFile::encodeName( origName ) );
00543     thumbName = QFile::encodeName( md5.hexDigest() ) + ".png";
00544 
00545     QImage thumb;
00546     if ( !thumb.load( thumbPath + thumbName ) ) return false;
00547 
00548     if ( thumb.text( "Thumb::URI", 0 ) != origName ||
00549          thumb.text( "Thumb::MTime", 0 ).toInt() != tOrig ) return false;
00550 
00551     QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString();
00552 
00553     if (!thumbnailerVersion.isEmpty() && thumb.text("Software", 0).startsWith("KDE Thumbnail Generator")) {
00554         //Check if the version matches
00555         //The software string should read "KDE Thumbnail Generator pluginName (vX)"
00556         QString softwareString = thumb.text("Software", 0).remove("KDE Thumbnail Generator").trimmed();
00557         if (softwareString.isEmpty()) {
00558             // The thumbnail has been created with an older version, recreating
00559             return false;
00560         }
00561         int versionIndex = softwareString.lastIndexOf("(v");
00562         if (versionIndex < 0) {
00563             return false;
00564         }
00565 
00566         QString cachedVersion = softwareString.remove(0, versionIndex+2);
00567         cachedVersion.chop(1);
00568         uint thumbnailerMajor = thumbnailerVersion.toInt();
00569         uint cachedMajor = cachedVersion.toInt();
00570         if (thumbnailerMajor > cachedMajor) {
00571             return false;
00572         }
00573     }
00574 
00575     // Found it, use it
00576     emitPreview( thumb );
00577     succeeded = true;
00578     determineNextFile();
00579     return true;
00580 }
00581 
00582 
00583 void PreviewJobPrivate::getOrCreateThumbnail()
00584 {
00585     Q_Q(PreviewJob);
00586     // We still need to load the orig file ! (This is getting tedious) :)
00587     const KFileItem& item = currentItem.item;
00588     const QString localPath = item.localPath();
00589     if (!localPath.isEmpty()) {  
00590         createThumbnail( localPath );
00591     } else {
00592         const KUrl fileUrl = item.url();
00593         // heuristics for remote URL support
00594         bool supportsProtocol = false;
00595         if (m_remoteProtocolPlugins.value(fileUrl.scheme()).contains(item.mimetype())) {
00596             // There's a plugin supporting this protocol and mimetype
00597             supportsProtocol = true;
00598         } else if (m_remoteProtocolPlugins.value("KIO").contains(item.mimetype())) {
00599             // Assume KIO understands any URL, ThumbCreator slaves who have
00600             // X-KDE-Protocol=KIO, will get feed the remote URL directly.
00601             supportsProtocol = true;
00602         }
00603 
00604         if (supportsProtocol) {
00605             createThumbnail(fileUrl.url());
00606             return;
00607         }
00608         // No plugin support access to this remote content, copy the file
00609         // to the local machine, then create the thumbnail
00610         state = PreviewJobPrivate::STATE_GETORIG;
00611         KTemporaryFile localFile;
00612         localFile.setAutoRemove(false);
00613         localFile.open();
00614         KUrl localURL;
00615         localURL.setPath( tempName = localFile.fileName() );
00616         const KUrl currentURL = item.mostLocalUrl();
00617         KIO::Job * job = KIO::file_copy( currentURL, localURL, -1, KIO::Overwrite | KIO::HideProgressInfo /* No GUI */ );
00618         job->addMetaData("thumbnail","1");
00619         q->addSubjob(job);
00620     }
00621 }
00622 
00623 void PreviewJobPrivate::createThumbnail( const QString &pixPath )
00624 {
00625     Q_Q(PreviewJob);
00626     state = PreviewJobPrivate::STATE_CREATETHUMB;
00627     KUrl thumbURL;
00628     thumbURL.setProtocol("thumbnail");
00629     thumbURL.setPath(pixPath);
00630     KIO::TransferJob *job = KIO::get(thumbURL, NoReload, HideProgressInfo);
00631     q->addSubjob(job);
00632     q->connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), SLOT(slotThumbData(KIO::Job *, const QByteArray &)));
00633     bool save = bSave && currentItem.plugin->property("CacheThumbnail").toBool() && !sequenceIndex;
00634     job->addMetaData("mimeType", currentItem.item.mimetype());
00635     job->addMetaData("width", QString().setNum(save ? cacheWidth : width));
00636     job->addMetaData("height", QString().setNum(save ? cacheHeight : height));
00637     job->addMetaData("iconSize", QString().setNum(save ? 64 : iconSize));
00638     job->addMetaData("iconAlpha", QString().setNum(iconAlpha));
00639     job->addMetaData("plugin", currentItem.plugin->library());
00640     if(sequenceIndex)
00641         job->addMetaData("sequence-index", QString().setNum(sequenceIndex));
00642 
00643 #ifdef Q_OS_UNIX
00644     if (shmid == -1)
00645     {
00646         if (shmaddr) {
00647             shmdt((char*)shmaddr);
00648             shmctl(shmid, IPC_RMID, 0);
00649         }
00650         shmid = shmget(IPC_PRIVATE, cacheWidth * cacheHeight * 4, IPC_CREAT|0600);
00651         if (shmid != -1)
00652         {
00653             shmaddr = (uchar *)(shmat(shmid, 0, SHM_RDONLY));
00654             if (shmaddr == (uchar *)-1)
00655             {
00656                 shmctl(shmid, IPC_RMID, 0);
00657                 shmaddr = 0;
00658                 shmid = -1;
00659             }
00660         }
00661         else
00662             shmaddr = 0;
00663     }
00664     if (shmid != -1)
00665         job->addMetaData("shmid", QString().setNum(shmid));
00666 #endif
00667 }
00668 
00669 void PreviewJobPrivate::slotThumbData(KIO::Job *, const QByteArray &data)
00670 {
00671     bool save = bSave &&
00672                 currentItem.plugin->property("CacheThumbnail").toBool() &&
00673                 (currentItem.item.url().protocol() != "file" ||
00674                  !currentItem.item.url().directory( KUrl::AppendTrailingSlash ).startsWith(thumbRoot)) && !sequenceIndex;
00675     QImage thumb;
00676 #ifdef Q_OS_UNIX
00677     if (shmaddr)
00678     {
00679         // Keep this in sync with kdebase/kioslave/thumbnail.cpp
00680         QDataStream str(data);
00681         int width, height;
00682         quint8 iFormat;
00683         str >> width >> height >> iFormat;
00684         QImage::Format format = static_cast<QImage::Format>( iFormat );
00685         thumb = QImage(shmaddr, width, height, format ).copy();
00686     }
00687     else
00688 #endif
00689         thumb.loadFromData(data);
00690 
00691     if (thumb.isNull()) {
00692         QDataStream s(data);
00693         s >> thumb;
00694     }
00695 
00696     QString tempFileName;
00697     bool savedCorrectly = false;
00698     if (save)
00699     {
00700         thumb.setText("Thumb::URI", origName);
00701         thumb.setText("Thumb::MTime", QString::number(tOrig));
00702         thumb.setText("Thumb::Size", number(currentItem.item.size()));
00703         thumb.setText("Thumb::Mimetype", currentItem.item.mimetype());
00704         QString thumbnailerVersion = currentItem.plugin->property("ThumbnailerVersion", QVariant::String).toString();
00705         QString signature = QString("KDE Thumbnail Generator "+currentItem.plugin->name());
00706         if (!thumbnailerVersion.isEmpty()) {
00707             signature.append(" (v"+thumbnailerVersion+')');
00708         }
00709         thumb.setText("Software", signature);
00710         KTemporaryFile temp;
00711         temp.setPrefix(thumbPath + "kde-tmp-");
00712         temp.setSuffix(".png");
00713         temp.setAutoRemove(false);
00714         if (temp.open()) //Only try to write out the thumbnail if we
00715         {                //actually created the temp file.
00716             tempFileName = temp.fileName();
00717             savedCorrectly = thumb.save(tempFileName, "PNG");
00718         }
00719     }
00720     if(savedCorrectly)
00721     {
00722         Q_ASSERT(!tempFileName.isEmpty());
00723         KDE::rename(tempFileName, thumbPath + thumbName);
00724     }
00725     emitPreview( thumb );
00726     succeeded = true;
00727 }
00728 
00729 void PreviewJobPrivate::emitPreview(const QImage &thumb)
00730 {
00731     Q_Q(PreviewJob);
00732     QPixmap pix;
00733     if (thumb.width() > width || thumb.height() > height)
00734         pix = QPixmap::fromImage( thumb.scaled(QSize(width, height), Qt::KeepAspectRatio, Qt::SmoothTransformation) );
00735     else
00736         pix = QPixmap::fromImage( thumb );
00737     emit q->gotPreview(currentItem.item, pix);
00738 }
00739 
00740 QStringList PreviewJob::availablePlugins()
00741 {
00742     QStringList result;
00743     const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator");
00744     for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
00745         if (!result.contains((*it)->desktopEntryName()))
00746             result.append((*it)->desktopEntryName());
00747     return result;
00748 }
00749 
00750 QStringList PreviewJob::supportedMimeTypes()
00751 {
00752     QStringList result;
00753     const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator");
00754     for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
00755         result += (*it)->serviceTypes();
00756     return result;
00757 }
00758 
00759 #ifndef KDE_NO_DEPRECATED
00760 PreviewJob *KIO::filePreview( const KFileItemList &items, int width, int height,
00761     int iconSize, int iconAlpha, bool scale, bool save,
00762     const QStringList *enabledPlugins )
00763 {
00764     return new PreviewJob(items, width, height, iconSize, iconAlpha,
00765                           scale, save, enabledPlugins);
00766 }
00767 
00768 PreviewJob *KIO::filePreview( const KUrl::List &items, int width, int height,
00769     int iconSize, int iconAlpha, bool scale, bool save,
00770     const QStringList *enabledPlugins )
00771 {
00772     KFileItemList fileItems;
00773     for (KUrl::List::ConstIterator it = items.begin(); it != items.end(); ++it) {
00774         Q_ASSERT( (*it).isValid() ); // please call us with valid urls only
00775         fileItems.append(KFileItem(KFileItem::Unknown, KFileItem::Unknown, *it, true));
00776     }
00777     return new PreviewJob(fileItems, width, height, iconSize, iconAlpha,
00778                           scale, save, enabledPlugins);
00779 }
00780 #endif
00781 
00782 PreviewJob *KIO::filePreview(const KFileItemList &items, const QSize &size, const QStringList *enabledPlugins)
00783 {
00784     return new PreviewJob(items, size, enabledPlugins);
00785 }
00786 
00787 #ifndef KDE_NO_DEPRECATED
00788 KIO::filesize_t PreviewJob::maximumFileSize()
00789 {
00790     KConfigGroup cg( KGlobal::config(), "PreviewSettings" );
00791     return cg.readEntry( "MaximumSize", 5*1024*1024LL /* 5MB */ );
00792 }
00793 #endif
00794 
00795 #include "previewjob.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal