summaryrefslogtreecommitdiffstats
path: root/ksquirrel/sq_filethumbview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ksquirrel/sq_filethumbview.cpp')
-rw-r--r--ksquirrel/sq_filethumbview.cpp549
1 files changed, 549 insertions, 0 deletions
diff --git a/ksquirrel/sq_filethumbview.cpp b/ksquirrel/sq_filethumbview.cpp
new file mode 100644
index 0000000..7d3423e
--- /dev/null
+++ b/ksquirrel/sq_filethumbview.cpp
@@ -0,0 +1,549 @@
+/***************************************************************************
+ sq_fileiconview.cpp - description
+ -------------------
+ begin : Mon Mar 15 2004
+ copyright : (C) 2004 by Baryshev Dmitry
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <qpainter.h>
+#include <qhbox.h>
+#include <qtoolbar.h>
+#include <qtoolbutton.h>
+#include <qlabel.h>
+#include <qtimer.h>
+#include <qapplication.h>
+
+#include <kstandarddirs.h>
+#include <kstringhandler.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kglobal.h>
+
+#include "ksquirrel.h"
+#include "sq_iconloader.h"
+#include "sq_config.h"
+#include "sq_dir.h"
+#include "sq_filethumbview.h"
+#include "sq_libraryhandler.h"
+#include "sq_thumbnailloadjob.h"
+#include "sq_thumbnailsize.h"
+#include "sq_widgetstack.h"
+#include "sq_diroperator.h"
+#include "sq_progress.h"
+#include "sq_progressbox.h"
+#include "sq_filethumbviewitem.h"
+#include "sq_dragprovider.h"
+
+SQ_FileThumbView::SQ_FileThumbView(QWidget *parent, const char *name) : SQ_FileIconViewBase(parent, name), isPending(false)
+{
+ // create progress bar
+ m_progressBox = new SQ_ProgressBox(this);
+
+ timerScroll = new QTimer(this);
+ connect(timerScroll, SIGNAL(timeout()), this, SLOT(slotDelayedContentsMoving()));
+
+ timerAdd = new QTimer(this);
+ connect(timerAdd, SIGNAL(timeout()), this, SLOT(slotDelayedAddItems()));
+
+ // setup cache limit
+ SQ_Config::instance()->setGroup("Thumbnails");
+ m_lazy = SQ_Config::instance()->readBoolEntry("lazy", true);
+ lazyDelay = SQ_Config::instance()->readNumEntry("lazy_delay", 500);
+ if(lazyDelay <= 0) lazyDelay = 500;
+ m_rows = SQ_Config::instance()->readNumEntry("rows", 2);
+ if(m_rows <= 0 || m_rows > 5) m_rows = 2;
+
+ setResizeMode(QIconView::Adjust);
+
+ // load "pending" pixmaps
+ pending = SQ_IconLoader::instance()->loadIcon("clock", KIcon::Desktop, 32);
+
+ connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotContentsMoving(int, int)));
+
+ rebuildCachedPixmaps();
+}
+
+SQ_FileThumbView::~SQ_FileThumbView()
+{}
+
+/*
+ * Reimplement insertItem() to enable/disable inserting
+ * directories (depends on current settings) and inserting thumbnails.
+ */
+void SQ_FileThumbView::insertItem(KFileItem *i)
+{
+ SQ_Config::instance()->setGroup("Fileview");
+
+ // directores disabled ?
+ if(i->isDir() && SQ_Config::instance()->readBoolEntry("disable_dirs", false))
+ return;
+
+ SQ_Config::instance()->setGroup("Thumbnails");
+
+ SQ_FileThumbViewItem *item;
+
+ setUpdatesEnabled(false);
+ if(SQ_Config::instance()->readBoolEntry("mark", false) && SQ_LibraryHandler::instance()->libraryForFile(i->url().path()))
+ {
+ item = new SQ_FileThumbViewItem(this, i->text(), pendingCache, i);
+ }
+ else
+ {
+ QPixmap mimeall = i->pixmap(SQ_ThumbnailSize::smallest());
+ QPixmap thumbnail(pixelSize.width(), pixelSize.height());
+ QPainter painter(&thumbnail);
+ painter.setBrush(colorGroup().base());
+ painter.setPen(colorGroup().highlight());
+ painter.drawRect(0, 0, pixelSize.width(), pixelSize.height());
+ painter.drawPixmap((pixelSize.width()-mimeall.width())/2, (pixelSize.height()-mimeall.height())/2, mimeall);
+ item = new SQ_FileThumbViewItem(this, i->text(), thumbnail, i);
+ }
+
+ initItemMy(item, i);
+
+ i->setExtraData(this, item);
+ setUpdatesEnabled(true);
+}
+
+/*
+ * One thumbnail is loaded. Let's update KFileItem's pixmap.
+ */
+void SQ_FileThumbView::setThumbnailPixmap(const KFileItem* fileItem, const SQ_Thumbnail &t)
+{
+ KFileIconViewItem *iconItem = viewItem(fileItem);
+
+ if(!iconItem) return;
+
+ SQ_FileThumbViewItem *item = static_cast<SQ_FileThumbViewItem*>(iconItem);
+
+ if(!item) return;
+
+ QPixmap newpix;
+
+ // Extended thumbnail also have mime icon and dimensions
+ if(SQ_ThumbnailSize::instance()->extended())
+ {
+ QSize sz = pixelSize;//SQ_ThumbnailSize::instance()->extendedSize();
+ int W = sz.width(), H = sz.height();
+
+ // erase original pixmap
+ newpix.resize(W, H);
+
+ QPainter painter;
+ painter.begin(&newpix);
+
+ painter.setPen(colorGroup().highlight());
+ painter.setBrush(colorGroup().base());
+
+ // draw bounding rect
+ painter.drawRect(0, 0, W, H);
+
+ painter.drawImage((W - t.thumbnail.width())/2, (W - t.thumbnail.height())/2, t.thumbnail);
+ painter.drawPixmap(W-t.mime.width()-5, H-t.mime.height()-4, t.mime);
+ painter.drawLine(3, W-1, W-4, W-1);
+
+ QFont f = painter.font();
+ f.setPixelSize(10);
+ painter.setFont(f);
+
+ int rest = H-W-2;
+
+ painter.setPen(colorGroup().text());
+
+ if(t.w && t.h) painter.drawText(4, W+rest/2-12, 100, 12, 0, QString::fromLatin1("%1x%2").arg(t.w).arg(t.h));
+
+ painter.drawText(4, W+rest/2+1, 100, 12, 0, KIO::convertSize(fileItem->size()));
+ painter.end();
+ }
+ else
+ {
+ newpix.resize(pixelSize.width(), pixelSize.height());
+
+ QPainter painter;
+ painter.begin(&newpix);
+
+ painter.setPen(colorGroup().highlight());
+ painter.setBrush(colorGroup().base());
+
+ // draw bounding rect
+ painter.drawRect(0, 0, pixelSize.width(), pixelSize.height());
+
+ // draw pixmap
+ painter.drawImage((pixelSize.width() - t.thumbnail.width())/2, (pixelSize.height() - t.thumbnail.height())/2, t.thumbnail);
+ painter.end();
+ }
+
+ item->setPixmap(newpix);
+ item->setListed(true);
+
+ // update item
+ item->repaint();
+}
+
+void SQ_FileThumbView::startThumbnailUpdate()
+{
+ stopThumbnailUpdate();
+ doStartThumbnailUpdate(itemsToUpdate());
+}
+
+KFileItemList SQ_FileThumbView::itemsToUpdate(bool fromAll)
+{
+ // non-lazy mode - simply return all items
+ if(!m_lazy)
+ return *items();
+
+ // hehe, lazy mode
+ KFileItemList list;
+
+ QRect rect(contentsX(), contentsY(), viewport()->width(), viewport()->height());
+ QIconViewItem *first = fromAll ? firstItem() : findFirstVisibleItem(rect);
+ QIconViewItem *last = fromAll ? lastItem() : findLastVisibleItem(rect);
+
+ if(first && last)
+ {
+ SQ_FileThumbViewItem *tfi;
+
+ QIconViewItem *f = first;
+ int yy;
+
+ if(m_rows)
+ {
+ // one row more up and down
+ for(int i = 0;i < m_rows;++i)
+ {
+ if(!last) break;
+
+ last = last->nextItem();
+
+ if(last)
+ {
+ yy = last->y();
+
+ while((last = last->nextItem()) && last->y() == yy)
+ {}
+ }
+ }
+
+ for(int i = 0;i < m_rows;++i)
+ {
+ f = first->prevItem();
+
+ if(f)
+ {
+ yy = f->y();
+
+ while((f = first->prevItem()) && f->y() == yy)
+ first = f;
+ }
+ }
+ }
+ else
+ last = last->nextItem();
+
+ for(QIconViewItem *item = first;(item && item != last);item = item->nextItem())
+ {
+ tfi = dynamic_cast<SQ_FileThumbViewItem *>(item);
+
+ if(tfi && !tfi->listed())
+ list.append(tfi->fileInfo());
+ }
+ }
+
+ return list;
+}
+
+void SQ_FileThumbView::slotContentsMoving(int, int)
+{
+ if(isVisible())
+ timerScroll->start(lazyDelay, true);
+ else
+ waitForShowEvent();
+}
+
+void SQ_FileThumbView::slotDelayedContentsMoving()
+{
+ // restart generator in lazy mode
+ if(m_lazy)
+ {
+ stopThumbnailUpdate();
+ doStartThumbnailUpdate(itemsToUpdate());
+ }
+ // make visible items first items in the job
+ else
+ {
+ // force itemsToUpdate() return only visible items
+ // that need update
+ m_lazy = true;
+ KFileItemList visibleItems = itemsToUpdate();
+
+ if(updateRunning())
+ thumbJob->pop(visibleItems);
+
+ // restore lazy mode
+ m_lazy = false;
+ }
+}
+
+/*
+ * Create job, connect signals and start updating
+ */
+void SQ_FileThumbView::doStartThumbnailUpdate(const KFileItemList &list)
+{
+ if(list.isEmpty())
+ return;
+
+ // update progress bar
+ SQ_WidgetStack::instance()->thumbnailUpdateStart(list.count());
+
+ // create new job
+ thumbJob = new SQ_ThumbnailLoadJob(list, this);
+
+ connect(thumbJob, SIGNAL(thumbnailLoaded(const KFileItem*, const SQ_Thumbnail &)),
+ this, SLOT(setThumbnailPixmap(const KFileItem*, const SQ_Thumbnail&)));
+
+ connect(thumbJob, SIGNAL(done()), SQ_WidgetStack::instance(), SLOT(thumbnailsUpdateEnded()));
+
+ // start!
+ thumbJob->start();
+}
+
+// Stop thumbnail update: delete job, reset progress bar
+void SQ_FileThumbView::stopThumbnailUpdate()
+{
+ timerScroll->stop();
+ timerAdd->stop();
+ newItems.clear();
+
+ if(!thumbJob.isNull())
+ {
+ thumbJob->kill();
+ SQ_WidgetStack::instance()->thumbnailsUpdateEnded();
+ }
+}
+
+// Start/stop thumbnail job
+void SQ_FileThumbView::slotThumbnailUpdateToggle()
+{
+ if(!thumbJob.isNull())
+ stopThumbnailUpdate();
+ else
+ startThumbnailUpdate();
+}
+
+/*
+ * Append new items to thumbnail generating job.
+ */
+void SQ_FileThumbView::addItemsToJob(const KFileItemList &items, bool append)
+{
+ newItemsAppend = append;
+
+ KFileItemListIterator it(items);
+ KFileItem *fi;
+
+ while((fi = it.current()))
+ {
+ newItems.append(fi);
+ ++it;
+ }
+
+ // don't confuse user with multiple updates
+ timerAdd->start(500, true);
+}
+
+void SQ_FileThumbView::slotDelayedAddItems()
+{
+ KFileItemList _newItems = newItems;
+ newItems.clear();
+
+ if(m_lazy)
+ {
+ KFileItemList visItems = itemsToUpdate();
+ KFileItemListIterator it(_newItems);
+ KFileItem *fi;
+
+ while((fi = it.current()))
+ {
+ if(visItems.findRef(fi) == -1)
+ _newItems.removeRef(fi); // also does ++it
+ else
+ ++it;
+ }
+ }
+
+ // job is not running
+ if(thumbJob.isNull())
+ doStartThumbnailUpdate(_newItems);
+ // add new items to running job
+ else
+ {
+ m_progressBox->addSteps(_newItems.count());
+
+ if(newItemsAppend)
+ thumbJob->appendItems(_newItems);
+ else
+ thumbJob->prependItems(_newItems);
+ }
+}
+
+/*
+ * Clear current view and insert "..".
+ */
+void SQ_FileThumbView::clearView()
+{
+ // stop job
+ stopThumbnailUpdate();
+ slotRemoveToolTip();
+
+ pixelSize = SQ_ThumbnailSize::instance()->extended() ?
+ SQ_ThumbnailSize::instance()->extendedSize() : QSize(SQ_ThumbnailSize::instance()->pixelSize()+2,SQ_ThumbnailSize::instance()->pixelSize()+2);
+
+ // clear
+ KFileIconView::clearView();
+
+ // insert ".."
+ insertCdUpItem(SQ_WidgetStack::instance()->url());
+}
+
+/*
+ * Is thumbnail job running ?
+ */
+bool SQ_FileThumbView::updateRunning() const
+{
+ return !thumbJob.isNull();
+}
+
+/*
+ * Insert ".." item.
+ */
+void SQ_FileThumbView::insertCdUpItem(const KURL &base)
+{
+ static const QString &dirup = KGlobal::staticQString("..");
+
+ KFileItem *fi = new KFileItem(base.upURL(), "inode/directory", S_IFDIR);
+
+ // insert new item
+ SQ_FileThumbViewItem *item = new SQ_FileThumbViewItem(this, dirup, directoryCache, fi);
+
+ // item ".." won't be selectable
+ item->setSelectable(false);
+
+ fi->setExtraData(this, item);
+}
+
+/*
+ * All files are listed. Do something important.
+ */
+void SQ_FileThumbView::listingCompleted()
+{
+ arrangeItemsInGrid();
+}
+
+void SQ_FileThumbView::rebuildPendingPixmap(bool dir)
+{
+ QPixmap pixmapDir;
+
+ if(dir)
+ pixmapDir = SQ_IconLoader::instance()->loadIcon("folder", KIcon::Desktop, 48);
+
+ QPixmap *p = dir ? &directoryCache : &pendingCache;
+ QPixmap *w = dir ? &pixmapDir : &pending;
+
+ p->resize(pixelSize.width(), pixelSize.height());
+
+ QPainter painter(p);
+ painter.setBrush(colorGroup().base());
+ painter.setPen(colorGroup().highlight());
+ painter.drawRect(0, 0, pixelSize.width(), pixelSize.height());
+ painter.drawPixmap((pixelSize.width() - w->width())/2, (pixelSize.height() - w->height())/2, *w);
+}
+
+void SQ_FileThumbView::rebuildCachedPixmaps()
+{
+ pixelSize = SQ_ThumbnailSize::instance()->extended() ?
+ SQ_ThumbnailSize::instance()->extendedSize() : QSize(SQ_ThumbnailSize::instance()->pixelSize()+2,SQ_ThumbnailSize::instance()->pixelSize()+2);
+
+ // rebuild "pending" thumbnail
+ rebuildPendingPixmap();
+
+ // rebuild directory pixmap
+ rebuildPendingPixmap(true);
+}
+
+void SQ_FileThumbView::itemRemoved(KFileItem *i)
+{
+ thumbJob->itemRemoved(i);
+}
+
+void SQ_FileThumbView::itemsRemoved(const KFileItemList &l)
+{
+ thumbJob->itemsRemoved(l);
+}
+
+void SQ_FileThumbView::showEvent(QShowEvent *e)
+{
+ KFileIconView::showEvent(e);
+
+ if(isPending)
+ {
+ isPending = false;
+ startThumbnailUpdate();
+ }
+}
+
+void SQ_FileThumbView::startDrag()
+{
+ SQ_Config::instance()->setGroup("Fileview");
+
+ if(SQ_Config::instance()->readBoolEntry("drag", true))
+ {
+ SQ_DragProvider::instance()->setParams(this, *KFileView::selectedItems(), SQ_DragProvider::Thumbnails);
+ SQ_DragProvider::instance()->start();
+ }
+ else
+ KFileIconView::startDrag();
+}
+
+void SQ_FileThumbView::setLazy(bool l, int delay)
+{
+ m_lazy = l;
+ lazyDelay = delay <= 0 ? 500 : delay;
+
+ // non-lazy mode requires to update all thumbnails
+ if(!m_lazy)
+ {
+ m_lazy = true;
+
+ stopThumbnailUpdate();
+ doStartThumbnailUpdate(itemsToUpdate(true));
+
+ // restore lazy mode
+ m_lazy = false;
+ }
+}
+
+void SQ_FileThumbView::resizeEvent(QResizeEvent *e)
+{
+ KFileIconView::resizeEvent(e);
+
+ if(isVisible())
+ timerScroll->start(lazyDelay, true);
+ else
+ waitForShowEvent();
+}
+
+#include "sq_filethumbview.moc"