diff options
Diffstat (limited to 'src/sq_thumbnailloadjob.cpp')
-rw-r--r-- | src/sq_thumbnailloadjob.cpp | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/src/sq_thumbnailloadjob.cpp b/src/sq_thumbnailloadjob.cpp new file mode 100644 index 0000000..e75dcf4 --- /dev/null +++ b/src/sq_thumbnailloadjob.cpp @@ -0,0 +1,480 @@ +/* + copyright : (C) 2004 by Baryshev Dmitry + KSquirrel - image viewer for KDE +*/ + +/* This file is part of the KDE project + Copyright (C) 2000 David Faure <faure@kde.org> + 2000 Carsten Pfeiffer <pfeiffer@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <tqdir.h> +#include <tqimage.h> +#include <tqpainter.h> +#include <tqlabel.h> +#include <tqdatetime.h> + +#include <tdefileitem.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <tdetempfile.h> +#include <kdebug.h> + +#include "sq_config.h" +#include "sq_widgetstack.h" +#include "sq_pixmapcache.h" +#include "sq_dirthumbs.h" +#include "sq_thumbnailloadjob.h" +#include "sq_libraryhandler.h" +#include "sq_thumbnailsize.h" +#include "sq_thumbnailsunused.h" +#include "sq_utils.h" +#include "sq_filethumbview.h" +#include "sq_filethumbviewitem.h" +#include "sq_imageloader.h" + +#include <ksquirrel-libs/fmt_defs.h> + +#include <string> + +#define SQ_PREDOWNLOAD_SIZE 20 + +SQ_ThumbnailLoadJob::SQ_ThumbnailLoadJob(const KFileItemList &items, SQ_FileThumbView *parnt) + : TDEIO::Job(false), parent(parnt) +{ + mBrokenThumbnail.thumbnail = TDEGlobal::iconLoader()->loadIcon("file_broken", TDEIcon::Desktop, SQ_ThumbnailSize::smallest()); + mItems = items; + + donothing = false; + + dir = new SQ_DirThumbs; +} + +SQ_ThumbnailLoadJob::~SQ_ThumbnailLoadJob() +{ + delete dir; +} + +void SQ_ThumbnailLoadJob::start() +{ + if(mItems.isEmpty()) + { + emit done(); + delete this; + return; + } + + determineNextIcon(); +} + +void SQ_ThumbnailLoadJob::appendItem(const KFileItem* item) +{ + mItems.append(item); +} + +void SQ_ThumbnailLoadJob::itemRemoved(const KFileItem* item) +{ + mItems.removeRef(item); + + nextFile(item == mCurrentItem); +} + +void SQ_ThumbnailLoadJob::itemsRemoved(const KFileItemList &items) +{ + KFileItem *item; + bool next = false; + KFileItemList *m_items = const_cast<KFileItemList *>(&items); + + if(!mItems.isEmpty() && !items.isEmpty()) + { + for(item = m_items->first();item;item = m_items->next()) + { + mItems.removeRef(item); + + if(item == mCurrentItem) + next = true; + } + } + + nextFile(next); +} + +void SQ_ThumbnailLoadJob::pop(const KFileItemList &items) +{ + KFileItem *item; + bool next = false; + KFileItemList *m_items = const_cast<KFileItemList *>(&items); + + if(!mItems.isEmpty() && !items.isEmpty()) + { + for(item = m_items->first();item;item = m_items->next()) + { + mItems.removeRef(item); + + if(item == mCurrentItem) + next = true; + } + + for(item = m_items->last();item;item = m_items->prev()) + mItems.prepend(item); + } + + nextFile(next); +} + +void SQ_ThumbnailLoadJob::nextFile(bool b) +{ + if(b) + { + TDEIO::Job *j = subjobs.first(); + + if(j) + { + j->kill(); + subjobs.removeFirst(); + } + + determineNextIcon(); + } +} + +void SQ_ThumbnailLoadJob::determineNextIcon() +{ + if(donothing) + return; + + KFileItem *item = 0; + SQ_FileThumbViewItem *tfi; + + while(true) + { + item = mItems.first(); + + if(!item) + { + emit done(); + delete this; + return; + } + + SQ_WidgetStack::instance()->thumbnailProcess(); + + tfi = reinterpret_cast<SQ_FileThumbViewItem *>(item->extraData(parent)); + + // 1) local urls that are 100% supported, or + // 2) remote urls that are 100% supported or _maybe_ supported (application/octet-stream) + if(item->isReadable() && SQ_LibraryHandler::instance()->maybeSupported(item->url(), item->mimetype()) != SQ_LibraryHandler::No) + break; + else + { + mItems.removeFirst(); + tfi->setListed(true); + } + } + + if(mItems.isEmpty() || !item) + { + emit done(); + delete this; + return; + } + else + { + mState = STATE_STATORIG; + mCurrentItem = mItems.first(); + mCurrentURL = mCurrentItem->url(); + mItems.removeFirst(); + + TDEIO::StatJob *job = TDEIO::stat(mCurrentURL, false); + job->setSide(true); + job->setDetails(0); + addSubjob(job); + } +} + +void SQ_ThumbnailLoadJob::slotResult(TDEIO::Job *job) +{ + subjobs.remove(job); +// Q_ASSERT(subjobs.isEmpty()); + + switch(mState) + { + case STATE_STATORIG: + { + TDEIO::UDSEntry entry = mCurrentItem->entry(); + TDEIO::UDSEntry::ConstIterator it = entry.begin(); + mOriginalTime = 0; + size = totalSize = 0; + TQString suff; + + for(; it != entry.end(); ++it) + { + if((*it).m_uds == TDEIO::UDS_MODIFICATION_TIME) + { + mOriginalTime = (time_t)((*it).m_long); + } + else if((*it).m_uds == TDEIO::UDS_SIZE) + { + totalSize = (TDEIO::filesize_t)((*it).m_long); + } + else if((*it).m_uds == TDEIO::UDS_NAME) + { + suff = (*it).m_str; + } + } + + mThumbURL.setPath(dir->absPath(mCurrentURL)); + + if(mCurrentURL.isLocalFile()) + { + if(!statResultThumbnail()) + createThumbnail(mCurrentURL); + + determineNextIcon(); + } + else if(statResultThumbnail()) + determineNextIcon(); + else if(SQ_ThumbnailsUnused::instance()->needUpdate(mCurrentURL, mOriginalTime)) + { + mState = STATE_PREDOWNLOAD; + continueDownload = false; + + tmp = new KTempFile(TQString(), TQString::fromLatin1(".%1").arg(suff), 0600); + tmp->setAutoDelete(true); + tmp->close(); + + mTempURL.setPath(tmp->name()); + + TDEIO::Job *cpjob = TDEIO::get(mCurrentURL, false, false); + + connect(cpjob, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), + this, TQ_SLOT(slotData(TDEIO::Job *, const TQByteArray &))); + + addSubjob(cpjob); + } + else + determineNextIcon(); + } + break; + + case STATE_PREDOWNLOAD: + { + // error + if(job->error() && job->error() != TDEIO::ERR_USER_CANCELED) + emitThumbnailLoadingFailed(); + + // no errors, or canceled + delete tmp; + determineNextIcon(); + } + break; + + case STATE_DOWNLOAD: + { + if(job->error()) + emitThumbnailLoadingFailed(); + else if(SQ_LibraryHandler::instance()->libraryForFile(mTempURL.path())) + createThumbnail(mTempURL); + else + SQ_ThumbnailsUnused::instance()->insert(mCurrentURL, mOriginalTime); + + delete tmp; + determineNextIcon(); + } + break; + } +} + +void SQ_ThumbnailLoadJob::slotData(TDEIO::Job *job, const TQByteArray &data) +{ + if(!data.size()) + return; + + size += data.size(); + + TQFile f(mTempURL.path()); + + if(f.open(IO_WriteOnly | IO_Append)) + { + f.writeBlock(data); + f.close(); + } + + // 20 bytes are enough to determine file type + if(size >= SQ_PREDOWNLOAD_SIZE && !continueDownload) + { + // cancel download (file type is not supported) + if(totalSize != size + && !SQ_LibraryHandler::instance()->libraryForFile(mTempURL.path())) + { + SQ_ThumbnailsUnused::instance()->insert(mCurrentURL, mOriginalTime); + job->kill(false); // kill job & emit result + } + else if(!statResultThumbnail()) + { + // nice, we can open this image - + // go to 'STATE_DOWNLOAD' stage and continue download + continueDownload = true; + mState = STATE_DOWNLOAD; + } + else if(size != totalSize) + { + job->kill(true); // kill job + subjobs.remove(job); + determineNextIcon(); + } + } +} + +bool SQ_ThumbnailLoadJob::statResultThumbnail() +{ + SQ_Thumbnail th; + + if(SQ_PixmapCache::instance()->contains2(mCurrentURL, th)) + { + emitThumbnailLoaded(th); + return true; + } + + if(dir->needUpdate(mThumbURL.path(), mOriginalTime)) + { +// kdDebug() << "STAT **** thumbnailTime < mOriginalTime ****" << endl; + return false; + } + + if(!th.thumbnail.load(mThumbURL.path(), sqdirThumbFormat)) + return false; + + SQ_LIBRARY *lib = SQ_LibraryHandler::instance()->libraryForFile(mCurrentURL); + + th.w = th.thumbnail.text("Thumb::Image::Width").toInt(); + th.h = th.thumbnail.text("Thumb::Image::Height").toInt(); + + if((!th.w || !th.h) && mCurrentURL.isLocalFile()) + SQ_ImageLoader::instance()->tasteImage(mCurrentURL.path(), &th.w, &th.h, lib); + + th.mime = lib->mime; + th.originalTime = mOriginalTime; + th.mime.load(dir->absPath(mCurrentURL), sqdirMimeFormat); + + insertOrSync(mCurrentURL, th); + + emitThumbnailLoaded(th); + + return true; +} + +void SQ_ThumbnailLoadJob::createThumbnail(const KURL &pixPath) +{ + SQ_Thumbnail th; + bool loaded = false; + + if(SQ_PixmapCache::instance()->contains2(pixPath, th)) + { + emitThumbnailLoaded(th); +// kdDebug() << "CREATE found in cache \"" << pixPath << "\"" << endl; + return; + } + + loaded = SQ_Utils::loadThumbnail(pixPath, th); + + if(loaded) + { + th.originalTime = mOriginalTime; + th.thumbnail = th.thumbnail.swapRGB(); + insertOrSync(mCurrentURL, th); + emitThumbnailLoaded(th); + } + else + emitThumbnailLoadingFailed(); +} + +void SQ_ThumbnailLoadJob::insertOrSync(const KURL &url, SQ_Thumbnail &th) +{ + if(!SQ_PixmapCache::instance()->full()) + { + SQ_PixmapCache::instance()->insert(url, th); +// kdDebug() << "IOSYNC inserting \"" << url.url() << "\"" << endl; + } + else + { +// kdDebug() << "IOSYNC SQ_PixmapCache is full! Cache is ignored!" << endl; + SQ_PixmapCache::instance()->syncEntry(url, th); + } +} + +void SQ_ThumbnailLoadJob::emitThumbnailLoaded(SQ_Thumbnail &t) +{ + int biggestDimension = TQMAX(t.thumbnail.width(), t.thumbnail.height()); + int thumbPixelSize = SQ_ThumbnailSize::instance()->pixelSize(); + + if(biggestDimension <= thumbPixelSize) + { + emit thumbnailLoaded(mCurrentItem, t); + return; + } + + t.thumbnail = SQ_Utils::scaleImage( + t.thumbnail.bits(), + t.thumbnail.width(), + t.thumbnail.height(), + thumbPixelSize); + + emit thumbnailLoaded(mCurrentItem, t); +} + +void SQ_ThumbnailLoadJob::emitThumbnailLoadingFailed() +{ + emit thumbnailLoaded(mCurrentItem, mBrokenThumbnail); +} + +void SQ_ThumbnailLoadJob::appendItems(const KFileItemList &items) +{ + KFileItem *item; + KFileItemList *m_items = const_cast<KFileItemList *>(&items); + + if(!mItems.isEmpty() && !items.isEmpty()) + { + for(item = m_items->first();item;item = m_items->next()) + mItems.append(item); + } +} + +void SQ_ThumbnailLoadJob::prependItems(const KFileItemList &items) +{ + KFileItem *item; + KFileItemList *m_items = const_cast<KFileItemList *>(&items); + + if(!mItems.isEmpty() && !items.isEmpty()) + { + for(item = m_items->last();item;item = m_items->prev()) + mItems.prepend(item); + } +} + +void SQ_ThumbnailLoadJob::kill(bool q) +{ + donothing = true; + + TDEIO::Job::kill(q); +} + +#include "sq_thumbnailloadjob.moc" |