diff options
Diffstat (limited to 'ksquirrel/sq_filethumbview.cpp')
-rw-r--r-- | ksquirrel/sq_filethumbview.cpp | 549 |
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 + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * 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" |