28 #include <sys/types.h>
35 #include <QtCore/QDir>
36 #include <QtCore/QFile>
37 #include <QtGui/QImage>
38 #include <QtCore/QTimer>
39 #include <QtCore/QRegExp>
49 #include <QtCore/QLinkedList>
56 namespace KIO {
struct PreviewItem; }
59 struct KIO::PreviewItem
68 enum { STATE_STATORIG,
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,
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()));
168 KIO::
Job(*new PreviewJobPrivate)
174 d->initialItems = items;
175 if (enabledPlugins) {
176 d->enabledPlugins = *enabledPlugins;
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);
268 void 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) {
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())) {
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()) {
332 const KMimeType::Ptr mimeInfo = KMimeType::mimeType(mimeType);
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;
413 void 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();
465 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumLocalSize
466 && !d->currentItem.plugin->property(
"IgnoreMaximumSize").toBool();
471 skipCurrentItem = !d->ignoreMaximumSize && size > d->maximumRemoteSize;
474 if (!skipCurrentItem) {
476 KMimeType::Ptr mime = d->currentItem.item.mimeTypePtr();
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();
511 d->createThumbnail( static_cast<KIO::FileCopyJob*>(job)->destUrl().toLocalFile() );
514 case PreviewJobPrivate::STATE_CREATETHUMB:
516 if (!d->tempName.isEmpty())
518 QFile::remove(d->tempName);
521 d->determineNextFile();
527 bool 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 );
578 void PreviewJobPrivate::getOrCreateThumbnail()
582 const KFileItem& item = currentItem.item;
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() );
618 void 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());
634 job->
addMetaData(
"plugin", currentItem.plugin->library());
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);
664 void 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()) {
692 bool savedCorrectly =
false;
695 thumb.setText(
"Thumb::URI", origName);
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 );
724 void 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,
759 return new PreviewJob(items, width, height, iconSize, iconAlpha,
760 scale, save, enabledPlugins);
764 int iconSize,
int iconAlpha,
bool scale,
bool save,
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"
void removeItem(const KUrl &url)
Removes an item from preview processing.
When set, automatically overwrite the destination if it exists already.
static QStringList availablePlugins()
Returns a list of all available preview plugins.
qulonglong filesize_t
64-bit file size
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the slave.
void setOverlayIconSize(int size)
Sets the size of the MIME-type icon which overlays the preview.
void setPrefix(const QString &prefix)
Universal Directory Service.
QString mimetype() const
Returns the mimetype of the file item.
static KServiceTypeTrader * self()
Hide progress information dialog, i.e.
void setScaleType(ScaleType type)
Sets the scale type for the generated preview.
TransferJob * get(const KUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
Get (a.k.a.
int rename(const QString &in, const QString &out)
StatJob * stat(const KUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
A KIO job that retrieves information about a file or directory.
virtual bool removeSubjob(KJob *job)
Mark a sub job as being done.
void setSuffix(const QString &suffix)
The original size of the preview will be returned.
int overlayIconAlpha() const
KSharedConfigPtr config()
void setPath(const QString &path)
static bool makeDir(const QString &dir, int mode=0755)
int sequenceIndex() const
Returns the currently set sequence index.
void setProtocol(const QString &proto)
static KIO::filesize_t maximumFileSize()
Returns the default "maximum file size", in bytes, used by PreviewJob.
FileCopyJob * file_copy(const KUrl &src, const KUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
Copy a single file.
ScaleType scaleType() const
long long numberValue(uint field, long long defaultValue=0) const
QString localPath() const
Returns the local path if isLocalFile() == true or the KIO item has a UDS_LOCAL_PATH atom...
List of KFileItems, which adds a few helper methods to QList.
void setPass(const QString &pass)
PreviewJob(const KFileItemList &items, int width, int height, int iconSize, int iconAlpha, bool scale, bool save, const QStringList *enabledPlugins)
Creates a new PreviewJob.
static QString protocolClass(const QString &protocol)
QStringList mimeTypes(Mode mode=Writing)
Returns a list of MIME types for all KImageIO supported formats.
The last time the file was modified.
KIO Job to get a thumbnail picture.
KService::List query(const QString &servicetype, const QString &constraint=QString()) const
The preview will be scaled to the size specified when constructing the PreviewJob.
void setIgnoreMaximumSize(bool ignoreSize=true)
If ignoreSize is true, then the preview is always generated regardless of the settings.
void setOverlayIconAlpha(int alpha)
Sets the alpha-value for the MIME-type icon which overlays the preview.
The base class for all jobs.
const QList< KJob * > & subjobs() const
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.
ScaleType
Specifies the type of scaling that is applied to the generated preview.
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
virtual void slotResult(KJob *job)
The transfer job pumps data into and/or out of a Slave.
static QStringList supportedMimeTypes()
Returns a list of all supported MIME types.
KAction * save(const QObject *recvr, const char *slot, QObject *parent)
T readEntry(const QString &key, const T &aDefault) const
The preview will be scaled to the size specified when constructing the PreviewJob.
KUrl url() const
Returns the url of the file.
KUrl mostLocalUrl(bool &local) const
Tries to give a local URL for this file item if possible.
A KFileItem is a generic class to handle a file, local or remote.
int overlayIconSize() const
QString number(KIO::filesize_t size)
Converts a size to a string representation Not unlike QString::number(...)
void setSequenceIndex(int index)
Sets the sequence index given to the thumb creators.