36#include <QtCore/QFile>
37#include <QtGui/QImage>
38#include <QtCore/QTimer>
39#include <QtCore/QRegExp>
49#include <QtCore/QLinkedList>
56namespace KIO {
struct PreviewItem; }
59struct KIO::PreviewItem
68 enum { STATE_STATORIG,
75 QStringList enabledPlugins;
80 QLinkedList<PreviewItem> items;
82 PreviewItem currentItem;
102 bool ignoreMaximumSize;
121 void getOrCreateThumbnail();
122 bool statResultThumbnail();
123 void createThumbnail(
const QString& );
124 void determineNextFile();
125 void emitPreview(
const QImage &thumb);
128 void slotThumbData(
KIO::Job *,
const QByteArray &);
133#ifndef KDE_NO_DEPRECATED
135 int iconSize,
int iconAlpha,
bool scale,
bool save,
136 const QStringList *enabledPlugins )
137 :
KIO::
Job(*new PreviewJobPrivate)
143 d->initialItems = items;
146 d->height = height ? height : width;
147 d->cacheWidth = d->width;
148 d->cacheHeight = d->height;
149 d->iconSize = iconSize;
150 d->iconAlpha = iconAlpha;
152 d->bSave =
save && scale;
153 d->succeeded =
false;
154 d->thumbRoot = QDir::homePath() + QLatin1String(
"/.thumbnails/");
155 d->ignoreMaximumSize =
false;
156 d->sequenceIndex = 0;
157 d->maximumLocalSize = 0;
158 d->maximumRemoteSize = 0;
161 QTimer::singleShot(0,
this, SLOT(startPreview()));
167 const QStringList *enabledPlugins) :
168 KIO::
Job(*new PreviewJobPrivate)
174 d->initialItems = items;
175 if (enabledPlugins) {
176 d->enabledPlugins = *enabledPlugins;
179 d->enabledPlugins = globalConfig.
readEntry(
"Plugins", QStringList()
180 <<
"directorythumbnail"
184 d->width = size.width();
185 d->height = size.height();
186 d->cacheWidth = d->width;
187 d->cacheHeight = d->height;
192 d->succeeded =
false;
193 d->thumbRoot = QDir::homePath() + QLatin1String(
"/.thumbnails/");
194 d->ignoreMaximumSize =
false;
195 d->sequenceIndex = 0;
196 d->maximumLocalSize = 0;
197 d->maximumRemoteSize = 0;
200 QTimer::singleShot(0,
this, SLOT(startPreview()));
208 shmdt((
char*)d->shmaddr);
209 shmctl(d->shmid, IPC_RMID, 0);
229 d->iconAlpha = qBound(0, alpha, 255);
268void PreviewJobPrivate::startPreview()
275 for (KService::List::ConstIterator it = plugins.constBegin(); it != plugins.constEnd(); ++it) {
276 QStringList protocols = (*it)->property(
"X-KDE-Protocols").toStringList();
277 const QString p = (*it)->property(
"X-KDE-Protocol").toString();
281 foreach (
const QString &protocol, protocols) {
282 QStringList mtypes = (*it)->serviceTypes();
285 foreach (
const QString &_mtype, mtypes) {
286 if (!((*it)->hasMimeType(_mtype))) {
287 mtypes.removeAll(_mtype);
291 QStringList &_ms = m_remoteProtocolPlugins[protocol];
292 foreach (
const QString &_m, mtypes) {
293 protocolMap[protocol].insert(_m, *it);
294 if (!_ms.contains(_m)) {
299 if (enabledPlugins.contains((*it)->desktopEntryName())) {
300 const QStringList
mimeTypes = (*it)->serviceTypes();
301 for (QStringList::ConstIterator mt =
mimeTypes.constBegin(); mt !=
mimeTypes.constEnd(); ++mt)
302 mimeMap.insert(*mt, *it);
307 bool bNeedCache =
false;
308 KFileItemList::const_iterator kit = initialItems.constBegin();
309 const KFileItemList::const_iterator kend = initialItems.constEnd();
310 for ( ; kit != kend; ++kit )
314 const QString mimeType = item.item.mimetype();
319 if (it != protocolMap.constEnd()) {
320 plugin = it.value().value(mimeType);
325 if (pluginIt == mimeMap.constEnd()) {
326 QString groupMimeType = mimeType;
327 groupMimeType.replace(QRegExp(
"/.*"),
"/*");
328 pluginIt = mimeMap.constFind(groupMimeType);
330 if (pluginIt == mimeMap.constEnd()) {
334 const QStringList parentMimeTypes = mimeInfo->allParentMimeTypes();
335 Q_FOREACH(
const QString& parentMimeType, parentMimeTypes) {
336 pluginIt = mimeMap.constFind(parentMimeType);
337 if (pluginIt != mimeMap.constEnd())
344 if (pluginIt != mimeMap.constEnd()) {
350 item.plugin = plugin;
352 if (!bNeedCache && bSave &&
353 ((*kit).url().protocol() !=
"file" ||
355 plugin->property(
"CacheThumbnail").toBool()) {
359 emit q->failed( *kit );
364 maximumLocalSize = cg.readEntry(
"MaximumSize", 5*1024*1024LL );
365 maximumRemoteSize = cg.readEntry(
"MaximumRemoteSize", 0 );
369 if (width <= 128 && height <= 128) cacheWidth = cacheHeight = 128;
370 else cacheWidth = cacheHeight = 256;
371 thumbPath = thumbRoot + (cacheWidth == 128 ?
"normal/" :
"large/");
377 initialItems.clear();
384 for (QLinkedList<PreviewItem>::Iterator it = d->items.begin(); it != d->items.end(); ++it)
385 if ((*it).item.url() == url)
391 if (d->currentItem.item.url() == url)
396 d->determineNextFile();
401 d_func()->sequenceIndex = index;
405 return d_func()->sequenceIndex;
410 d_func()->ignoreMaximumSize = ignoreSize;
413void PreviewJobPrivate::determineNextFile()
416 if (!currentItem.item.isNull())
419 emit q->failed( currentItem.item );
422 if ( items.isEmpty() )
430 state = PreviewJobPrivate::STATE_STATORIG;
431 currentItem = items.first();
448 case PreviewJobPrivate::STATE_STATORIG:
453 d->determineNextFile();
459 bool skipCurrentItem =
false;
461 const KUrl itemUrl = d->currentItem.item.mostLocalUrl();
463 if (itemUrl.
isLocalFile() || KProtocolInfo::protocolClass(itemUrl.
protocol()) == QLatin1String(
":local"))
465 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumLocalSize
466 && !d->currentItem.plugin->property(
"IgnoreMaximumSize").toBool();
471 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumRemoteSize;
474 if (!skipCurrentItem) {
477 if (mime && mime->is(
"inode/directory")) {
478 skipCurrentItem =
true;
484 d->determineNextFile();
488 bool pluginHandlesSequences = d->currentItem.plugin->property(
"HandleSequences", QVariant::Bool).toBool();
489 if ( !d->currentItem.plugin->property(
"CacheThumbnail" ).toBool() || (d->sequenceIndex && pluginHandlesSequences) )
493 d->getOrCreateThumbnail();
497 if ( d->statResultThumbnail() )
500 d->getOrCreateThumbnail();
503 case PreviewJobPrivate::STATE_GETORIG:
507 d->determineNextFile();
514 case PreviewJobPrivate::STATE_CREATETHUMB:
516 if (!d->tempName.isEmpty())
518 QFile::remove(d->tempName);
521 d->determineNextFile();
527bool PreviewJobPrivate::statResultThumbnail()
529 if ( thumbPath.isEmpty() )
532 KUrl url = currentItem.item.mostLocalUrl();
535 origName = url.
url();
537 KMD5 md5( QFile::encodeName( origName ) );
538 thumbName = QFile::encodeName( md5.hexDigest() ) +
".png";
541 if ( !thumb.load( thumbPath + thumbName ) )
return false;
543 if ( thumb.text(
"Thumb::URI", 0 ) != origName ||
544 thumb.text(
"Thumb::MTime", 0 ).toInt() != tOrig )
return false;
546 QString thumbnailerVersion = currentItem.plugin->property(
"ThumbnailerVersion", QVariant::String).toString();
548 if (!thumbnailerVersion.isEmpty() && thumb.text(
"Software", 0).startsWith(
"KDE Thumbnail Generator")) {
551 QString softwareString = thumb.text(
"Software", 0).remove(
"KDE Thumbnail Generator").trimmed();
552 if (softwareString.isEmpty()) {
556 int versionIndex = softwareString.lastIndexOf(
"(v");
557 if (versionIndex < 0) {
561 QString cachedVersion = softwareString.remove(0, versionIndex+2);
562 cachedVersion.chop(1);
563 uint thumbnailerMajor = thumbnailerVersion.toInt();
564 uint cachedMajor = cachedVersion.toInt();
565 if (thumbnailerMajor > cachedMajor) {
571 emitPreview( thumb );
578void PreviewJobPrivate::getOrCreateThumbnail()
582 const KFileItem& item = currentItem.item;
583 const QString localPath = item.
localPath();
584 if (!localPath.isEmpty()) {
585 createThumbnail( localPath );
587 const KUrl fileUrl = item.
url();
589 bool supportsProtocol =
false;
590 if (m_remoteProtocolPlugins.value(fileUrl.scheme()).contains(item.
mimetype())) {
592 supportsProtocol =
true;
593 }
else if (m_remoteProtocolPlugins.value(
"KIO").contains(item.
mimetype())) {
596 supportsProtocol =
true;
599 if (supportsProtocol) {
600 createThumbnail(fileUrl.
url());
605 state = PreviewJobPrivate::STATE_GETORIG;
607 localFile.setAutoRemove(
false);
610 localURL.
setPath( tempName = localFile.fileName() );
618void PreviewJobPrivate::createThumbnail(
const QString &pixPath )
621 state = PreviewJobPrivate::STATE_CREATETHUMB;
627 q->connect(job, SIGNAL(data(
KIO::Job*,QByteArray)), SLOT(slotThumbData(
KIO::Job*,QByteArray)));
628 bool save = bSave && currentItem.plugin->property(
"CacheThumbnail").toBool() && !sequenceIndex;
629 job->
addMetaData(
"mimeType", currentItem.item.mimetype());
630 job->
addMetaData(
"width", QString().setNum(save ? cacheWidth : width));
631 job->
addMetaData(
"height", QString().setNum(save ? cacheHeight : height));
632 job->
addMetaData(
"iconSize", QString().setNum(save ? 64 : iconSize));
633 job->
addMetaData(
"iconAlpha", QString().setNum(iconAlpha));
634 job->
addMetaData(
"plugin", currentItem.plugin->library());
636 job->
addMetaData(
"sequence-index", QString().setNum(sequenceIndex));
642 shmdt((
char*)shmaddr);
643 shmctl(shmid, IPC_RMID, 0);
645 shmid = shmget(IPC_PRIVATE, cacheWidth * cacheHeight * 4, IPC_CREAT|0600);
648 shmaddr = (uchar *)(shmat(shmid, 0, SHM_RDONLY));
649 if (shmaddr == (uchar *)-1)
651 shmctl(shmid, IPC_RMID, 0);
660 job->
addMetaData(
"shmid", QString().setNum(shmid));
664void PreviewJobPrivate::slotThumbData(
KIO::Job *,
const QByteArray &data)
667 currentItem.plugin->property(
"CacheThumbnail").toBool() &&
668 (currentItem.item.url().protocol() !=
"file" ||
675 QDataStream str(data);
678 str >> width >> height >> iFormat;
679 QImage::Format format =
static_cast<QImage::Format
>( iFormat );
680 thumb = QImage(shmaddr, width, height, format ).copy();
684 thumb.loadFromData(data);
686 if (thumb.isNull()) {
691 QString tempFileName;
692 bool savedCorrectly =
false;
695 thumb.setText(
"Thumb::URI", origName);
696 thumb.setText(
"Thumb::MTime", QString::number(tOrig));
697 thumb.setText(
"Thumb::Size",
number(currentItem.item.size()));
698 thumb.setText(
"Thumb::Mimetype", currentItem.item.mimetype());
699 QString thumbnailerVersion = currentItem.plugin->property(
"ThumbnailerVersion", QVariant::String).toString();
700 QString signature = QString(
"KDE Thumbnail Generator "+currentItem.plugin->name());
701 if (!thumbnailerVersion.isEmpty()) {
702 signature.append(
" (v"+thumbnailerVersion+
')');
704 thumb.setText(
"Software", signature);
708 temp.setAutoRemove(
false);
711 tempFileName = temp.fileName();
712 savedCorrectly = thumb.save(tempFileName,
"PNG");
717 Q_ASSERT(!tempFileName.isEmpty());
720 emitPreview( thumb );
724void PreviewJobPrivate::emitPreview(
const QImage &thumb)
728 if (thumb.width() > width || thumb.height() > height)
729 pix = QPixmap::fromImage( thumb.scaled(QSize(width, height), Qt::KeepAspectRatio, Qt::SmoothTransformation) );
731 pix = QPixmap::fromImage( thumb );
732 emit q->gotPreview(currentItem.item, pix);
739 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
740 if (!
result.contains((*it)->desktopEntryName()))
741 result.append((*it)->desktopEntryName());
749 for (KService::List::ConstIterator it = plugins.begin(); it != plugins.end(); ++it)
750 result += (*it)->serviceTypes();
754#ifndef KDE_NO_DEPRECATED
756 int iconSize,
int iconAlpha,
bool scale,
bool save,
757 const QStringList *enabledPlugins )
759 return new PreviewJob(items, width, height, iconSize, iconAlpha,
760 scale,
save, enabledPlugins);
764 int iconSize,
int iconAlpha,
bool scale,
bool save,
765 const QStringList *enabledPlugins )
768 for (KUrl::List::ConstIterator it = items.begin(); it != items.end(); ++it) {
769 Q_ASSERT( (*it).isValid() );
772 return new PreviewJob(fileItems, width, height, iconSize, iconAlpha,
773 scale,
save, enabledPlugins);
779 return new PreviewJob(items, size, enabledPlugins);
782#ifndef KDE_NO_DEPRECATED
786 return cg.
readEntry(
"MaximumSize", 5*1024*1024LL );
790#include "previewjob.moc"
const QList< KJob * > & subjobs() const
QString readEntry(const char *key, const char *aDefault=0) const
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
A KFileItem is a generic class to handle a file, local or remote.
KUrl mostLocalUrl(bool &local) const
Tries to give a local URL for this file item if possible.
QString mimetype() const
Returns the mimetype of the file item.
QString localPath() const
Returns the local path if isLocalFile() == true or the KIO item has a UDS_LOCAL_PATH atom.
KUrl url() const
Returns the url of the file.
The FileCopyJob copies data from one place to another.
KUrl destUrl() const
Returns the destination URL.
The base class for all jobs.
virtual bool removeSubjob(KJob *job)
Mark a sub job as being done.
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the slave.
KIO Job to get a thumbnail picture.
int sequenceIndex() const
Returns the currently set sequence index.
void setScaleType(ScaleType type)
Sets the scale type for the generated preview.
static QStringList supportedMimeTypes()
Returns a list of all supported MIME types.
static QStringList availablePlugins()
Returns a list of all available preview plugins.
void removeItem(const KUrl &url)
Removes an item from preview processing.
virtual void slotResult(KJob *job)
ScaleType
Specifies the type of scaling that is applied to the generated preview.
@ Unscaled
The original size of the preview will be returned.
@ Scaled
The preview will be scaled to the size specified when constructing the PreviewJob.
@ ScaledAndCached
The preview will be scaled to the size specified when constructing the PreviewJob.
static KIO::filesize_t maximumFileSize()
Returns the default "maximum file size", in bytes, used by PreviewJob.
void setOverlayIconSize(int size)
Sets the size of the MIME-type icon which overlays the preview.
PreviewJob(const KFileItemList &items, int width, int height, int iconSize, int iconAlpha, bool scale, bool save, const QStringList *enabledPlugins)
Creates a new PreviewJob.
void setOverlayIconAlpha(int alpha)
Sets the alpha-value for the MIME-type icon which overlays the preview.
void setSequenceIndex(int index)
Sets the sequence index given to the thumb creators.
int overlayIconSize() const
ScaleType scaleType() const
void setIgnoreMaximumSize(bool ignoreSize=true)
If ignoreSize is true, then the preview is always generated regardless of the settings.
int overlayIconAlpha() const
A KIO job that retrieves information about a file or directory.
The transfer job pumps data into and/or out of a Slave.
Universal Directory Service.
long long numberValue(uint field, long long defaultValue=0) const
@ UDS_MODIFICATION_TIME
The last time the file was modified.
@ UDS_SIZE
Size of the file.
bool kill(KillVerbosity verbosity=Quietly)
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
static KServiceTypeTrader * self()
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
static bool makeDir(const QString &dir, int mode=0755)
void setPrefix(const QString &prefix)
void setSuffix(const QString &suffix)
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
void setProtocol(const QString &proto)
void setPath(const QString &path)
void setPass(const QString &pass)
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
int rename(const QString &in, const QString &out)
KSharedConfigPtr config()
A namespace for KIO globals.
StatJob * stat(const KUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
FileCopyJob * file_copy(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
Copy a single file.
TransferJob * get(const KUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
Get (a.k.a.
PreviewJob * filePreview(const KFileItemList &items, int width, int height=0, int iconSize=0, int iconAlpha=70, bool scale=true, bool save=true, const QStringList *enabledPlugins=0)
Creates a PreviewJob to generate or retrieve a preview image for the given URL.
@ HideProgressInfo
Hide progress information dialog, i.e.
@ Overwrite
When set, automatically overwrite the destination if it exists already.
qulonglong filesize_t
64-bit file size
QString number(KIO::filesize_t size)
Converts a size to a string representation Not unlike QString::number(...)
QStringList mimeTypes(Mode mode=Writing)
Returns a list of MIME types for all KImageIO supported formats.
KAction * save(const QObject *recvr, const char *slot, QObject *parent)