/* ============================================================
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-11-22
 * Description : a bar widget to display image thumbnails
 * 
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 * Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot 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, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * ============================================================ */

// C Ansi includes.

extern "C"
{
#include <unistd.h>
}

// C++ includes.

#include <cmath>

// TQt includes.

#include <tqdir.h>
#include <tqpixmap.h>
#include <tqimage.h>
#include <tqtimer.h>
#include <tqpainter.h>
#include <tqdict.h>
#include <tqpoint.h>
#include <tqstylesheet.h>
#include <tqdatetime.h>
#include <tqguardedptr.h>

// KDE includes.

#include <kmdcodec.h>
#include <tdefileitem.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <kmimetype.h>
#include <tdefileitem.h>
#include <tdeglobal.h>

// LibKDcraw includes.

#include <libkdcraw/version.h>
#include <libkdcraw/kdcraw.h>

#if KDCRAW_VERSION < 0x000106
#include <libkdcraw/dcrawbinary.h>
#endif

// Local includes.

#include "dmetadata.h"
#include "thumbnailjob.h"
#include "thumbnailsize.h"
#include "thumbbar.h"
#include "thumbbar.moc"

namespace Digikam
{

class ThumbBarViewPriv
{
public:

    ThumbBarViewPriv() :
        margin(5)
    {
        dragging   = false;
        exifRotate = false;
        clearing   = false;
        toolTip    = 0;
        firstItem  = 0;
        lastItem   = 0;
        currItem   = 0;
        count      = 0;
        thumbJob   = 0;
        tileSize   = ThumbnailSize::Small;

        itemDict.setAutoDelete(false);
    }

    bool                       clearing;
    bool                       exifRotate;
    bool                       dragging;

    const int                  margin;
    int                        count;
    int                        tileSize;
    int                        orientation;

    TQTimer                    *timer;

    TQPoint                     dragStartPos;

    ThumbBarItem              *firstItem;
    ThumbBarItem              *lastItem;
    ThumbBarItem              *currItem;

    TQDict<ThumbBarItem>        itemDict;
    TQGuardedPtr<ThumbnailJob>  thumbJob;

    ThumbBarToolTipSettings    toolTipSettings;

    ThumbBarToolTip           *toolTip;
};

// -------------------------------------------------------------------------

class ThumbBarItemPriv
{
public:

    ThumbBarItemPriv()
    {
        pos    = 0;
        pixmap = 0;
        next   = 0;
        prev   = 0;
        view   = 0;
    }

    int           pos;

    TQPixmap      *pixmap;

    KURL          url;

    ThumbBarItem *next;
    ThumbBarItem *prev;

    ThumbBarView *view;
};

// -------------------------------------------------------------------------

ThumbBarView::ThumbBarView(TQWidget* parent, int orientation, bool exifRotate,
                           ThumbBarToolTipSettings settings)
            : TQScrollView(parent)
{
    d = new ThumbBarViewPriv;
    d->orientation     = orientation;
    d->exifRotate      = exifRotate;
    d->toolTipSettings = settings;
    d->toolTip         = new ThumbBarToolTip(this);
    d->timer           = new TQTimer(this);

    connect(d->timer, TQ_SIGNAL(timeout()),
            this, TQ_SLOT(slotUpdate()));

    viewport()->setBackgroundMode(TQt::NoBackground);
    viewport()->setMouseTracking(true);
    viewport()->setAcceptDrops(true);

    setFrameStyle(TQFrame::NoFrame);
    setAcceptDrops(true); 

    if (d->orientation ==TQt::Vertical)
    {
        setHScrollBarMode(TQScrollView::AlwaysOff);
    }
    else
    {
        setVScrollBarMode(TQScrollView::AlwaysOff);
    }
}

ThumbBarView::~ThumbBarView()
{
    if (!d->thumbJob.isNull())
    {
        d->thumbJob->kill();
        d->thumbJob = 0;
    }

    clear(false);

    delete d->timer;
    delete d->toolTip;
    delete d;
}

void ThumbBarView::resizeEvent(TQResizeEvent* e)
{
    if (!e) return;

    TQScrollView::resizeEvent(e);

    if (d->orientation ==TQt::Vertical)
    {
        d->tileSize = width() - 2*d->margin - verticalScrollBar()->sizeHint().width();
        verticalScrollBar()->setLineStep(d->tileSize);
        verticalScrollBar()->setPageStep(2*d->tileSize);
    }
    else
    {
        d->tileSize = height() - 2*d->margin - horizontalScrollBar()->sizeHint().height();
        horizontalScrollBar()->setLineStep(d->tileSize);
        horizontalScrollBar()->setPageStep(2*d->tileSize);
    }

    rearrangeItems();
    ensureItemVisible(currentItem());
}

void ThumbBarView::setExifRotate(bool exifRotate)
{
    if (d->exifRotate == exifRotate)
	return;
	
    d->exifRotate = exifRotate;
    TQString thumbCacheDir = TQDir::homeDirPath() + "/.thumbnails/";

    for (ThumbBarItem *item = d->firstItem; item; item = item->d->next)
    {
        // Remove all current album item thumbs from disk cache.

        TQString uri = "file://" + TQDir::cleanDirPath(item->url().path(-1));
        KMD5 md5(TQFile::encodeName(uri).data());
        uri = md5.hexDigest();

        TQString smallThumbPath = thumbCacheDir + "normal/" + uri + ".png";
        TQString bigThumbPath   = thumbCacheDir + "large/"  + uri + ".png";

        ::unlink(TQFile::encodeName(smallThumbPath));
        ::unlink(TQFile::encodeName(bigThumbPath));

        invalidateThumb(item);
    }

    triggerUpdate();
}

bool ThumbBarView::getExifRotate()
{
    return d->exifRotate;
}

int ThumbBarView::getOrientation()
{
    return d->orientation;
}

int ThumbBarView::getTileSize()
{
    return d->tileSize;
}

int ThumbBarView::getMargin()
{
    return d->margin;
}

void ThumbBarView::setToolTipSettings(const ThumbBarToolTipSettings &settings)
{
    d->toolTipSettings = settings;
}

ThumbBarToolTipSettings& ThumbBarView::getToolTipSettings()
{
    return d->toolTipSettings;
}

int ThumbBarView::countItems()
{
    return d->count;
}

KURL::List ThumbBarView::itemsURLs()
{
    KURL::List urlList;
    if (!countItems())
        return urlList;

    for (ThumbBarItem *item = firstItem(); item; item = item->next())
        urlList.append(item->url());

    return urlList;
}

void ThumbBarView::clear(bool updateView)
{
    d->clearing = true;

    ThumbBarItem *item = d->firstItem;
    while (item)
    {
        ThumbBarItem *tmp = item->d->next;
        delete item;
        item = tmp;
    }

    d->firstItem = 0;
    d->lastItem  = 0;
    d->count     = 0;
    d->currItem  = 0;

    if (updateView)
        slotUpdate();

    d->clearing = false;

    emit signalItemSelected(0);
}

void ThumbBarView::triggerUpdate()
{
    d->timer->start(0, true);
}

ThumbBarItem* ThumbBarView::currentItem() const
{
    return d->currItem;
}

ThumbBarItem* ThumbBarView::firstItem() const
{
    return d->firstItem;
}

ThumbBarItem* ThumbBarView::lastItem() const
{
    return d->lastItem;
}

ThumbBarItem* ThumbBarView::findItem(const TQPoint& pos) const
{
    int itemPos;

    if (d->orientation ==TQt::Vertical)
        itemPos = pos.y();
    else
        itemPos = pos.x();

    for (ThumbBarItem *item = d->firstItem; item; item = item->d->next)
    {
        if (itemPos >= item->d->pos && itemPos <= (item->d->pos+d->tileSize+2*d->margin))
        {
            return item;
        }
    }

    return 0;
}

ThumbBarItem* ThumbBarView::findItemByURL(const KURL& url) const
{
    for (ThumbBarItem *item = d->firstItem; item; item = item->d->next)
    {
        if (item->url().equals(url))
        {
            return item;
        }
    }

    return 0;
}

void ThumbBarView::setSelected(ThumbBarItem* item)
{
    if (!item) return;

    ensureItemVisible(item);
    emit signalURLSelected(item->url());
    emit signalItemSelected(item);

    if (d->currItem == item) return;

    if (d->currItem)
    {
        ThumbBarItem* item = d->currItem;
        d->currItem = 0;
        item->repaint();
    }

    d->currItem = item;
    if (d->currItem)
        item->repaint();
}

void ThumbBarView::ensureItemVisible(ThumbBarItem* item)
{
    if (item)
    {
        // We want the complete thumb visible and the next one.
        // find the middle of the image and give a margin of 1,5 image
        // When changed, watch regression for bug 104031
        if (d->orientation ==TQt::Vertical)
            ensureVisible(0, (int)(item->d->pos + d->margin + d->tileSize*.5),
                          0, (int)(d->tileSize*1.5 + 3*d->margin));
        else
            ensureVisible((int)(item->d->pos + d->margin + d->tileSize*.5), 0,
                          (int)(d->tileSize*1.5 + 3*d->margin), 0);
    }
}

void ThumbBarView::refreshThumbs(const KURL::List& urls)
{
    for (KURL::List::const_iterator it = urls.begin() ; it != urls.end() ; ++it)
    {
        ThumbBarItem *item = findItemByURL(*it);
        if (item)
        {
            invalidateThumb(item);
        }
    }
}

void ThumbBarView::invalidateThumb(ThumbBarItem* item)
{
    if (!item) return;

    if (item->d->pixmap)
    {
        delete item->d->pixmap;
        item->d->pixmap = 0;
    }

    if (!d->thumbJob.isNull())
    {
       d->thumbJob->kill();
       d->thumbJob = 0;
    }

    d->thumbJob = new ThumbnailJob(item->url(), ThumbnailSize::Huge, true, d->exifRotate);

    connect(d->thumbJob, TQ_SIGNAL(signalThumbnail(const KURL&, const TQPixmap&)),
            this, TQ_SLOT(slotGotThumbnail(const KURL&, const TQPixmap&)));

    connect(d->thumbJob, TQ_SIGNAL(signalFailed(const KURL&)),
            this, TQ_SLOT(slotFailedThumbnail(const KURL&)));
}

void ThumbBarView::viewportPaintEvent(TQPaintEvent* e)
{
    int cy, cx, ts, y1, y2, x1, x2;
    TQPixmap bgPix, tile;
    TQRect er(e->rect());

    if (d->orientation ==TQt::Vertical)
    {
       cy = viewportToContents(er.topLeft()).y();

       bgPix.resize(contentsRect().width(), er.height());

       ts = d->tileSize + 2*d->margin;
       tile.resize(visibleWidth(), ts);

       y1 = (cy/ts)*ts;
       y2 = ((y1 + er.height())/ts +1)*ts;
    }
    else
    {
       cx = viewportToContents(er.topLeft()).x();

       bgPix.resize(er.width(), contentsRect().height());

       ts = d->tileSize + 2*d->margin;
       tile.resize(ts, visibleHeight());

       x1 = (cx/ts)*ts;
       x2 = ((x1 + er.width())/ts +1)*ts;
    }

    bgPix.fill(colorGroup().background());

    for (ThumbBarItem *item = d->firstItem; item; item = item->d->next)
    {
        if (d->orientation ==TQt::Vertical)
        {
            if (y1 <= item->d->pos && item->d->pos <= y2)
            {
                if (item == d->currItem)
                    tile.fill(colorGroup().highlight());
                else
                    tile.fill(colorGroup().background());

                TQPainter p(&tile);
                p.setPen(TQt::white);
                p.drawRect(0, 0, tile.width(), tile.height());
                p.end();

                if (item->d->pixmap)
                {
                    TQPixmap pix; 
                    pix.convertFromImage(TQImage(item->d->pixmap->convertToImage()).
                                         smoothScale(d->tileSize, d->tileSize, TQImage::ScaleMin));
                    int x = (tile.width()  - pix.width())/2;
                    int y = (tile.height() - pix.height())/2;
                    bitBlt(&tile, x, y, &pix);
                }

                bitBlt(&bgPix, 0, item->d->pos - cy, &tile);
            }
        }
        else
        {
            if (x1 <= item->d->pos && item->d->pos <= x2)
            {
                if (item == d->currItem)
                    tile.fill(colorGroup().highlight());
                else
                    tile.fill(colorGroup().background());

                TQPainter p(&tile);
                p.setPen(TQt::white);
                p.drawRect(0, 0, tile.width(), tile.height());
                p.end();

                if (item->d->pixmap)
                {
                    TQPixmap pix; 
                    pix.convertFromImage(TQImage(item->d->pixmap->convertToImage()).
                                         smoothScale(d->tileSize, d->tileSize, TQImage::ScaleMin));
                    int x = (tile.width() - pix.width())/2;
                    int y = (tile.height()- pix.height())/2;
                    bitBlt(&tile, x, y, &pix);
                }

                bitBlt(&bgPix, item->d->pos - cx, 0, &tile);
            }
        }
    }

    if (d->orientation ==TQt::Vertical)
       bitBlt(viewport(), 0, er.y(), &bgPix);
    else
       bitBlt(viewport(), er.x(), 0, &bgPix);
}

void ThumbBarView::contentsMousePressEvent(TQMouseEvent* e)
{
    ThumbBarItem* barItem = findItem(e->pos());
    d->dragging           = true;
    d->dragStartPos       = e->pos();

    if (!barItem || barItem == d->currItem)
        return;

    if (d->currItem)
    {
        ThumbBarItem* item = d->currItem;
        d->currItem = 0;
        item->repaint();
    }

    d->currItem = barItem;
    barItem->repaint();
}

void ThumbBarView::contentsMouseMoveEvent(TQMouseEvent *e)
{
    if (!e) return;

    if (d->dragging && (e->state() & TQt::LeftButton))
    {
        if ( findItem(d->dragStartPos) &&
             (d->dragStartPos - e->pos()).manhattanLength() > TQApplication::startDragDistance() )
        {
            startDrag();
        }
        return;
    }
}

void ThumbBarView::contentsMouseReleaseEvent(TQMouseEvent *e)
{
    d->dragging = false;
    ThumbBarItem *item = findItem(e->pos());
    if (item) 
    {
        emit signalURLSelected(item->url());
        emit signalItemSelected(item);
    }
}

void ThumbBarView::contentsWheelEvent(TQWheelEvent *e)
{
    e->accept();

    if (e->delta() < 0)
    {
        if (e->state() & TQt::ShiftButton)
        {
            if (d->orientation ==TQt::Vertical)
                scrollBy(0, verticalScrollBar()->pageStep());
            else
                scrollBy(horizontalScrollBar()->pageStep(), 0);
        }
        else
        {
            if (d->orientation ==TQt::Vertical)
                scrollBy(0, verticalScrollBar()->lineStep());
            else
                scrollBy(horizontalScrollBar()->lineStep(), 0);
        }
    }

    if (e->delta() > 0)
    {
        if (e->state() & TQt::ShiftButton)
        {
            if (d->orientation ==TQt::Vertical)
                scrollBy(0, (-1)*verticalScrollBar()->pageStep());
            else
                scrollBy((-1)*horizontalScrollBar()->pageStep(), 0);
        }
        else
        {
            if (d->orientation ==TQt::Vertical)
                scrollBy(0, (-1)*verticalScrollBar()->lineStep());
            else
                scrollBy((-1)*horizontalScrollBar()->lineStep(), 0);
        }
    }
}

void ThumbBarView::startDrag()
{
}

void ThumbBarView::insertItem(ThumbBarItem* item)
{
    if (!item) return;

    if (!d->firstItem)
    {
        d->firstItem = item;
        d->lastItem  = item;
        item->d->prev = 0;
        item->d->next = 0;
    }
    else
    {
        d->lastItem->d->next = item;
        item->d->prev = d->lastItem;
        item->d->next = 0;
        d->lastItem = item;

    }

    if (!d->currItem)
    {
        d->currItem = item;
        emit signalURLSelected(item->url());
        emit signalItemSelected(item);
    }

    d->itemDict.insert(item->url().url(), item);

    d->count++;
    triggerUpdate();
    emit signalItemAdded();
}

void ThumbBarView::removeItem(ThumbBarItem* item)
{
    if (!item) return;

    d->count--;

    if (item == d->firstItem)
    {
        d->firstItem = d->currItem = d->firstItem->d->next;
        if (d->firstItem)
            d->firstItem->d->prev = 0;
        else
            d->firstItem = d->lastItem = d->currItem = 0;
    }
    else if (item == d->lastItem)
    {
        d->lastItem = d->currItem = d->lastItem->d->prev;
        if ( d->lastItem )
           d->lastItem->d->next = 0;
        else
            d->firstItem = d->lastItem = d->currItem = 0;
    }
    else
    {
        ThumbBarItem *i = item;
        if (i)
        {
            if (i->d->prev )
            {
                i->d->prev->d->next = d->currItem = i->d->next;
            }
            if ( i->d->next )
            {
                i->d->next->d->prev = d->currItem = i->d->prev;
            }
        }
    }

    d->itemDict.remove(item->url().url());

    if (!d->clearing)
    {
        triggerUpdate();
    }

    if (d->count == 0)
        emit signalItemSelected(0);
}

void ThumbBarView::rearrangeItems()
{
    KURL::List urlList;

    int pos = 0;
    ThumbBarItem *item = d->firstItem;

    while (item)
    {
        item->d->pos = pos;
        pos += d->tileSize + 2*d->margin;
        if (!(item->d->pixmap))
            urlList.append(item->d->url);
        item = item->d->next;
    }

    if (d->orientation ==TQt::Vertical)
       resizeContents(visibleWidth(), d->count*(d->tileSize+2*d->margin));
    else    
       resizeContents(d->count*(d->tileSize+2*d->margin), visibleHeight());

    if (!urlList.isEmpty())
    {
        if (!d->thumbJob.isNull())
        {
           d->thumbJob->kill();
           d->thumbJob = 0;
        }

        d->thumbJob = new ThumbnailJob(urlList, ThumbnailSize::Huge, true, d->exifRotate);

        connect(d->thumbJob, TQ_SIGNAL(signalThumbnail(const KURL&, const TQPixmap&)),
                this, TQ_SLOT(slotGotThumbnail(const KURL&, const TQPixmap&)));

        connect(d->thumbJob, TQ_SIGNAL(signalFailed(const KURL&)),
                this, TQ_SLOT(slotFailedThumbnail(const KURL&)));
    }
}

void ThumbBarView::repaintItem(ThumbBarItem* item)
{
    if (item)
    {
       if (d->orientation ==TQt::Vertical)
           repaintContents(0, item->d->pos, visibleWidth(), d->tileSize+2*d->margin);
       else
           repaintContents(item->d->pos, 0, d->tileSize+2*d->margin, visibleHeight());
    }
}

void ThumbBarView::slotUpdate()
{
    rearrangeItems();
    viewport()->update();
}

void ThumbBarView::slotGotThumbnail(const KURL& url, const TQPixmap& pix)
{
    if (!pix.isNull())
    {
        ThumbBarItem* item = d->itemDict.find(url.url());
        if (!item)
            return;

        if (item->d->pixmap)
        {
            delete item->d->pixmap;
            item->d->pixmap = 0;
        }

        item->d->pixmap = new TQPixmap(pix);
        item->repaint();
    }
}

void ThumbBarView::slotFailedThumbnail(const KURL& url)
{
    ThumbBarItem* item = d->itemDict.find(url.url());
    if (!item)
        return;

    TDEIconLoader* iconLoader = TDEApplication::kApplication()->iconLoader();
    TQPixmap pix = iconLoader->loadIcon("image-x-generic", TDEIcon::NoGroup, ThumbnailSize::Huge);

    if (item->d->pixmap)
    {
        delete item->d->pixmap;
        item->d->pixmap = 0;
    }

    item->d->pixmap = new TQPixmap(pix);
    item->repaint();
}

// -------------------------------------------------------------------------

ThumbBarItem::ThumbBarItem(ThumbBarView* view, const KURL& url)
{
    d = new ThumbBarItemPriv;
    d->url  = url;
    d->view = view;
    d->view->insertItem(this);
}

ThumbBarItem::~ThumbBarItem()
{
    d->view->removeItem(this);

    if (d->pixmap)
        delete d->pixmap;

    delete d;
}

KURL ThumbBarItem::url() const
{
    return d->url;
}

ThumbBarItem* ThumbBarItem::next() const
{
    return d->next;
}

ThumbBarItem* ThumbBarItem::prev() const
{
    return d->prev;
}

TQRect ThumbBarItem::rect() const
{
    if (d->view->d->orientation == ThumbBarView::Vertical)
    {
        return TQRect(0, d->pos,
                     d->view->visibleWidth(),
                     d->view->d->tileSize + 2*d->view->d->margin);
    }
    else
    {
        return TQRect(d->pos, 0,
                     d->view->d->tileSize + 2*d->view->d->margin,
                     d->view->visibleHeight());
    }
}

int ThumbBarItem::position() const
{
    return d->pos;
}

TQPixmap* ThumbBarItem::pixmap() const
{
    return d->pixmap;
}

void ThumbBarItem::repaint()
{
    d->view->repaintItem(this);   
}

// -------------------------------------------------------------------------

ThumbBarToolTip::ThumbBarToolTip(ThumbBarView* parent)
               : TQToolTip(parent->viewport()), m_maxStringLen(30), m_view(parent)
{
    m_headBeg = TQString("<tr bgcolor=\"orange\"><td colspan=\"2\">"
                        "<nobr><font size=\"-1\" color=\"black\"><b>");
    m_headEnd = TQString("</b></font></nobr></td></tr>");

    m_cellBeg = TQString("<tr><td><nobr><font size=\"-1\" color=\"black\">");
    m_cellMid = TQString("</font></nobr></td>"
                        "<td><nobr><font size=\"-1\" color=\"black\">");
    m_cellEnd = TQString("</font></nobr></td></tr>");

    m_cellSpecBeg = TQString("<tr><td><nobr><font size=\"-1\" color=\"black\">");
    m_cellSpecMid = TQString("</font></nobr></td>"
                            "<td><nobr><font size=\"-1\" color=\"steelblue\"><i>");
    m_cellSpecEnd = TQString("</i></font></nobr></td></tr>");
}

void ThumbBarToolTip::maybeTip(const TQPoint& pos)
{
    if ( !parentWidget() || !m_view) return;

    ThumbBarItem* item = m_view->findItem( m_view->viewportToContents(pos) );
    if (!item) return;

    if (!m_view->getToolTipSettings().showToolTips) return;

    TQString tipText = tipContent(item);
    tipText.append(tipContentExtraData(item));
    tipText.append("</table>");

    TQRect r(item->rect());
    r = TQRect( m_view->contentsToViewport(r.topLeft()), r.size() );

    tip(r, tipText);
}

TQString ThumbBarToolTip::tipContent(ThumbBarItem* item)
{
    ThumbBarToolTipSettings settings = m_view->getToolTipSettings();

    TQString tipText, str;
    TQString unavailable(i18n("unavailable"));

    tipText = "<table cellspacing=\"0\" cellpadding=\"0\" width=\"250\" border=\"0\">";

    TQFileInfo fileInfo(item->url().path());

    KFileItem fi(KFileItem::Unknown, KFileItem::Unknown, item->url());
    DMetadata metaData(item->url().path());

    // -- File properties ----------------------------------------------

    if (settings.showFileName  ||
        settings.showFileDate  ||
        settings.showFileSize  ||
        settings.showImageType ||
        settings.showImageDim)
    {
        tipText += m_headBeg + i18n("File Properties") + m_headEnd;

        if (settings.showFileName)
        {
            tipText += m_cellBeg + i18n("Name:") + m_cellMid;
            tipText += item->url().fileName() + m_cellEnd;
        }

        if (settings.showFileDate)
        {
            TQDateTime modifiedDate = fileInfo.lastModified();
            str = TDEGlobal::locale()->formatDateTime(modifiedDate, true, true);
            tipText += m_cellBeg + i18n("Modified:") + m_cellMid + str + m_cellEnd;
        }

        if (settings.showFileSize)
        {
            tipText += m_cellBeg + i18n("Size:") + m_cellMid;
            str = i18n("%1 (%2)").arg(TDEIO::convertSize(fi.size()))
                                .arg(TDEGlobal::locale()->formatNumber(fi.size(), 0));
            tipText += str + m_cellEnd;
        }

        TQSize   dims;
#if KDCRAW_VERSION < 0x000106
        TQString rawFilesExt(KDcrawIface::DcrawBinary::instance()->rawFiles());
#else
        TQString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
#endif
        TQString ext = fileInfo.extension(false).upper();

        if (!ext.isEmpty() && rawFilesExt.upper().contains(ext))
        {
            str = i18n("RAW Image");
            dims = metaData.getImageDimensions();
        }
        else
        {
            str = fi.mimeComment();

            KFileMetaInfo meta = fi.metaInfo();
            if (meta.isValid())
            {
                if (meta.containsGroup("Jpeg EXIF Data"))
                    dims = meta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
                else if (meta.containsGroup("General"))
                    dims = meta.group("General").item("Dimensions").value().toSize();
                else if (meta.containsGroup("Technical"))
                    dims = meta.group("Technical").item("Dimensions").value().toSize();
            }
        }

        if (settings.showImageType)
        {
            tipText += m_cellBeg + i18n("Type:") + m_cellMid + str + m_cellEnd;
        }

        if (settings.showImageDim)
        {
            TQString mpixels;
            mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2);
            str = (!dims.isValid()) ? i18n("Unknown") : i18n("%1x%2 (%3Mpx)")
                .arg(dims.width()).arg(dims.height()).arg(mpixels);
            tipText += m_cellBeg + i18n("Dimensions:") + m_cellMid + str + m_cellEnd;
        }
    }

    // -- Photograph Info ----------------------------------------------------
    
    if (settings.showPhotoMake  ||
        settings.showPhotoDate  ||
        settings.showPhotoFocal ||
        settings.showPhotoExpo  ||
        settings.showPhotoMode  ||
        settings.showPhotoFlash ||
        settings.showPhotoWB)
    {
        PhotoInfoContainer photoInfo = metaData.getPhotographInformations();

        if (!photoInfo.isEmpty())
        {
            TQString metaStr;
            tipText += m_headBeg + i18n("Photograph Properties") + m_headEnd;

            if (settings.showPhotoMake)
            {
                str = TQString("%1 / %2").arg(photoInfo.make.isEmpty() ? unavailable : photoInfo.make)
                                        .arg(photoInfo.model.isEmpty() ? unavailable : photoInfo.model);
                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("Make/Model:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            if (settings.showPhotoDate)
            {
                if (photoInfo.dateTime.isValid())
                {
                    str = TDEGlobal::locale()->formatDateTime(photoInfo.dateTime, true, true);
                    if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                    metaStr += m_cellBeg + i18n("Created:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
                }
                else
                    metaStr += m_cellBeg + i18n("Created:") + m_cellMid + TQStyleSheet::escape( unavailable ) + m_cellEnd;
            }

            if (settings.showPhotoFocal)
            {
                str = photoInfo.aperture.isEmpty() ? unavailable : photoInfo.aperture;

                if (photoInfo.focalLength35mm.isEmpty())
                    str += TQString(" / %1").arg(photoInfo.focalLength.isEmpty() ? unavailable : photoInfo.focalLength);
                else 
                    str += TQString(" / %1").arg(i18n("%1 (35mm: %2)").arg(photoInfo.focalLength).arg(photoInfo.focalLength35mm));

                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("Aperture/Focal:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            if (settings.showPhotoExpo)
            {
                str = TQString("%1 / %2").arg(photoInfo.exposureTime.isEmpty() ? unavailable : photoInfo.exposureTime)
                                        .arg(photoInfo.sensitivity.isEmpty() ? unavailable : i18n("%1 ISO").arg(photoInfo.sensitivity));
                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("Exposure/Sensitivity:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            if (settings.showPhotoMode)
            {

                if (photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
                    str = unavailable;
                else if (!photoInfo.exposureMode.isEmpty() && photoInfo.exposureProgram.isEmpty())
                    str = photoInfo.exposureMode;
                else if (photoInfo.exposureMode.isEmpty() && !photoInfo.exposureProgram.isEmpty())
                    str = photoInfo.exposureProgram;
                else 
                    str = TQString("%1 / %2").arg(photoInfo.exposureMode).arg(photoInfo.exposureProgram);
                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("Mode/Program:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            if (settings.showPhotoFlash)
            {
                str = photoInfo.flash.isEmpty() ? unavailable : photoInfo.flash;
                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("Flash:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            if (settings.showPhotoWB)
            {
                str = photoInfo.whiteBalance.isEmpty() ? unavailable : photoInfo.whiteBalance;
                if (str.length() > m_maxStringLen) str = str.left(m_maxStringLen-3) + "...";
                metaStr += m_cellBeg + i18n("White Balance:") + m_cellMid + TQStyleSheet::escape( str ) + m_cellEnd;
            }

            tipText += metaStr;
        }
    }

    return tipText;
}

TQString ThumbBarToolTip::breakString(const TQString& input)
{
    TQString str = input.simplifyWhiteSpace();
    str = TQStyleSheet::escape(str);
    const uint maxLen = m_maxStringLen;

    if (str.length() <= maxLen)
        return str;

    TQString br;

    uint i     = 0;
    uint count = 0;

    while (i < str.length())
    {
        if (count >= maxLen && str[i].isSpace())
        {
            count = 0;
            br.append("<br>");
        }
        else
        {
            br.append(str[i]);
        }

        i++;
        count++;
    }

    return br;
}

}  // NameSpace Digikam
