summaryrefslogtreecommitdiffstats
path: root/src/libs/thumbbar/thumbnailjob.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/thumbbar/thumbnailjob.cpp')
-rw-r--r--src/libs/thumbbar/thumbnailjob.cpp318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/libs/thumbbar/thumbnailjob.cpp b/src/libs/thumbbar/thumbnailjob.cpp
new file mode 100644
index 00000000..dcabb393
--- /dev/null
+++ b/src/libs/thumbbar/thumbnailjob.cpp
@@ -0,0 +1,318 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2003-10-14
+ * Description : digiKam TDEIO thumbnails generator interface
+ *
+ * Copyright (C) 2003-2005 by Renchi Raju <[email protected]>
+ * Copyright (C) 2006-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ *
+ * 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, 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.
+ *
+ * ============================================================ */
+
+// C Ansi includes.
+
+extern "C"
+{
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include <unistd.h>
+}
+
+// TQt includes.
+
+#include <tqstring.h>
+#include <tqdir.h>
+#include <tqfileinfo.h>
+#include <tqimage.h>
+#include <tqpixmap.h>
+#include <tqpainter.h>
+#include <tqcolor.h>
+#include <tqdatastream.h>
+
+// KDE includes.
+
+#include <tdeglobal.h>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "thumbnailjob.h"
+#include "thumbnailjob.moc"
+
+namespace Digikam
+{
+
+class ThumbnailJobPriv
+{
+public:
+
+ bool highlight;
+ bool exifRotate;
+ bool running;
+
+ int size;
+
+ // Shared memory segment Id. The segment is allocated to a size
+ // of extent x extent x 4 (32 bit image) on first need.
+ int shmid;
+
+ // And the data area
+ uchar *shmaddr;
+
+ KURL curr_url;
+ KURL next_url;
+ KURL::List urlList;
+};
+
+ThumbnailJob::ThumbnailJob(const KURL& url, int size,
+ bool highlight, bool exifRotate)
+ : TDEIO::Job(false)
+{
+ d = new ThumbnailJobPriv;
+
+ d->urlList.append(url);
+
+ d->size = size;
+ d->highlight = highlight;
+ d->exifRotate = exifRotate;
+ d->curr_url = d->urlList.first();
+ d->next_url = d->curr_url;
+ d->running = false;
+ d->shmid = -1;
+ d->shmaddr = 0;
+
+ processNext();
+}
+
+ThumbnailJob::ThumbnailJob(const KURL::List& urlList, int size,
+ bool highlight, bool exifRotate)
+ : TDEIO::Job(false)
+{
+ d = new ThumbnailJobPriv;
+
+ d->urlList = urlList;
+ d->size = size;
+ d->highlight = highlight;
+ d->running = false;
+ d->exifRotate = exifRotate;
+ d->curr_url = d->urlList.first();
+ d->next_url = d->curr_url;
+ d->shmid = -1;
+ d->shmaddr = 0;
+
+ processNext();
+}
+
+ThumbnailJob::~ThumbnailJob()
+{
+ if (d->shmaddr)
+ {
+ shmdt((char*)d->shmaddr);
+ shmctl(d->shmid, IPC_RMID, 0);
+ }
+
+ delete d;
+}
+
+void ThumbnailJob::addItem(const KURL& url)
+{
+ d->urlList.append(url);
+
+ if (!d->running && subjobs.isEmpty())
+ processNext();
+}
+
+void ThumbnailJob::addItems(const KURL::List& urlList)
+{
+ for (KURL::List::const_iterator it = urlList.begin();
+ it != urlList.end(); ++it)
+ {
+ d->urlList.append(*it);
+ }
+
+ if (!d->running && subjobs.isEmpty())
+ processNext();
+}
+
+bool ThumbnailJob::setNextItemToLoad(const KURL& url)
+{
+ KURL::List::const_iterator it = d->urlList.find(url);
+ if (it != d->urlList.end())
+ {
+ d->next_url = *it;
+ return true;
+ }
+
+ return false;
+}
+
+void ThumbnailJob::removeItem(const KURL& url)
+{
+ d->urlList.remove(url);
+}
+
+void ThumbnailJob::processNext()
+{
+ if (d->urlList.isEmpty())
+ {
+ d->running = false;
+ emit signalCompleted();
+ return;
+ }
+
+ KURL::List::iterator it = d->urlList.find(d->next_url);
+ if (it == d->urlList.end())
+ {
+ it = d->urlList.begin();
+ }
+
+ d->curr_url = *it;
+ it = d->urlList.remove(it);
+ if (it != d->urlList.end())
+ {
+ d->next_url = *it;
+ }
+ else
+ {
+ d->next_url = KURL();
+ }
+
+ KURL url(d->curr_url);
+ url.setProtocol("digikamthumbnail");
+
+ TDEIO::TransferJob *job = TDEIO::get(url, false, false);
+ job->addMetaData("size", TQString::number(d->size));
+ createShmSeg();
+
+ if (d->shmid != -1)
+ job->addMetaData("shmid", TQString::number(d->shmid));
+
+ // Rotate thumbnail accordindly with Exif rotation tag if necessary.
+ if (d->exifRotate)
+ job->addMetaData("exif", "yes");
+
+ connect(job, TQ_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
+ this, TQ_SLOT(slotThumbData(TDEIO::Job *, const TQByteArray &)));
+
+ addSubjob(job);
+ d->running = true;
+}
+
+void ThumbnailJob::slotResult(TDEIO::Job *job)
+{
+ subjobs.remove(job);
+ Q_ASSERT( subjobs.isEmpty() );
+
+ if (job->error())
+ {
+ emit signalFailed(d->curr_url);
+ }
+
+ d->running = false;
+ processNext();
+}
+
+void ThumbnailJob::createShmSeg()
+{
+ if (d->shmid == -1)
+ {
+ if (d->shmaddr)
+ {
+ shmdt((char*)d->shmaddr);
+ shmctl(d->shmid, IPC_RMID, 0);
+ }
+
+ d->shmid = shmget(IPC_PRIVATE, 256 * 256 * 4, IPC_CREAT|0600);
+ if (d->shmid != -1)
+ {
+ d->shmaddr = static_cast<uchar *>(shmat(d->shmid, 0, SHM_RDONLY));
+ if (d->shmaddr == (uchar *)-1)
+ {
+ shmctl(d->shmid, IPC_RMID, 0);
+ d->shmaddr = 0;
+ d->shmid = -1;
+ }
+ }
+ else
+ d->shmaddr = 0;
+ }
+}
+
+void ThumbnailJob::slotThumbData(TDEIO::Job*, const TQByteArray &data)
+{
+ if (data.isEmpty())
+ return;
+
+ TQImage thumb;
+ TQDataStream stream(data, IO_ReadOnly);
+ if (d->shmaddr)
+ {
+ int width, height, depth;
+ stream >> width >> height >> depth;
+ thumb = TQImage(d->shmaddr, width, height, depth,
+ 0, 0, TQImage::IgnoreEndian);
+
+ // The buffer supplied to the TQImage constructor above must remain valid
+ // throughout the lifetime of the object.
+ // This is not true, the shared memory will be freed or reused.
+ // If we pass the object around, we must do a deep copy.
+ thumb = thumb.copy();
+ }
+ else
+ {
+ stream >> thumb;
+ }
+
+ if (thumb.isNull())
+ {
+ DWarning() << k_funcinfo << "thumbnail is null" << endl;
+ emit signalFailed(d->curr_url);
+ return;
+ }
+
+ emitThumbnail(thumb);
+}
+
+void ThumbnailJob::emitThumbnail(TQImage& thumb)
+{
+ if (thumb.isNull())
+ {
+ return;
+ }
+
+ TQPixmap pix(thumb);
+
+ int w = pix.width();
+ int h = pix.height();
+
+ // highlight only when requested and when thumbnail
+ // width and height are greater than 10
+ if (d->highlight && (w >= 10 && h >= 10))
+ {
+ TQPainter p(&pix);
+ p.setPen(TQPen(TQColor(0,0,0),1));
+ p.drawRect(0,0,w,h);
+ p.end();
+ }
+
+ emit signalThumbnail(d->curr_url, pix);
+}
+
+} // namespace Digikam
+
+