#include #include "browser.h" #include "menuid.h" #include "rightclick.h" #include "uimanager.h" #include "imageheaders.h" //#include "mplayer.h" #include "fileop.h" #include "ifapp.h" #include "imageutils.h" #include "imagedata.h" #include "../misc/exif.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define INVALID_POS QCOORD_MAX extern GC rubberBandGC; extern GC viewFillGC; QRect oldSelectRect; inline bool intersects(int x, int y, int w, int h, const QRect &r) { return(QMAX(x, r.x()) <= QMIN(x+w-1, r.right()) && QMAX(y, r.y()) <= QMIN(y+h-1, r.bottom())); } inline bool contains(int x, int y, int w, int h, int px, int py) { return(px >= x && px <= x+w-1 && py >= y && py <= y+h-1); } PixieBrowser::PixieBrowser(UIManager *manager, QWidget *parent, const char *name) : QWidget(parent, name, WResizeNoErase | WRepaintNoErase) { mgr = manager; itemList = NULL; itemCount = 0; curIdx = -1; curPreviewingIdx = -1; inSelection = selectStarted = false; dndStarted = dndSent = false; stopProcessing = false; inGenerateThumbs = false; inDirLoad = false; invalidDir = false; hasNameFilter = false; hasInitialLoad = false; currentSort = 0; oldestFile = newestFile = 0; kioCurrentThumb = kioThumbCount = 0; thumbJob = NULL; imagesOnTop = false; sortCatagories = false; arrayCount = 0; visibleRects = NULL; iconDict.setAutoDelete(true); catDict.setAutoDelete(true); QHBoxLayout *layout = new QHBoxLayout(this); setBackgroundMode(QWidget::NoBackground); view = new QWidget(this, "PixieViewport", WResizeNoErase | WRepaintNoErase); view->setBackgroundMode(QWidget::NoBackground); view->installEventFilter(this); view->setMouseTracking(true); view->setAcceptDrops(true); layout->addWidget(view, 1); sb = new QScrollBar(Qt::Vertical, this); connect(sb, SIGNAL(valueChanged(int)), this, SLOT(slotScrollBarChanged(int))); layout->addWidget(sb); fm = new QFontMetrics(view->fontMetrics()); textHeight = fm->lineSpacing()*2; selectBrush.setColor(Qt::blue); selectBrush.setStyle(Dense4Pattern); tmpIconPix = new QPixmap; curFramePix = NULL; curGraphicsPix = NULL; curTextPix = NULL; curSelTextPix = NULL; curPreviewingPix = NULL; dirWatch = new KDirWatch; connect(dirWatch, SIGNAL(dirty(const QString &)), this, SLOT(slotDirChanged(const QString &))); resize(600, 450); view->setFocusPolicy(StrongFocus); tips = new BrowserTip(view, NULL); } PixieBrowser::~PixieBrowser() { stopProcessing = true; if(thumbJob) thumbJob->kill(); clear(); if(visibleRects) free(visibleRects); delete fm; delete dirWatch; delete tmpIconPix; if(curFramePix) delete curFramePix; if(curGraphicsPix) delete curGraphicsPix; if(curTextPix) delete curTextPix; if(curSelTextPix) delete curSelTextPix; if(curPreviewingPix) delete curPreviewingPix; delete tips; } void PixieBrowser::clear() { if(!itemList || !itemCount) return; int i; clearSelection(false); for(i=0; i < itemCount; ++i){ if(itemList[i].filename) free(itemList[i].filename); if(itemList[i].formattedText) free(itemList[i].formattedText); if(itemList[i].tooltip) free(itemList[i].tooltip); if(itemList[i].thumbnailData) free(itemList[i].thumbnailData); if(itemList[i].mimetype) free(itemList[i].mimetype); if(itemList[i].status) free(itemList[i].status); if(itemList[i].pixmap) delete itemList[i].pixmap; } free(itemList); itemList = NULL; itemCount = 0; curIdx = -1; firstVisibleIdx = -1; visibleRectCount = 0; if(visibleRects){ free(visibleRects); visibleRects = NULL; } inSelection = false; selectStarted = false; dndStarted = false; dndSent = false; sb->setValue(0); sb->setEnabled(false); view->repaint(false); } void PixieBrowser::selectAll() { if(!itemList || !itemCount) return; selectList.clear(); int i; for(i=0; i < itemCount; ++i){ itemList[i].selected = true; selectList.append(i); } view->repaint(false); } void PixieBrowser::clearSelection(bool redraw) { if(!itemList || !itemCount) return; // TODO - test if this gets last item! QValueList::iterator it; bool redrawNeeded = false; for(it = selectList.begin(); it != selectList.end(); ++it){ if((*it) < itemCount){ itemList[(*it)].selected = false; redrawNeeded = true; } } selectList.clear(); if(redrawNeeded && redraw) view->repaint(false); } bool PixieBrowser::allocateArray(int c) { clear(); itemList = (Thumbnail *)malloc(sizeof(Thumbnail)*c); if(!itemList){ itemCount = 0; return(false); } int i; for(i=0; i < c; ++i){ itemList[i].filename = NULL; itemList[i].formattedText = NULL; itemList[i].thumbnailData = NULL; itemList[i].tooltip = NULL; itemList[i].mimetype = NULL; itemList[i].status = NULL; itemList[i].pixmap = NULL; itemList[i].thumbnailed = itemList[i].isDir = itemList[i].selected = false; itemList[i].textDirty = true; itemList[i].isImage = false; itemList[i].imageHasThumb = false; itemList[i].extensionChecked = false; itemList[i].mimetypeChecked = false; } itemCount = c; return(true); } QValueList* PixieBrowser::selection() { if(itemList &&itemCount) sortSelectionByView(); return(&selectList); } bool PixieBrowser::selectionStringList(QStringList &list) { list.clear(); if(selectList.count() == 0) return(false); sortSelectionByView(); QValueList::iterator it; for(it = selectList.begin(); it != selectList.end(); ++it){ if((*it) < itemCount) list.append(absFileStr + "/" + itemList[(*it)].filename); } return(true); } bool PixieBrowser::selectionHasImages() { if(selectList.count() == 0) return(false); QValueList::iterator it; int idx; for(it = selectList.begin(); it != selectList.end(); ++it){ idx = *it; if(isImage(&itemList[idx], absFileStr + "/" + itemList[idx].filename, false)) return(true); } return(false); } bool PixieBrowser::selectionHasFolders() { if(selectList.count() == 0) return(false); QValueList::iterator it; int idx; for(it = selectList.begin(); it != selectList.end(); ++it){ idx = *it; if(S_ISDIR(itemList[idx].status->st_mode)) return(true); } return(false); } void PixieBrowser::sortSelectionByView() { if(selectList.count() == 0) return; qHeapSort(selectList); } int PixieBrowser::count() { return(itemCount); } int PixieBrowser::currentIndex() { return(curIdx); } Thumbnail* PixieBrowser::currentItem() { if(itemCount && curIdx != -1) return(&itemList[curIdx]); else return(NULL); } bool PixieBrowser::setCurrentItem(int idx) { if(itemCount && idx < itemCount){ clearSelection(true); curIdx = idx; return(true); } return(false); } Thumbnail* PixieBrowser::allItems() { return(itemList); } int PixieBrowser::findItem(const char *filename) { if(!itemCount) return(-1); int i; for(i=0; i < itemCount; ++i){ if(qstrcmp(itemList[i].filename, filename) == 0) return(i); } return(-1); } bool PixieBrowser::eventFilter(QObject *obj, QEvent *ev) { if(obj == view){ if(ev->type() == QEvent::Paint){ viewportPaintEvent((QPaintEvent *)ev); return(true); } else if(ev->type() == 6){ // for some reason QEvent::KeyPress gives compile error. Conflict? viewportKeyEvent((QKeyEvent *)ev); } else if(ev->type() == QEvent::MouseButtonPress){ viewportMousePressEvent((QMouseEvent *)ev); } else if(ev->type() == QEvent::MouseButtonRelease){ viewportMouseReleaseEvent((QMouseEvent *)ev); } else if(ev->type() == QEvent::MouseButtonDblClick){ viewportMouseDoubleClickEvent((QMouseEvent *)ev); } else if(ev->type() == QEvent::MouseMove){ viewportMouseMoveEvent((QMouseEvent *)ev); } else if(ev->type() == QEvent::Resize){ viewportResizeEvent((QResizeEvent *)ev); } else if(ev->type() == QEvent::Drop){ viewportDropEvent((QDropEvent *)ev); } else if(ev->type() == QEvent::DragMove){ viewportDragMoveEvent((QDragMoveEvent *)ev); } else if(ev->type() == QEvent::Wheel){ viewportWheelEvent((QWheelEvent *)ev); } } return(false); } void PixieBrowser::viewportWheelEvent(QWheelEvent *ev) { ev->accept(); if(ev->orientation() == Vertical) QApplication::sendEvent(sb, ev); } void PixieBrowser::viewportKeyEvent(QKeyEvent *ev) { if(!itemCount){ qWarning("Got keypress with no items!"); ev->ignore(); return; } if(ev->key() == Qt::Key_Down || ev->key() == Qt::Key_Right){ int idx; if(curIdx < firstVisibleIdx || curIdx > firstVisibleIdx + visibleRectCount) curIdx = firstVisibleIdx; if(ev->key() == Qt::Key_Down) idx = curIdx + columns; else idx = ++curIdx;; if(idx >= itemCount){ qWarning("Already at bottom of view"); qApp->beep(); } else{ int itemY = (idx/columns)*totalItemHeight; curIdx = idx; if(itemY+totalItemHeight <= sb->value()+view->height()) view->repaint(false); else{ qWarning("Scrolling down"); sb->setValue(sb->value()+(itemY-sb->value())); } } } else if(ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Left){ int idx; if(curIdx < firstVisibleIdx || curIdx > firstVisibleIdx + visibleRectCount) curIdx = firstVisibleIdx; if(ev->key() == Qt::Key_Up) idx = curIdx - columns; else idx = --curIdx; if(idx < 0){ qWarning("Already at top of view"); qApp->beep(); } else{ int itemY = (idx/columns)*totalItemHeight; curIdx = idx; if(itemY < sb->value()) sb->setValue(itemY); else view->repaint(false); } } else if(ev->key() == Qt::Key_PageUp){ // FIXME: Make entire item visible if(sb->value() - sb->pageStep() >= 0) sb->setValue(sb->value()-sb->pageStep()); else sb->setValue(0); curIdx = firstVisibleIdx; view->repaint(false); } else if(ev->key() == Qt::Key_PageDown){ if(sb->value() + sb->pageStep() <= sb->maxValue()) sb->setValue(sb->value()+sb->pageStep()); else sb->setValue(sb->maxValue()); curIdx = firstVisibleIdx + visibleRectCount-1; if(curIdx >= itemCount) curIdx = itemCount-1; view->repaint(false); } else if(ev->key() == Qt::Key_Home){ curIdx = 0; if(sb->value() != 0) sb->setValue(0); else view->repaint(false); } else if(ev->key() == Qt::Key_End){ curIdx = itemCount-1; if(sb->value() != sb->maxValue()) sb->setValue(sb->maxValue()); else view->repaint(false); } else if(ev->key() == Qt::Key_Space){ if(curIdx >= itemCount) return; if(!isImage(&itemList[curIdx], absFileStr + "/" + itemList[curIdx].filename, false)) qWarning("Space clicked on non-image file!"); else{ clearSelection(false); itemList[curIdx].selected = true; selectList.append(curIdx); view->repaint(true); emit clicked(&itemList[curIdx]); } } else if(ev->key() == Qt::Key_Return || ev->key() == Qt::Key_Enter){ if(curIdx >= itemCount) return; clearSelection(false); itemList[curIdx].selected = true; selectList.append(curIdx); view->repaint(true); emit doubleClicked(&itemList[curIdx]); } ev->ignore(); } void PixieBrowser::viewportDragMoveEvent(QDragMoveEvent *ev) { QStringList fileList; if(!QUriDrag::decodeLocalFiles(ev, fileList)){ qWarning("Pixie: Can't decode drop."); return; } if(!fileList.count()) return; QStringList::Iterator it; QFileInfo fi; bool valid = true; int idx = itemAt(ev->pos().x(), ev->pos().y()); if(idx != -1 && !itemList[idx].isDir){ ev->ignore(itemRect(idx)); valid = false; } else{ for(it = fileList.begin(); it != fileList.end(); ++it){ fi.setFile(*it); if(idx == -1){ if(fi.dirPath(true) == absFileStr){ ev->ignore(); valid = false; } } else{ if(qstrcmp(QFile::encodeName(fi.fileName()), itemList[idx].filename) == 0){ ev->ignore(itemRect(idx)); valid = false; } } } } if(valid){ if(idx == -1) ev->accept(); else ev->accept(itemRect(idx)); } } void PixieBrowser::viewportDropEvent(QDropEvent *ev) { QStringList fileList; if(!QUriDrag::decodeLocalFiles(ev, fileList)){ qWarning("Pixie: Can't decode drop."); return; } if(!fileList.count()) return; // check if valid - shouldn't have to since same check is in dragmove QStringList::Iterator it; QFileInfo fi; bool valid = true; int idx = itemAt(ev->pos().x(), ev->pos().y()); if(idx != -1 && !itemList[idx].isDir) valid = false; else{ for(it = fileList.begin(); it != fileList.end(); ++it){ fi.setFile(*it); if(idx == -1){ if(fi.dirPath(true) == absFileStr) valid = false; } else{ if(qstrcmp(QFile::encodeName(fi.fileName()), itemList[idx].filename) == 0) valid = false; } } } if(!valid) return; int op; QPopupMenu opPopup; opPopup.insertItem(i18n("&Copy Here"), 1); opPopup.insertItem(i18n("&Move Here"), 2); opPopup.insertItem(i18n("&Link Here"), 3); op = opPopup.exec(view->mapToGlobal(ev->pos())); switch(op){ case 1: ev->setAction(QDropEvent::Copy); break; case 2: ev->setAction(QDropEvent::Move); break; case 3: ev->setAction(QDropEvent::Link); break; default: return; } QString destStr(idx == -1 ? absFileStr : absFileStr+ "/" + itemList[idx].filename); KIFFileTransfer::transferFiles(fileList, destStr, ev->action()); } void PixieBrowser::viewportResizeEvent(QResizeEvent *ev) { recalcColumns(ev->size().width(), ev->size().height()); QWidget::resizeEvent(ev); } void PixieBrowser::recalcRects() { // I originally managed visible rects in a QValueList but decided a // array would be faster than iterating over a list all the time. if(itemCount == 0){ firstVisibleIdx = -1; visibleRectCount = 0; if(visibleRects){ free(visibleRects); visibleRects = NULL; } return; } int start = sb->value()/totalItemHeight; int offset = sb->value()-(start*totalItemHeight); int idx = start*columns; int tmp, x, y, i, n=0; tmp = ((int)ceil(((float)(view->height() + offset))/totalItemHeight)) * columns; if(idx + tmp >= itemCount) tmp = itemCount-idx; firstVisibleIdx = idx; if(!visibleRects) visibleRects = (PixieRect *)malloc(sizeof(PixieRect)*tmp); else if(tmp > visibleRectCount || visibleRectCount-tmp > 64){ // to avoid memory fragmentation only reallocate if it's worth it free(visibleRects); visibleRects = (PixieRect *)malloc(sizeof(PixieRect)*tmp); } visibleRectCount = tmp; for(y=0-offset; y < view->height() && idx < itemCount; y+= totalItemHeight){ for(x=i=0; x < view->width() && idx < itemCount && i < columns; x+=totalItemWidth, ++i){ visibleRects[n].x = x+4; visibleRects[n].y = y+4; visibleRects[n].w = iSize+2; visibleRects[n].h = iSize+2+textHeight; ++n; ++idx; } } } bool PixieBrowser::viewToIconRect(const QRect &viewRect, QRect &destRect) { destRect = viewRect; if(!visibleRects) return(false); int i; for(i=0; i < visibleRectCount; ++i){ if(intersects(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h, viewRect)) destRect = destRect.unite(QRect(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h)); } return(destRect.isValid()); } QRect PixieBrowser::itemRect(int item) { QRect r; if(!visibleRects) return(r); // invalid rect int i, idx = firstVisibleIdx; for(i=0; i < visibleRectCount; ++i){ if(idx == item) return(QRect(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h)); ++idx; } return(r); } int PixieBrowser::itemAt(int x, int y) { if(!visibleRects) return(-1); int i, idx = firstVisibleIdx; for(i=0; i < visibleRectCount; ++i){ if(contains(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h, x, y)) return(idx); ++idx; } return(-1); } bool PixieBrowser::isItemVisible(int i) { return(visibleRects && i >= firstVisibleIdx && i <= firstVisibleIdx+visibleRectCount); } void PixieBrowser::viewportPaintEvent(QPaintEvent *ev) { QPainter p; if(!hasInitialLoad){ p.begin(view); p.fillRect(ev->rect(), Qt::white); p.end(); return; } if(inDirLoad){ p.begin(view); QFont fnt(p.font()); p.setPen(Qt::black); fnt.setBold(true); p.setFont(fnt); p.fillRect(ev->rect(), Qt::white); if(invalidDir) p.drawText(20, 20, i18n("Invalid folder!")); else if(inDirLoad) p.drawText(20, 20, i18n("Loading folder...")); p.end(); return; } else if(!count()){ p.begin(view); QFont fnt(p.font()); fnt.setBold(true); p.setFont(fnt); p.fillRect(ev->rect(), Qt::white); p.setPen(Qt::black); p.drawText(20, 20, i18n("Empty folder!")); p.end(); return; } int i; int idx = firstVisibleIdx; QRegion bgRegion(ev->rect()); // do background fill before the icons - uses an extra // loop but looks much nicer if the thumbs take a sec to load for(i=0; i < visibleRectCount; ++i){ if(intersects(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h, ev->rect())) bgRegion -= QRect(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h); } QMemArrayrects = bgRegion.rects(); XRectangle *xRects = (XRectangle *)malloc(sizeof(XRectangle)* rects.size()); for(i=0; i < (int)rects.size(); ++i){ xRects[i].x = rects[i].x(); xRects[i].y = rects[i].y(); xRects[i].width = rects[i].width(); xRects[i].height = rects[i].height(); } // Use Xlib because QPainter doesn't allow you to specify multiple // rects in fillRect(). Xlib lets you do it all in one call :) XFillRectangles(x11Display(), view->winId(), viewFillGC, xRects, rects.size()); free(xRects); // now do the actual painting if(tmpIconPix->width() != iSize+2 || tmpIconPix->height() != iSize+2+textHeight) tmpIconPix->resize(iSize+2, iSize+2+textHeight); p.begin(tmpIconPix); for(i=0; i < visibleRectCount; ++i){ if(intersects(visibleRects[i].x, visibleRects[i].y, visibleRects[i].w, visibleRects[i].h, ev->rect())){ paintItem(&p, idx, visibleRects[i].x, visibleRects[i].y); bitBlt(view, visibleRects[i].x, visibleRects[i].y, tmpIconPix, 0, 0, iSize+2, iSize+2+textHeight, Qt::CopyROP, true); } ++idx; } p.end(); } void PixieBrowser::paintItem(QPainter *p, int idx, int x, int y) { Thumbnail *i = itemList+idx; bool isBeingPreviewed = /*inGenerateThumbs && curPreviewingIdx == idx*/ 0; if(!i->thumbnailed) updateThumbnail(idx); if(i->isImage && !i->imageHasThumb && !isBeingPreviewed) bitBlt(tmpIconPix, 0, 0, curGraphicsPix, 0, 0, iSize+2, iSize+2, Qt::CopyROP, true); else bitBlt(tmpIconPix, 0, 0, curFramePix, 0, 0, iSize+2, iSize+2, Qt::CopyROP, true); if(isBeingPreviewed){ bitBlt(tmpIconPix, 1, 1, curPreviewingPix, 0, 0, iSize, iSize, Qt::CopyROP, false); } else if(i->pixmap && (!i->isImage || i->imageHasThumb)){ int dx = ((iSize+2)-i->pixmap->width())/2; int dy = ((iSize+2)-i->pixmap->height())/2; bitBlt(tmpIconPix, dx, dy, i->pixmap, 0, 0, i->pixmap->width(), i->pixmap->height(), Qt::CopyROP, false); } bool selected = i->selected; if(inSelection && selectStarted){ QRect selRect(selectStartPos, currentSelPos); selRect = selRect.normalize(); QRect itemRect(x, y+sb->value(), iSize+2, iSize+2+textHeight); if(selRect.intersects(itemRect)) selected = true; else selected = i->selected; } // text area box QPixmap *pix = selected ? curSelTextPix : curTextPix; bitBlt(tmpIconPix, 0, iSize+2, pix, 0, 0, iSize+2, textHeight, Qt::CopyROP, true); if(i->textDirty) calcTextWrapping(i); if(selected) p->fillRect(0, 0, iSize+2, iSize, selectBrush); if(idx == curIdx){ p->setPen(QColor(0, 0, 64)); p->drawRect(0, 0, tmpIconPix->width(), tmpIconPix->height()); p->setPen(QPen(QColor(200, 200, 255), 1, DotLine)); p->drawRect(0, 0, tmpIconPix->width(), tmpIconPix->height()); } p->setPen(Qt::black); p->drawText(0, iSize+2, iSize+2, textHeight, Qt::AlignHCenter | AlignTop, i->formattedText ? i->formattedText : i->filename); } bool PixieBrowser::paintThumbnail(int i, QPainter *painter) { if(!isItemVisible(i)) return(false); int idx = i-firstVisibleIdx; if(painter) paintItem(painter, i, visibleRects[idx].x, visibleRects[idx].y); else{ if(tmpIconPix->width() != iSize+2 || tmpIconPix->height() != iSize+2+textHeight) tmpIconPix->resize(iSize+2, iSize+2+textHeight); QPainter p; p.begin(tmpIconPix); paintItem(&p, i, visibleRects[idx].x, visibleRects[idx].y); p.end(); } bitBlt(view, visibleRects[idx].x, visibleRects[idx].y, tmpIconPix, 0, 0, iSize+2, iSize+2+textHeight, Qt::CopyROP, true); return(true); } void PixieBrowser::resetFrames() { if(curFramePix && curFramePix->width() == iSize + 2 && curGraphicsPix && curGraphicsPix->width() == iSize + 2) return; qWarning("Creating icon frames"); iconDict.clear(); curFrameImage = uic_findImage("imagetile.png").smoothScale(iSize+2, iSize+2); curGraphicsImage = uic_findImage("imageicon.png").smoothScale(iSize+2, iSize+2); if(!curFramePix) curFramePix = new QPixmap(curFrameImage); else curFramePix->convertFromImage(curFrameImage); if(!curGraphicsPix) curGraphicsPix = new QPixmap(curGraphicsImage); else curGraphicsPix->convertFromImage(curGraphicsImage); if(!curTextPix) curTextPix = new QPixmap; if(!curSelTextPix) curSelTextPix = new QPixmap; curTextPix->convertFromImage(uic_findImage("textbox.png"). smoothScale(iSize+2, textHeight)); curSelTextPix->convertFromImage(uic_findImage("textbox-select.png"). smoothScale(iSize+2, textHeight)); int tw = fm->width(i18n("Previewing..."))+4; if(tw < iSize) tw = iSize; /* if(curPreviewingPix) curPreviewingPix->resize(tw, tw); else curPreviewingPix = new QPixmap(tw, tw); QPainter p(curPreviewingPix); p.fillRect(0, 0, tw, tw, QColor(191, 227, 255)); p.setPen(QColor(0, 95, 168)); p.drawRect(0, 0, tw, tw); p.setPen(Qt::black); p.drawText(2, 2, tw-4, tw-4, Qt::AlignCenter, i18n("Previewing...")); p.end(); if(tw > iSize){ QImage img(curPreviewingPix->convertToImage()); img = img.smoothScale(iSize, iSize); curPreviewingPix->convertFromImage(img); }*/ } void PixieBrowser::viewportMousePressEvent(QMouseEvent *ev) { if(!itemCount) return; int idx = itemAt(ev->x(), ev->y()); bool ctrlDown = ev->state() & ControlButton; bool shiftDown = ev->state() & ShiftButton; bool hasOldSelection = selectList.count() != 0; if(ev->button() == LeftButton){ // handle selection if(idx != -1){ if(shiftDown){ // if shift is down select all items between this one and // the previous selected item. First try searching forward // and only if no selection is found search backward. int i; bool hasSelection = false; if(!itemList[idx].selected){ itemList[idx].selected = true; selectList.append(idx); } // first search forward for(i=idx+1; i < itemCount; ++i){ if(itemList[i].selected){ hasSelection = true; break; } } if(hasSelection){ for(i=idx+1; i < itemCount && !itemList[i].selected; ++i){ itemList[i].selected = true; selectList.append(i); } } else{ for(i=idx-1; i >= 0; --i){ if(itemList[i].selected){ hasSelection = true; break; } } if(hasSelection){ for(i=idx-1; i >= 0 && !itemList[i].selected; --i){ itemList[i].selected = true; selectList.append(i); } } else qWarning("Shift key down but no previous selection!"); } view->repaint(false); return; } else if(itemList[idx].selected){ // if we are on a button and it is already selected start a // potential dnd, else add it to selection and emit clicked if(!ctrlDown){ dndStarted = true; dndSent = false; selectStartPos = QPoint(ev->x(), ev->y()+sb->value()); } } else{ if(hasOldSelection && !ctrlDown) clearSelection(false); dndStarted = false; itemList[idx].selected = true; selectList.append(idx); } curIdx = idx; emit clicked(&itemList[idx]); inSelection = false; selectStarted = false; // TODO - only repaint full view if hasOldSelection && !ctrlbtn view->repaint(false); } else{ // setup rubberbanding if(hasOldSelection && !ctrlDown){ clearSelection(false); view->repaint(false); } selectStartPos = QPoint(ev->x(), ev->y()+sb->value()); currentSelPos = QPoint(INVALID_POS, INVALID_POS); inSelection = true; selectStarted = false; dndStarted = false; oldSelectRect = QRect(); } } else if(ev->button() == RightButton){ //emit rightButtonClicked(idx == -1 ? NULL : &itemList[idx], // ev->globalPos()); if(hasOldSelection && !ctrlDown && !itemList[idx].selected) clearSelection(false); if(idx != -1){ if(!itemList[idx].selected){ itemList[idx].selected = true; selectList.append(idx); curIdx = idx; } view->repaint(false); /* iconRightClickMenu(absFileStr, mgr, this, &itemList[idx], ev->globalPos());*/ EditMenu *mnu = new EditMenu(mgr); mnu->execItem(&itemList[idx], ev->globalPos()); delete mnu; } else viewRightClickMenu(absFileStr, mgr, this, ev->globalPos()); } } void PixieBrowser::viewportMouseReleaseEvent(QMouseEvent *ev) { if(!itemCount) return; if(dndStarted){ inSelection = selectStarted = false; dndStarted = dndSent = false; } else if(inSelection){ inSelection = false; disconnect(&scrollOutsideViewTimer, SIGNAL(timeout()), this, SLOT(slotScrollOutsideView())); scrollOutsideViewTimer.stop(); if(selectStarted){ selectStarted = false; QPoint pos(ev->x(), ev->y()); if(pos.x() < 0) pos.setX(0); if(pos.x() > view->width()) pos.setX(view->width()); if(pos.y() < 0) pos.setY(0); if(pos.y() > view->height()) pos.setY(view->height()); pos.setY(pos.y()+sb->value()); QRect selRect(selectStartPos, pos); selRect = selRect.normalize(); // Pain in the butt because we need to account for spacing // between items :P int start_row = (selRect.y()/totalItemHeight)*totalItemHeight; int rows = (int)ceil(((float)selRect.height())/totalItemHeight); int curr_row; int x, y, idx, i; QRect r; idx = (selRect.y()/totalItemHeight)*columns; for(y=start_row, curr_row=0; curr_row <= rows; y+=totalItemHeight, ++curr_row){ for(x=i=0; x < view->width() && idx < itemCount && i < columns; x+=totalItemWidth, ++i, ++idx){ r.setRect(x+4, y+4, iSize+2, iSize+2+textHeight); if(r.intersects(selRect)){ itemList[idx].selected = true; if(selectList.findIndex(idx) == -1) selectList.append(idx); } } } } if(selectList.count() != 0) sortSelectionByView(); view->repaint(false); } } void PixieBrowser::viewportMouseDoubleClickEvent(QMouseEvent *ev) { if(!itemCount) return; inSelection = selectStarted = false; dndStarted = dndSent = false; int idx = itemAt(ev->x(), ev->y()); if(idx != -1){ curIdx = idx; emit doubleClicked(&itemList[idx]); } } void PixieBrowser::viewportMouseMoveEvent(QMouseEvent *ev) { if(!itemCount) return; if(dndStarted){ if(!dndSent){ if((selectStartPos-QPoint(ev->pos().x(), ev->pos().y()-sb->value())). manhattanLength() > QApplication::startDragDistance()){ dndSent = true; QStrList uriList; QValueList::iterator it; sortSelectionByView(); int idx; Thumbnail *item = 0; for(it = selectList.begin(); it != selectList.end(); ++it){ idx = (*it); if(idx < itemCount){ item = &itemList[idx]; uriList.append(QUriDrag::localFileToUri(currentDir+"/"+ itemList[idx].filename)); } } QUriDrag *uri = new QUriDrag(uriList, this); if(uriList.count() == 1 && item->pixmap){ if(item->isImage) uri->setPixmap(*item->pixmap); else{ // we can't just use the mimetype pixmap cached in // the thumbnail because it's alphablended w/ the // tile :P KURL url(absFileStr+"/"+item->filename); uri->setPixmap(KMimeType::pixmapForURL(url, item->status->st_mode, KIcon::Desktop, 64)); } } else uri->setPixmap(KGlobal::iconLoader()-> loadIcon("kmultiple", KIcon::NoGroup, KIcon::SizeLarge)); uri->drag(); } } } else if(inSelection){ if(!selectStarted){ if((selectStartPos-QPoint(ev->pos().x(), ev->pos().y()-sb->value())). manhattanLength() > QApplication::startDragDistance()){ selectStarted = true; } } if(selectStarted){ QPoint pos(ev->x(), ev->y()); if(ev->x() > view->width()) // only scrolls vertically pos.setX(view->width()); else if(ev->x() < 0) pos.setX(0); if(ev->y() > view->height()){ if(!scrollOutsideViewTimer.isActive()) slotScrollOutsideView(); return; } else if(ev->y() < 0){ if(sb->value() == 0) pos.setY(0); else{ if(!scrollOutsideViewTimer.isActive()) slotScrollOutsideView(); } return; } disconnect(&scrollOutsideViewTimer, SIGNAL(timeout()), this, SLOT(slotScrollOutsideView())); scrollOutsideViewTimer.stop(); Display *dpy = QPaintDevice::x11Display(); QRect r1, r2; if(currentSelPos.x() != INVALID_POS){ r1.setCoords(selectStartPos.x(), selectStartPos.y()-sb->value(), currentSelPos.x(), currentSelPos.y()-sb->value()); r1 = r1.normalize(); // we shouldn't have to do this, must have a logic error... XDrawRectangle(dpy, view->winId(), rubberBandGC, r1.x(), r1.y(), r1.width(), r1.height()); } r2.setCoords(selectStartPos.x(), selectStartPos.y()-sb->value(), pos.x(), pos.y()); r2 = r2.normalize(); currentSelPos.setX(pos.x()); currentSelPos.setY(pos.y()+sb->value()); QRect destRect; if(r1.isValid()){ r1 = r1.unite(r2); r1 = r1.intersect(view->rect()); viewToIconRect(r1, destRect); QPaintEvent pe(destRect, false); viewportPaintEvent(&pe); } else{ r2 = r2.intersect(view->rect()); viewToIconRect(r2, destRect); QPaintEvent pe(destRect, false); viewportPaintEvent(&pe); } XDrawRectangle(dpy, view->winId(), rubberBandGC, r2.x(), r2.y(), r2.width(), r2.height()); } } } void PixieBrowser::slotScrollOutsideView() { disconnect(&scrollOutsideViewTimer, SIGNAL(timeout()), this, SLOT(slotScrollOutsideView())); scrollOutsideViewTimer.stop(); Window root, child; int root_x, root_y, win_x, win_y; unsigned int mousestate; // Mouse pointer may have been released while events were blocked... XQueryPointer(qt_xdisplay(), qt_xrootwin(), &root, &child, &root_x, &root_y, &win_x, &win_y, &mousestate); if(!(mousestate & Button1Mask)) return; int step; Display *dpy = QPaintDevice::x11Display(); QPoint pos(QCursor::pos()); pos = view->mapFromGlobal(pos); if(pos.y() < 0 && sb->value() != 0){ step = sb->value()-sb->lineStep(); if(step < 0) step = 0; sb->setValue(step); pos.setY(0); } else if(pos.y() > view->height()){ step = sb->value()+sb->lineStep(); if(step > sb->maxValue()) step = sb->maxValue(); sb->setValue(step); pos.setY(view->height()); } else view->repaint(false); if(pos.x() < 0) pos.setX(0); else if(pos.x() > view->width()) pos.setX(view->width()); QRect r; r.setCoords(selectStartPos.x(), selectStartPos.y()-sb->value(), pos.x(), pos.y()); r = r.normalize(); XDrawRectangle(dpy, view->winId(), rubberBandGC, r.x(), r.y(), r.width(), r.height()); currentSelPos.setX(pos.x()); currentSelPos.setY(pos.y()+sb->value()); connect(&scrollOutsideViewTimer, SIGNAL(timeout()), this, SLOT(slotScrollOutsideView())); scrollOutsideViewTimer.start(100); } void PixieBrowser::slotScrollBarChanged(int) { recalcRects(); view->repaint(false); } void PixieBrowser::slotDirChanged(const QString &path) { qWarning("In slotDirChanged"); emit updateMe(); emit dirChanged(path); } bool PixieBrowser::updateThumbnail(int idx) { Thumbnail *i = itemList+idx; if(i->thumbnailed) return(true); i->thumbnailed = true; if(i->textDirty) calcTextWrapping(i); if(i->pixmap) return(true); resetFrames(); QFileInfo fi(currentDir+"/"+i->filename); bool hasPixieThumb = false; bool hasKonqThumb = false; if(!fi.isDir()){ hasPixieThumb = QFile::exists(pixieThumbPath + fi.fileName())&& QFileInfo(pixieThumbPath+fi.fileName()).lastModified() >= fi.lastModified(); hasKonqThumb = !hasPixieThumb && hasKonqThumbnails && QFile::exists(konqThumbPath + fi.fileName()) && QFileInfo(konqThumbPath + fi.fileName()).lastModified() >= fi.lastModified(); } QString fn, textStr; QImage img; if(hasPixieThumb || hasKonqThumb){ if(mgr->usePixieThumbs()){ fn = hasPixieThumb ? QFile::encodeName(pixieThumbPath + fi.fileName()) : QFile::encodeName(konqThumbPath + fi.fileName()); } else{ fn = hasKonqThumb ? QFile::encodeName(konqThumbPath + fi.fileName()) : QFile::encodeName(pixieThumbPath + fi.fileName()); } if(img.load(fn, "PNG")){ if(i->pixmap) delete i->pixmap; i->pixmap = new QPixmap(img.width(), img.height()); convertImageToPixmapBlend(img, curFrameImage, ((iSize+2)-img.width())/2, ((iSize+2)-img.height())/2, *i->pixmap); i->imageHasThumb = true; textStr = img.text("PixiePlus Size"); if(!textStr.isEmpty()){ if(i->thumbnailData) free(i->thumbnailData); i->thumbnailData = (char *)malloc(strlen(textStr.ascii())+1); qstrcpy(i->thumbnailData, textStr.ascii()); } return(true); } else qWarning("Invalid image for thumbnail %s!", i->filename); } // okay, no thumbnail - determine the icon if(!i->extensionChecked){ i->isImage = isImageType(i->filename); i->extensionChecked = true; } if(i->isImage){ i->pixmap = new QPixmap(iSize >= 64 ? DesktopIcon("image", 64) : DesktopIcon("image", 48)); } else processThumbnailMimeType(i, fi.absFilePath(), iSize); return(true); } QString PixieBrowser::calcKonqThumbPath(const QString &path, int iconSize) { QString sizeStr; if(iconSize == 48) sizeStr = "small"; else if(iconSize == 64) sizeStr = "med"; else if(iconSize == 90) sizeStr = "large"; else if(iconSize == 112) sizeStr = "xxl"; QString url("file:"); url += QDir::cleanDirPath(path); KMD5 md5(QFile::encodeName(url)); QCString hash = md5.hexDigest(); QString thumbPath(QDir::homeDirPath() + "/.kde/share/thumbnails/" + QString::fromLatin1(hash.data(), 4) + "/" + QString::fromLatin1(hash.data()+4, 4) + "/" + QString::fromLatin1(hash.data()+8) + "/" + sizeStr + "/"); return(thumbPath); } void PixieBrowser::calcTextWrapping(Thumbnail *item) { if(!item->textDirty) return; item->textDirty = false; int w = iSize; QString str(item->filename); if(fm->width(str) <= w) return; QString tmpStr; int i = 0; while(fm->width(tmpStr + str[i]) < w) tmpStr += str[i++]; QString buffer; if(fm->width(str)-fm->width(tmpStr) < w){ while(fm->width(buffer + str[i]) < w && i < ((int)str.length())) buffer += str[i++]; } else{ while(fm->width(buffer + str[i]) < w && i < ((int)str.length())) buffer += str[i++]; buffer.remove(0, 3); buffer += "..."; } tmpStr = tmpStr + "\n" + buffer; item->formattedText = (char *)malloc(strlen(tmpStr.latin1())+1); strcpy(item->formattedText, tmpStr.latin1()); } void PixieBrowser::calcTooltip(Thumbnail *item) { if(item->tooltip) return; QString tipStr; QString fn(item->filename); bool isDir = S_ISDIR(item->status->st_mode); tipStr += ""+ fn + "
"; // size QString sizeStr; if(!isDir){ float size = item->status->st_size; if(size >= 1024){ size /= 1024.0; if(size >= 1024){ size /= 1024.0; sizeStr += i18n("File size: ")+QString::number(size, 'f', 2)+"M
"; } else{ sizeStr += i18n("File size: ")+QString::number(size, 'f', 2)+"K
"; } } else{ sizeStr += i18n("File size: ")+QString::number((int)size)+"B
"; } tipStr += sizeStr; } // owner and group struct passwd *pentry = getpwuid(item->status->st_uid); if(pentry) tipStr += i18n("Owner: ") + QString(pentry->pw_name) + ", "; struct group *gentry = getgrgid(item->status->st_gid); if(gentry) tipStr += i18n("Group: ") + QString(gentry->gr_name) + "
"; QString pathStr(absFileStr + '/' + item->filename); tipStr += i18n("Your rights: "); bool anyRights = false; if(access(QFile::encodeName(pathStr), R_OK) == 0){ tipStr += i18n("Read "); anyRights = true; } if(access(QFile::encodeName(pathStr), W_OK) == 0){ tipStr += i18n("Write "); anyRights = true; } if(access(QFile::encodeName(pathStr), X_OK) == 0){ tipStr += i18n("Execute "); anyRights = true; } if(!anyRights) tipStr += i18n("None"); tipStr += "
"; // access and modified time QDateTime t; t.setTime_t(item->status->st_atime); tipStr += i18n("Last accessed: ") + t.toString() + "
"; t.setTime_t(item->status->st_mtime); tipStr += i18n("Last modified: ") + t.toString() + "
"; // get image specific information QString imageStr, cameraStr, commentStr; appendTooltipData(QFile::encodeName(pathStr), imageStr, cameraStr, commentStr, true); // Append them all together if(!imageStr.isEmpty()){ tipStr += ""; tipStr += i18n("Image info"); tipStr += "
"; tipStr += imageStr; } else if(item->thumbnailData){ tipStr += ""; tipStr += i18n("Image info"); tipStr += "
"; tipStr += i18n("Image size: "); tipStr += item->thumbnailData; tipStr += "
"; } // Display catagories after image info // catagories tipStr += /*"
"*/ "" + i18n("Categories") + "
"; QStringList itemList(itemCatagories(item)); if(itemList.count() == 0) tipStr += i18n("None"); else{ QStringList::Iterator it; for(it = itemList.begin(); it != itemList.end(); ++it){ tipStr += "\n\t"; tipStr += (*it); } } tipStr += "
"; if(!cameraStr.isEmpty()){ tipStr += ""; tipStr += i18n("Camera/Scanner info"); tipStr += "
"; tipStr += cameraStr; } if(!commentStr.isEmpty()){ tipStr += ""; tipStr += i18n("Comment"); tipStr += "
"; tipStr += commentStr; } tipStr += "
"; item->tooltip = (char *)malloc(tipStr.length()+1); strcpy(item->tooltip, tipStr.ascii()); } int sortLongIntegers(const void *long1, const void *long2) { return((*((long*)long1))-(*((long*)long2))); } void PixieBrowser::loadPath(const QString &newPathStr, int iconSize, int sortType, int showOnlyCatagory, bool catagoriesFirst, bool iconOnly, bool imagesFirst, const QString &nameFilter) { if(newPathStr != currentDir){ if(!currentDir.isNull()) dirWatch->removeDir(currentDir); dirWatch->addDir(newPathStr); } dirWatch->stopDirScan(newPathStr); qWarning("Show only catagory: %d", showOnlyCatagory); if(thumbJob){ qWarning("Killing old thumbnail generator"); thumbJob->kill(); thumbJob = NULL; stopProcessing = true; emit enableStopButton(false); inGenerateThumbs = false; } int reloadPosition = -1; if(sb->value() != 0 && currentDir == newPathStr) reloadPosition = sb->value(); currentDir = newPathStr; currentSort = sortType; QFileInfo fi(newPathStr); absFileStr = fi.absFilePath(); iSize = iconSize; totalItemWidth = iSize+2+8; // 4 pixels per side border + 1 pix frame totalItemHeight = iSize+2+textHeight+8; oldestFile = newestFile = 0; inDirLoad = true; invalidDir = false; clear(); QPainter p(view); p.fillRect(view->rect(), Qt::white); p.setPen(Qt::black); QFont fnt(p.font()); p.setPen(Qt::black); fnt.setBold(true); p.setFont(fnt); p.drawText(20, 20, i18n("Loading folder...")); p.end(); //view->repaint(false); qApp->processEvents(); hasNameFilter = !nameFilter.isEmpty(); const char *nameFilterStr = hasNameFilter ? nameFilter.latin1() : NULL; QString dirPrefix; switch(iSize){ case 112: dirPrefix = "/xxl/"; break; case 90: dirPrefix = "/large/"; break; case 64: dirPrefix = "/med/"; break; case 48: default: dirPrefix = "/small/"; break; } konqThumbPath = calcKonqThumbPath(currentDir, iconSize); pixieThumbPath = currentDir + "/.pics" + dirPrefix; hasKonqThumbnails = QFile::exists(konqThumbPath); bool processEntry; bool hasParentDir = false; struct dirinfo *listitem, *listhead = NULL; struct dirent *direntry; DIR *dirHandle; int n, i=0; struct inodeinfo *inodeHead = NULL; struct inodeinfo *inodeItem = NULL; long *inodeList = NULL; bool useInodeList; int inodeCount = 0;; loadCatagories(); sortCatagories = catagoriesFirst && catDict.count() != 0; useInodeList = catDict.count() != 0; // read all items into a singly linked list dirHandle = opendir(QFile::encodeName(currentDir)); if(!dirHandle){ qWarning("Invalid folder given to update!"); inDirLoad = false; invalidDir = true; curIdx = -1; view->repaint(false); return; } direntry = readdir(dirHandle); while(direntry){ if(direntry->d_name[0] != '.'){ processEntry = true; listitem = (struct dirinfo *)malloc(sizeof(struct dirinfo)); listitem->extensionChecked = false; listitem->isImage = false; listitem->browser = this; if(stat(QFile::encodeName(currentDir+"/"+direntry->d_name), &listitem->status) == -1){ qWarning("Unable to stat: %s", direntry->d_name); free(listitem); processEntry = false; } else{ if(useInodeList){ ++inodeCount; inodeItem = (struct inodeinfo *) malloc(sizeof(struct inodeinfo)); inodeItem->inode = listitem->status.st_ino; inodeItem->next = inodeHead; inodeHead = inodeItem; } if(processEntry && iconOnly){ if(S_ISDIR(listitem->status.st_mode)) ; else{ listitem->isImage = isImageType(direntry->d_name); listitem->extensionChecked = true; if(!listitem->isImage){ free(listitem); processEntry = false; } } } if(processEntry && hasNameFilter){ if(fnmatch(nameFilterStr, direntry->d_name, 0) != 0){ free(listitem); processEntry = false; } } if(processEntry && showOnlyCatagory != -1 && !S_ISDIR(listitem->status.st_mode)){ processEntry = false; CatInfo *data = catDict.find((long)listitem-> status.st_ino); if(data){ for(int j=0; j < 8; ++j){ if(data->catagories[j] == showOnlyCatagory){ processEntry = true; break; } } } if(!processEntry) free(listitem); } } if(processEntry){ if(!i) oldestFile = newestFile = listitem->status.st_mtime; else{ if(listitem->status.st_mtime < oldestFile) oldestFile = listitem->status.st_mtime; if(listitem->status.st_mtime > newestFile) newestFile = listitem->status.st_mtime; } ++i; listitem->name = (char *)malloc(strlen(direntry->d_name)+1); strcpy(listitem->name, direntry->d_name); listitem->next = listhead; listhead = listitem; } } else if(qstrcmp(direntry->d_name, "..") == 0) hasParentDir = true; direntry = readdir(dirHandle); } closedir(dirHandle); emit enableUpDir(hasParentDir); hasInitialLoad = true; if(i == 0){ inDirLoad = false; qWarning("No items in folder!"); view->repaint(false); dirWatch->restartDirScan(currentDir); if(useInodeList && inodeHead && inodeCount){ inodeItem = inodeHead; struct inodeinfo *tempinfo; for(n=0; n < inodeCount; ++n){ tempinfo = inodeItem; inodeItem = inodeItem->next; free(tempinfo); } } return; } // create an index to all the items listarray = (struct dirinfo **)malloc((sizeof(struct dirinfo *))*i); listitem = listhead; for(n=0; n < i; ++n){ listarray[n] = listitem; listitem = listitem->next; } if(useInodeList){ inodeList = (long *)malloc(sizeof(long)*inodeCount); inodeItem = inodeHead; struct inodeinfo *tempinfo; for(n=0; n < inodeCount; ++n){ inodeList[n] = inodeItem->inode; tempinfo = inodeItem; inodeItem = inodeItem->next; free(tempinfo); } } // sort imagesOnTop = imagesFirst; arrayCount = i; switch(sortType){ case AscendingByNameID: qsort(listarray, i, sizeof(struct dirinfo *), sortNameAscending); break; case DescendingByNameID: qsort(listarray, i, sizeof(struct dirinfo *), sortNameDescending); break; case AscendingBySizeID: qsort(listarray, i, sizeof(struct dirinfo *), sortSizeAscending); break; case AscendingSameSizesFirstID: qsort(listarray, i, sizeof(struct dirinfo *), sortSizeAscendingSameFirst); break; case DescendingBySizeID: qsort(listarray, i, sizeof(struct dirinfo *), sortSizeDescending); break; case AscendingByDateID: qsort(listarray, i, sizeof(struct dirinfo *), sortDateAscending); break; case DescendingByDateID: qsort(listarray, i, sizeof(struct dirinfo *), sortDateDescending); break; default: qWarning("Unknown sort type!"); break; } if(useInodeList) qsort(inodeList, inodeCount, sizeof(long), sortLongIntegers); allocateArray(i); recalcColumns(view->width(), view->height()); for(n=0; n < i /*&& !stopProcessing*/; ++n){ listitem = listarray[n]; itemList[n].status = (struct stat *)malloc(sizeof(struct stat)); memcpy(itemList[n].status, &listitem->status, sizeof(struct stat)); itemList[n].filename = (char *)malloc(strlen(listitem->name)+1); strcpy(itemList[n].filename, listitem->name); itemList[n].isDir = S_ISDIR(listitem->status.st_mode); itemList[n].extensionChecked = listitem->extensionChecked; itemList[n].isImage = listitem->isImage; free(listitem->name); free(listitem); } free(listarray); if(useInodeList){ // check for obselete catagory items - inodeList is a sorted // array of loaded inodes long inode; bool needsSave = false; QIntDictIterator it(catDict); while(it.current()){ inode = it.currentKey(); if(!bsearch(&inode, inodeList, inodeCount, sizeof(long), sortLongIntegers)){ qWarning("Removing obselete inode: %ld", inode); catDict.remove(inode); needsSave = true; } else ++it; } free(inodeList); if(needsSave) kifapp()->catagoryManager()-> saveFolderCatagories(currentDir, &catDict); } inDirLoad = false; view->setFocus(); if(i) curIdx = 0; else curIdx = -1; if(reloadPosition != -1){ if(reloadPosition <= sb->maxValue()) sb->setValue(reloadPosition); else sb->setValue(sb->maxValue()); } else view->repaint(false); dirWatch->restartDirScan(currentDir); } void PixieBrowser::slotGenerateThumbnails() { if(inGenerateThumbs || thumbJob){ QMessageBox::warning(this, i18n("Thumbnail Error!"), i18n("Already generating thumbnails!")); return; } if(!itemCount){ qWarning("No items to thumbnail!"); return; } dirWatch->stopDirScan(currentDir); stopProcessing = false; inGenerateThumbs = true; curPreviewingIdx = -1; emit setStatusBarText(i18n("Previewing images...")); emit enableStopButton(true); mgr->blockUI(true); qApp->processEvents(); QString thumbStr; switch(iSize){ case 112: thumbStr = "xxl/"; break; case 90: thumbStr = "large/"; break; case 64: thumbStr = "med/"; break; case 48: default: thumbStr = "small/"; break; } if(tmpIconPix->width() != iSize+2 || tmpIconPix->height() != iSize+2+textHeight) tmpIconPix->resize(iSize+2, iSize+2+textHeight); // calc thumbnail paths QString path(currentDir); // Pixie struct stat fileInfo; bool canSavePixieThumb = true; if(stat(QFile::encodeName(path+"/.pics"), &fileInfo) == -1){ if(mkdir(QFile::encodeName(path+"/.pics"), 0777) == -1){ canSavePixieThumb = false; } } if(canSavePixieThumb && stat(QFile::encodeName(path+"/.pics/"+thumbStr), &fileInfo) == -1){ if(mkdir(QFile::encodeName(path+"/.pics/"+thumbStr), 0777) == -1){ canSavePixieThumb = false; } } if(access(QFile::encodeName(path+"/.pics/"+thumbStr), W_OK) != 0) canSavePixieThumb = false; // Konq - make dirs even if we use internal previews if KIO thumbnails // are requested bool canSaveKonqThumb = true; if(!mgr->usePixieThumbs() || mgr->kioThumbnailTypes()->count() != 0){ QString urlStr("file:"); urlStr += QDir::cleanDirPath(currentDir); KMD5 md5(QFile::encodeName(urlStr)); QCString hash = md5.hexDigest(); QString testKonqPath = QDir::homeDirPath() + "/.kde/share/thumbnails/"; if(stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data(), 4) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data()+4, 4) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data()+8) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += thumbStr; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } if(access(QFile::encodeName(testKonqPath), W_OK) != 0) canSaveKonqThumb = false; } bool saveThumb; if(mgr->usePixieThumbs() && canSavePixieThumb){ thumbStr = pixieThumbPath; saveThumb = true; } else{ thumbStr = konqThumbPath; saveThumb = canSaveKonqThumb; } if(!saveThumb) qWarning("Could not save thumbnails!"); // shouldn't happen int i, percent, itemY; QString pathStr, sizeStr; QValueList videoList; KFileItemList kioPreviewList; QStringList *kioHandlers = mgr->kioThumbnailTypes(); const char *ext; bool useComment, process; QImage image; bool pixieThumb, konqThumb; QPainter p; p.begin(tmpIconPix); if(kioHandlers->count()){ QStringList::Iterator it; for(it=kioHandlers->begin(); it != kioHandlers->end(); ++it) qWarning("Handler: %s", (*it).latin1()); } for(i=0, percent=0; i < itemCount && !stopProcessing; ++i){ pathStr = QDir::cleanDirPath(currentDir + "/" + itemList[i].filename); pixieThumb = QFile::exists(pixieThumbPath + itemList[i].filename) && ((time_t)QFileInfo(pixieThumbPath+itemList[i].filename).lastModified().toTime_t()) >= itemList[i].status->st_mtime; konqThumb = hasKonqThumbnails && QFile::exists(konqThumbPath + itemList[i].filename) && ((time_t)QFileInfo(konqThumbPath + itemList[i].filename).lastModified().toTime_t()) >= itemList[i].status->st_mtime; if(!pixieThumb && !konqThumb){ if(!itemList[i].isDir && isImage(&itemList[i], pathStr, false)){ ext = extension(itemList[i].filename); process = true; // check for embedded thumbnail if requested if(mgr->useEmbeddedJPEGPreview() && (qstricmp(ext, "jpg") == 0 || qstricmp(ext, "jpeg") == 0)){ MyExifData exifInfo; // recreate each time, it gets confused if(exifInfo.scan(pathStr)){ image = exifInfo.getThumbnail(); if(image.isNull()){ qWarning("Unable to get embedded EXIF thumbnail for %s", itemList[i].filename); process = loadImage(image, pathStr); } else qWarning("Got EXIF thumbnail for %s", itemList[i].filename); } else process = loadImage(image, pathStr); } else if(mgr->useEmbeddedTIFFPreview() && (qstricmp(ext, "tif") == 0 || qstricmp(ext, "tiff") == 0)){ if(!checkTIFFThumbnail(QFile::encodeName(pathStr), image)) process = loadImage(image, pathStr); } else process = loadImage(image, pathStr); if(process){ itemY = (i/columns)*totalItemHeight; curPreviewingIdx = i; if(itemY+totalItemHeight > sb->value()+view->height() || itemY < sb->value()){ sb->setValue(itemY); qApp->processEvents(); } if(qstricmp(ext, "png") != 0 && qstricmp(ext, "jpg") != 0 && qstricmp(ext, "jpeg") != 0 && qstricmp(ext, "gif") != 0 && qstricmp(ext, "bmp") != 0 && qstricmp(ext, "tif") != 0 && qstricmp(ext, "tiff") != 0) useComment = true; else useComment = false; if(useComment){ sizeStr = sizeStr.sprintf("%dx%d", image.width(), image.height()); } if(image.width() > iSize || image.height() > iSize){ if(image.width() > image.height()){ float percent = (((float)iSize)/image.width()); int h = (int)(image.height()*percent); image = image.smoothScale(iSize, h); } else{ float percent = (((float)iSize)/image.height()); int w = (int)(image.width()*percent); image= image.smoothScale(w, iSize); } } if(mgr->lowQualityPreview && image.depth() > 8) image = image.convertDepth(8, Qt::AvoidDither | Qt::DiffuseAlphaDither); if(useComment) image.setText("PixiePlus Size", 0, sizeStr); image.save(thumbStr+itemList[i].filename, "PNG"); if(itemList[i].pixmap) delete itemList[i].pixmap; itemList[i].pixmap = new QPixmap(image.width(), image.height()); convertImageToPixmapBlend(image, curFrameImage, ((iSize+2)-image.width())/2, ((iSize+2)-image.height())/2, *itemList[i].pixmap); itemList[i].thumbnailed = true; itemList[i].imageHasThumb = true; if(itemList[i].thumbnailData) free(itemList[i].thumbnailData); itemList[i].thumbnailData = NULL; if(useComment){ itemList[i].thumbnailData = (char *) malloc(strlen(sizeStr.ascii())+1); qstrcpy(itemList[i].thumbnailData, sizeStr.ascii()); if(itemList[i].tooltip){ free(itemList[i].tooltip); itemList[i].tooltip = NULL; } } curPreviewingIdx = -1; paintThumbnail(i, &p); emit setStatusBarText(i18n("Created Thumbnail for ") + itemList[i].filename); } else qWarning("Unable to load %s!", itemList[i].filename); } else if(/*!itemList[i].isDir && mgr->useMPlayerVideo() && isVideoType(itemList[i].filename)*/false){ videoList.append(i); } else if(!itemList[i].isDir && itemList[i].mimetype && kioHandlers->count() != 0){ KURL url; url.setPath(currentDir + "/" + itemList[i].filename); KFileItem *fileItem = new KFileItem(url, itemList[i].mimetype, itemList[i].status-> st_mode); kioPreviewList.append(fileItem); } } if((int)(((float)i/itemCount)*100) > percent){ percent = (int)(((float)i/itemCount)*100); emit updateProgress(percent); } kifapp()->processEvents(); } // do video thumbnails if(!stopProcessing && videoList.count() && saveThumb){ /* QStringList fileList; QValueList::iterator it; for(it=videoList.begin(); it != videoList.end(); ++it){ i = (*it); fileList.append(itemList[i].filename); } qWarning("running mplayer dialog"); emit setStatusBarText(i18n("Previewing movies...")); qApp->processEvents(); // create by new, even tho we delete it right away :P MPlayerDialog *dlg = new MPlayerDialog(fileList, currentDir, thumbStr, iSize, view); dlg->run(); delete dlg; // update the items for(it=videoList.begin(); it != videoList.end(); ++it){ i = (*it); if(image.load(thumbStr+itemList[i].filename, "PNG")){ if(itemList[i].pixmap) delete itemList[i].pixmap; itemList[i].pixmap = new QPixmap(image.width(), image.height()); convertImageToPixmapBlend(image, curFrameImage, ((iSize+2)-image.width())/2, ((iSize+2)-image.height())/2, *itemList[i].pixmap); itemList[i].thumbnailed = true; paintThumbnail(i, &p); } else qWarning("Could not load video thumbnail %s", itemList[i].filename); }*/ } p.end(); // do KIO if(!stopProcessing && kioPreviewList.count() != 0){ emit updateProgress(0); emit setStatusBarText(i18n("Running KDE non-image previews...")); kioCurrentThumb = 0; kioThumbCount = kioPreviewList.count(); thumbJob = new KIO::PreviewJob(kioPreviewList, iSize, iSize, iSize, 70, true, true, kioHandlers); connect(thumbJob, SIGNAL(gotPreview(const KFileItem *, const QPixmap &)), this, SLOT(slotThumbJobPreview(const KFileItem *, const QPixmap &))); connect(thumbJob, SIGNAL(failed(const KFileItem *)), this, SLOT(slotThumbJobFailed(const KFileItem *))); connect(thumbJob, SIGNAL(result(KIO::Job *)), this, SLOT(slotThumbJobResult(KIO::Job *))); connect(thumbJob, SIGNAL(percent(KIO::Job *, unsigned long)), this, SLOT(slotThumbJobProgress(KIO::Job *, unsigned long))); } else{ emit updateProgress(100); emit setStatusBarText(i18n("PixiePlus thumbnails complete")); emit enableStopButton(false); emit enableFolderChanges(true); inGenerateThumbs = false; dirWatch->restartDirScan(currentDir); mgr->blockUI(false); } } void PixieBrowser::stop() { stopProcessing = true; if(inGenerateThumbs && thumbJob){ emit updateProgress(100); emit setStatusBarText(i18n("KDE thumbnails stopped")); qWarning("Killing KIO thumbnail generation"); thumbJob->kill(false); thumbJob = NULL; dirWatch->restartDirScan(currentDir); } inGenerateThumbs = false; } void PixieBrowser::recalcColumns(int vw, int vh) { int h; if(!count()){ columns = h = 0; } else{ columns = vw/totalItemWidth; h = (int)ceil(((float)count())/columns); h *= totalItemHeight; } if(h-vh > 0){ if(!sb->isEnabled()) sb->setEnabled(true); sb->setRange(0, h-vh); sb->setLineStep(16); sb->setPageStep(vh); } else{ sb->setRange(0, 0); if(sb->isEnabled()) sb->setEnabled(false); } recalcRects(); } void PixieBrowser::copy() { QValueList::iterator it; QStrList fileList; int idx; if(!selectList.count()) return; sortSelectionByView(); for(it = selectList.begin(); it != selectList.end(); ++it){ idx = *it; fileList.append(QFile::encodeName(currentDir + "/" + itemList[idx].filename)); } if(fileList.isEmpty()) return; QUriDrag *obj = new QUriDrag(fileList); QClipboard *cb = QApplication::clipboard(); #if QT_VERSION & 0x00FF00 cb->setData(obj, QClipboard::Clipboard); #else cb->setData(obj); #endif } void PixieBrowser::paste() { QClipboard *cb = QApplication::clipboard(); QStringList fileList; #if QT_VERSION & 0x00FF00 if(QUriDrag::decodeLocalFiles(cb->data(QClipboard::Clipboard), fileList)){ #else if(QUriDrag::decodeLocalFiles(cb->data(), fileList)){ #endif if(!fileList.count()) return; KIFFileTransfer::transferFiles(fileList, currentDir, QDropEvent::Copy); } else KMessageBox::sorry(this, i18n("The clipboard is empty."), i18n("Pixie Clipboard Error!")); } // Tooltips void BrowserTip::maybeTip(const QPoint &p) { PixieBrowser *browser = (PixieBrowser *)parentWidget()->parent(); if(!browser->count()) return; int i, idx = browser->firstVisibleIdx; PixieRect r; for(i=0; i < browser->visibleRectCount; ++i){ r = browser->visibleRects[i]; if(contains(r.x, r.y, r.w, r.h, p.x(), p.y()) && idx < browser->itemCount){ if(!browser->itemList[idx].tooltip) browser->calcTooltip(&browser->itemList[idx]); tip(QRect(r.x, r.y, r.w, r.h), browser->itemList[idx].tooltip); return; } ++idx; } } void PixieBrowser::clearTips() { int i; for(i=0; i < itemCount; ++i){ if(itemList[i].tooltip){ free(itemList[i].tooltip); itemList[i].tooltip = NULL; } } } // Catagories bool PixieBrowser::loadCatagories() { catError = false; supportCatagories = kifapp()->catagoryManager()-> loadFolderCatagories(currentDir, &catDict); return(supportCatagories); } bool PixieBrowser::saveCatagories() { dirWatch->stopDirScan(currentDir); clearTips(); bool result = kifapp()->catagoryManager()-> saveFolderCatagories(currentDir, &catDict); dirWatch->restartDirScan(currentDir); return(result); } QStringList PixieBrowser::itemCatagories(Thumbnail *item) { QStringList list; if(!item) return(list); CatInfo *info = catDict.find((long)item->status->st_ino); QString **catarray = kifapp()->catagoryManager()->array(); int i; if(info){ for(i=0; i < 8 && info->catagories[i]; ++i){ int j = info->catagories[i]; if(catarray[j] != 0) list.append(*catarray[j]); else qWarning("Invalid catagory index %d, value: %d", i, j); } } list.sort(); return(list); } void PixieBrowser::addCatagory(Thumbnail *item, int id) { CatInfo *info; long inode = (long)item->status->st_ino; int i; info = catDict.find(inode); if(!info){ qWarning("Adding new catagory %d for %s", id, item->filename); info = new CatInfo; info->catagories[0] = id; for(i=1; i < 8; ++i) info->catagories[i] = 0; catDict.insert(inode, info); } else{ unsigned char *data = info->catagories; for(i=0; i < 8 && data[i] != 0 && data[i] != id; ++i) ; if(i == 8){ // TODO: messagebox qWarning("Maximum allowed catagories!"); return; } else if(data[i] == id){ qWarning("Id already set!"); return; } else{ data[i] = id; } } } void PixieBrowser::removeCatagory(Thumbnail *item, int id) { qWarning("In removeCatagory"); CatInfo *info; long inode = (long)item->status->st_ino; int i; info = catDict.find(inode); if(!info){ // TODO messagebox qWarning("Tried to remove catagory that wasn't set"); return; } unsigned char *data = info->catagories; for(i=0; i < 8 && data[i] != id; ++i) ; if(i < 8 && data[i] == id){ // justify left while(i < 7){ data[i] = data[i+1]; ++i; } data[7] = 0; } else qWarning("Id's are mismatched: id: %d, i: %d, data[i]: %d!", id, i, data[i]); if(data[0] == 0){ qWarning("No more catagories, removing entry"); catDict.remove(inode); } qWarning("Leaving removeCatagory"); } // KIO thumbnail generation slots void PixieBrowser::slotThumbJobResult(KIO::Job *job) { if(job == thumbJob){ qWarning("KIO job finished"); thumbJob = NULL; emit updateProgress(100); kioThumbCount = kioCurrentThumb = 0; // shouldn't matter stopProcessing = true; emit enableStopButton(false); emit enableFolderChanges(true); emit setStatusBarText(i18n("KDE thumbnails complete")); dirWatch->restartDirScan(currentDir); inGenerateThumbs = false; mgr->blockUI(false); } } void PixieBrowser::slotThumbJobProgress(KIO::Job *, unsigned long) { ; } void PixieBrowser::slotThumbJobPreview(const KFileItem *item, const QPixmap &preview) { int percent; ++kioCurrentThumb; percent = (int)(((float)kioCurrentThumb/kioThumbCount)*100); if(percent == 100) percent = 99; // Don't do 100% until done emit updateProgress(percent); QString previewItemStr(item->url().fileName()); qWarning("Got KDE preview for %s", previewItemStr.latin1()); int idx = findItem(QFile::encodeName(previewItemStr)); if(idx != -1 && idx < itemCount){ if(itemList[idx].pixmap) delete itemList[idx].pixmap; itemList[idx].pixmap = new QPixmap(preview); itemList[idx].thumbnailed = true; if(isItemVisible(idx)) paintThumbnail(idx); } else qWarning("Could not find item!"); if(!QFile::exists(konqThumbPath + "/" + previewItemStr)){ // We always save thumbnails if possible. KDE skips some types // and will always regenerate, (ie: text), and uses a maximum // size limit qWarning("Thumbnail was not saved, saving..."); preview.save(konqThumbPath + "/" + previewItemStr, "PNG"); } else qWarning("Thumbnail was saved"); } void PixieBrowser::slotThumbJobFailed(const KFileItem */*item*/) { ++kioCurrentThumb; int percent = (int)(((float)kioCurrentThumb/kioThumbCount)*100); emit updateProgress(percent); } // Thumbnail conversion void PixieBrowser::convertToPixieThumbs() { QString thumbStr; int i, c = count(); switch(iSize){ case 112: thumbStr = "xxl/"; break; case 64: thumbStr = "med/"; break; case 48: thumbStr = "small/"; break; case 90: default: thumbStr = "large/"; break; } if(!hasKonqThumbnails || !c){ KMessageBox::sorry(this, i18n("No Konqueror previews in this folder!"), i18n("Thumbnail Error")); return; } dirWatch->stopDirScan(currentDir); struct stat fileInfo; bool canSavePixieThumb = true; if(stat(QFile::encodeName(currentDir+"/.pics"), &fileInfo) == -1){ if(mkdir(QFile::encodeName(currentDir+"/.pics"), 0777) == -1){ canSavePixieThumb = false; } } if(canSavePixieThumb && stat(QFile::encodeName(currentDir+"/.pics/"+thumbStr), &fileInfo) == -1){ if(mkdir(QFile::encodeName(currentDir+"/.pics/"+thumbStr), 0777) == -1){ canSavePixieThumb = false; } } if(access(QFile::encodeName(currentDir+"/.pics/"+thumbStr), W_OK) != 0) canSavePixieThumb = false; if(!canSavePixieThumb){ KMessageBox::sorry(this, i18n("Cannot save PixiePlus previews for this folder!"), i18n("Thumbnail Error")); dirWatch->restartDirScan(currentDir); return; } emit setStatusBarText(i18n("Converting thumbnails...")); kifapp()->processEvents(); QFileInfo fi; for(i=0; i < c; ++i){ if(QFile::exists(konqThumbPath + itemList[i].filename)){ fi.setFile(konqThumbPath + itemList[i].filename); KURL url("file:"+fi.absFilePath()); QString mimeStr = KMimeType::findByURL(url, true, true)->name(); // move only images and text if(mimeStr.left(6) == "image/" || (mimeStr.left(5) == "text/" && mimeStr != "text/html")){ if(QFile::exists(pixieThumbPath + itemList[i].filename)){ qWarning("%s has both thumbnails", itemList[i].filename); if(QFileInfo(konqThumbPath+itemList[i].filename).lastModified() > QFileInfo(pixieThumbPath+itemList[i].filename).lastModified()) KIFFileTransfer::move(konqThumbPath + itemList[i].filename, pixieThumbPath, false); } else KIFFileTransfer::move(konqThumbPath + itemList[i].filename, pixieThumbPath, false); } else qWarning("Ignoring non image or text file %s", itemList[i].filename); } } dirWatch->restartDirScan(currentDir); emit setStatusBarText(i18n("Done converting thumbnails")); } void PixieBrowser::convertToKonqThumbs() { QString thumbStr; int i, c = count(); switch(iSize){ case 112: thumbStr = "xxl/"; break; case 64: thumbStr = "med/"; break; case 48: thumbStr = "small/"; break; case 90: default: thumbStr = "large/"; break; } QString pixiePath = currentDir+"/.pics/"+thumbStr; if(!QFile::exists(pixiePath) || !c){ KMessageBox::sorry(this, i18n("No PixiePlus previews in this folder!"), i18n("Thumbnail Error")); return; } dirWatch->stopDirScan(currentDir); // test or create konq thumbnail dir bool canSaveKonqThumb = true; struct stat fileInfo; KURL url; url.setPath(QDir::cleanDirPath(currentDir)); KMD5 md5(QFile::encodeName(url.url())); QCString hash = md5.hexDigest(); QString testKonqPath = KGlobal::dirs()->localkdedir() + "/share/thumbnails/"; if(stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data(), 4) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data()+4, 4) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += QString::fromLatin1(hash.data()+8) + "/"; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } testKonqPath += thumbStr; if(canSaveKonqThumb && stat(QFile::encodeName(testKonqPath), &fileInfo) == -1){ if(mkdir(QFile::encodeName(testKonqPath), 0777) == -1){ canSaveKonqThumb = false; } } if(access(QFile::encodeName(testKonqPath), W_OK) != 0) canSaveKonqThumb = false; if(!canSaveKonqThumb){ KMessageBox::sorry(this, i18n("Cannot save Konqueror previews for this folder!"), i18n("Thumbnail Error")); dirWatch->restartDirScan(currentDir); return; } // move them emit setStatusBarText(i18n("Converting thumbnails...")); kifapp()->processEvents(); for(i=0; i < c; ++i){ if(QFile::exists(pixiePath + itemList[i].filename)){ if(QFile::exists(testKonqPath + itemList[i].filename)){ qWarning("%s has both thumbnails", itemList[i].filename); if(QFileInfo(pixiePath+itemList[i].filename).lastModified() > QFileInfo(testKonqPath+itemList[i].filename).lastModified()) KIFFileTransfer::move(pixiePath + itemList[i].filename, testKonqPath, false); } else KIFFileTransfer::move(pixiePath + itemList[i].filename, testKonqPath, false); } } dirWatch->restartDirScan(currentDir); emit setStatusBarText(i18n("Done converting thumbnails")); } // Misc bool PixieBrowser::isImage(Thumbnail *i, const QString &absPath, bool useExtensionOnly) { if(i->isImage) return(true); if(!i->extensionChecked){ i->isImage = isImageType(i->filename); i->extensionChecked = true; if(i->isImage) return(true); } if(!i->mimetypeChecked && !useExtensionOnly && !absPath.isEmpty()) processThumbnailMimeType(i, absPath, iSize); return(i->isImage); } void PixieBrowser::processThumbnailMimeType(Thumbnail *i, const QString &path, int iconSize) { if(i->isImage || i->mimetype || (i->mimetypeChecked && iconSize == -1)) return; i->mimetypeChecked = true; KMimeType::Ptr mimeType = KMimeType::findByPath(path, i->status->st_mode); if(iconSize != -1 && !i->pixmap){ i->pixmap = new QPixmap; QString iconStr = mimeType->icon(path, true); if(!iconStr) iconStr = "unknown"; QPixmap *cachedPix = iconDict.find(iconStr); if(cachedPix) *i->pixmap = *cachedPix; else{ QImage img(KGlobal::iconLoader()-> iconPath(iconStr, iconSize >= 64 ? -64 : -48)); if(1){ /*FIXME - make configurable*/ int scaleSize = iSize - 4; if(scaleSize > 82) scaleSize = 82; img = img.smoothScale(scaleSize, scaleSize); } cachedPix = new QPixmap(img.width(), img.height()); convertImageToPixmapBlend(img, curFrameImage, ((iSize+2)-img.width())/2, ((iSize+2)-img.height())/2, *cachedPix); iconDict.insert(iconStr, cachedPix); *i->pixmap = *cachedPix; } } if(mimeType->name().left(6) == "image/") i->isImage = true; else{ i->mimetype = (char *)malloc(strlen(mimeType->name().latin1())+1); qstrcpy(i->mimetype, mimeType->name().latin1()); } } QImage PixieBrowser::uicImage(const QString &name) { return(uic_findImage(name)); }