You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ksquirrel/ksquirrel/sq_filethumbview.cpp

550 lines
14 KiB

/***************************************************************************
sq_fileiconview.cpp - description
-------------------
begin : Mon Mar 15 2004
copyright : (C) 2004 by Baryshev Dmitry
email : ksquirrel.iv@gmail.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 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <tqpainter.h>
#include <tqhbox.h>
#include <tqtoolbar.h>
#include <tqtoolbutton.h>
#include <tqlabel.h>
#include <tqtimer.h>
#include <tqapplication.h>
#include <kstandarddirs.h>
#include <kstringhandler.h>
#include <tdeglobalsettings.h>
#include <tdelocale.h>
#include <tdeapplication.h>
#include <tdeglobal.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(TQWidget *parent, const char *name) : SQ_FileIconViewBase(parent, name), isPending(false)
{
// create progress bar
m_progressBox = new SQ_ProgressBox(this);
timerScroll = new TQTimer(this);
connect(timerScroll, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotDelayedContentsMoving()));
timerAdd = new TQTimer(this);
connect(timerAdd, TQ_SIGNAL(timeout()), this, TQ_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(TQIconView::Adjust);
// load "pending" pixmaps
pending = SQ_IconLoader::instance()->loadIcon("clock", TDEIcon::Desktop, 32);
connect(this, TQ_SIGNAL(contentsMoving(int, int)), this, TQ_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
{
TQPixmap mimeall = i->pixmap(SQ_ThumbnailSize::smallest());
TQPixmap thumbnail(pixelSize.width(), pixelSize.height());
TQPainter 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;
TQPixmap newpix;
// Extended thumbnail also have mime icon and dimensions
if(SQ_ThumbnailSize::instance()->extended())
{
TQSize sz = pixelSize;//SQ_ThumbnailSize::instance()->extendedSize();
int W = sz.width(), H = sz.height();
// erase original pixmap
newpix.resize(W, H);
TQPainter 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);
TQFont 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, TQString::fromLatin1("%1x%2").arg(t.w).arg(t.h));
painter.drawText(4, W+rest/2+1, 100, 12, 0, TDEIO::convertSize(fileItem->size()));
painter.end();
}
else
{
newpix.resize(pixelSize.width(), pixelSize.height());
TQPainter 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;
TQRect rect(contentsX(), contentsY(), viewport()->width(), viewport()->height());
TQIconViewItem *first = fromAll ? firstItem() : findFirstVisibleItem(rect);
TQIconViewItem *last = fromAll ? lastItem() : findLastVisibleItem(rect);
if(first && last)
{
SQ_FileThumbViewItem *tfi;
TQIconViewItem *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(TQIconViewItem *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, TQ_SIGNAL(thumbnailLoaded(const KFileItem*, const SQ_Thumbnail &)),
this, TQ_SLOT(setThumbnailPixmap(const KFileItem*, const SQ_Thumbnail&)));
connect(thumbJob, TQ_SIGNAL(done()), SQ_WidgetStack::instance(), TQ_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() : TQSize(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 TQString &dirup = TDEGlobal::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)
{
TQPixmap pixmapDir;
if(dir)
pixmapDir = SQ_IconLoader::instance()->loadIcon("folder", TDEIcon::Desktop, 48);
TQPixmap *p = dir ? &directoryCache : &pendingCache;
TQPixmap *w = dir ? &pixmapDir : &pending;
p->resize(pixelSize.width(), pixelSize.height());
TQPainter 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() : TQSize(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(TQShowEvent *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(TQResizeEvent *e)
{
KFileIconView::resizeEvent(e);
if(isVisible())
timerScroll->start(lazyDelay, true);
else
waitForShowEvent();
}
#include "sq_filethumbview.moc"