/*************************************************************************** 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 #include #include #include #include #include #include #include #include #include #include #include #include #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(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(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"