/*  Gwenview - A simple image viewer for TDE
    Copyright 2000-2004 Aurélien Gâteau
    This class is based on the TDEIconViewItem class from KDE libs.
    Original copyright follows.
*/
/* This file is part of the KDE libraries
   Copyright (C) 1999 Torben Weis <weis@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/
// TQt includes
#include <tqapplication.h>
#include <tqcolor.h>
#include <tqpainter.h>
#include <tqpen.h>
#include <tqpixmap.h>

// KDE includes
#include <kdebug.h>
#include <kwordwrap.h>
#include <kurldrag.h>

// Our includes
#include "archive.h"
#include "filethumbnailview.h"
#include "filethumbnailviewitem.h"
#include "fileviewconfig.h"
#include "timeutils.h"

namespace Gwenview {

const int SHOWN_ITEM_INDICATOR_SIZE = 8;

#if 0
static void printRect(const TQString& txt,const TQRect& rect) {
	kdWarning() << txt << " : " << rect.x() << "x" << rect.y() << " " << rect.width() << "x" << rect.height() << endl;
}
#endif


/**
 * An helper class to handle a caption line and help drawing it
 */
class FileThumbnailViewItem::Line {
protected:
	const TQIconViewItem* mItem;
	TQString mTxt;
	int mWidth;
public:
	Line(const TQIconViewItem* item, const TQString& txt)
	: mItem(item)
	, mTxt(txt)
	, mWidth(-1) {
	}
	virtual ~Line() {}

	virtual void setWidth(int width) {
		mWidth=width;
	}
	
	virtual int height() const=0;
	
	void paint(TQPainter* p, int textX, int textY, int align) const {
		Q_ASSERT(mWidth!=-1);
		int length=fontMetrics().width(mTxt);
		if (length<=mWidth ) {
			p->drawText(
				textX,
				textY,
				mWidth,
				fontMetrics().height(),
				align,
				mTxt);
		} else {
			p->save();
			complexPaint(p, textX, textY, align);
			p->restore();
		}
	};

protected:
	const FileThumbnailView* view() const {
		return static_cast<const FileThumbnailView*>(mItem->iconView());
	}

	TQFontMetrics fontMetrics() const {
		return view()->fontMetrics();
	}

	/**
	 * Called when the text won't fit the available space
	 */
	virtual void complexPaint(TQPainter* p, int textX, int textY, int align) const=0;
};


/**
 * A line which will get cropped if necessary
 */
class FileThumbnailViewItem::CroppedLine : public FileThumbnailViewItem::Line {
public:
	CroppedLine(const TQIconViewItem* item, const TQString& txt)
	: Line(item, txt) {}

	int height() const {
		return fontMetrics().height();
	}

	void complexPaint(TQPainter* p, int textX, int textY, int /*align*/) const {
		KWordWrap::drawFadeoutText(p,
			textX,
			textY + fontMetrics().ascent(),
			mWidth,
			mTxt);
	}
};

/**
 * A line which will get wrapped if necessary
 */

class FileThumbnailViewItem::WrappedLine : public FileThumbnailViewItem::Line {
	KWordWrap* mWordWrap;
public:
	WrappedLine(const TQIconViewItem* item, const TQString& txt)
	: Line(item, txt)
	, mWordWrap(0) {}

	~WrappedLine() {
		delete mWordWrap;
	}

	int height() const {
		Q_ASSERT(mWordWrap);
		if (!mWordWrap) return 0;
		return mWordWrap->boundingRect().height();
	}

	/**
	 * Regenerates mWordWrap if the width has changed
	 */
	void setWidth(int width) {
		if (width==mWidth) return;
		mWidth=width;
		delete mWordWrap;
		TQFontMetrics fm=fontMetrics();
		mWordWrap=KWordWrap::formatText(fm,
			TQRect(0, 0, mWidth, fm.height()*3),
			0 /*flags*/,
			mTxt);
	}

	void complexPaint(TQPainter* p, int textX, int textY, int align) const {
		Q_ASSERT(mWordWrap);
		if (!mWordWrap) return;

		int xpos=0;
		if (align & AlignHCenter) {
			xpos=( mWidth - mWordWrap->boundingRect().width() ) / 2;
		}
		
		mWordWrap->drawText(p, 
			textX + xpos,
			textY,
			align);
	}
};


FileThumbnailViewItem::FileThumbnailViewItem(TQIconView* view,const TQString& text,const TQPixmap& icon, KFileItem* fileItem)
: TQIconViewItem(view,text,icon), mFileItem(fileItem) {
	updateLines();
	calcRect();
}


FileThumbnailViewItem::~FileThumbnailViewItem() {
	TQValueVector<Line*>::ConstIterator it=mLines.begin();
	TQValueVector<Line*>::ConstIterator itEnd=mLines.end();
	for (;it!=itEnd; ++it) {
		delete *it;
	}
}


void FileThumbnailViewItem::updateLines() {
	TQValueVector<Line*>::ConstIterator it=mLines.begin();
	TQValueVector<Line*>::ConstIterator itEnd=mLines.end();
	for (;it!=itEnd; ++it) {
		delete *it;
	}
	mLines.clear();
	if (!mFileItem) return;

	bool showName, showDate, showImageSize, showFilesize;

	bool isDir=mFileItem->isDir();

	if (iconView()->itemTextPos()==TQIconView::Right) {
		// Text is on the right, show everything
		showName = true;
		showDate = true;
		showImageSize = true;
		showFilesize = !isDir;
	} else {
		// Text is below the icon, only show details selected in
		// view->itemDetails()
		FileThumbnailView *view=static_cast<FileThumbnailView*>(iconView());
		int details=view->itemDetails();
		bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem);

		showName      = !isImage || ( details & FileThumbnailView::FILENAME  );
		showDate      =             ( details & FileThumbnailView::FILEDATE  );
		showImageSize =             ( details & FileThumbnailView::IMAGESIZE );
		showFilesize  = !isDir   && ( details & FileThumbnailView::FILESIZE  );
	}

	if (showName) {
		mLines.append( new WrappedLine(this, mFileItem->name()) );
	}
	if (showDate) {
		time_t time = TimeUtils::getTime(mFileItem);
		mLines.append( new CroppedLine(this, TimeUtils::formatTime(time)) );
	}
	if (showImageSize) {
		TQSize sz;
		if (mImageSize.isValid()) {
			sz=mImageSize;
		} else if (FileViewConfig::loadMetadata()) {
			const KFileMetaInfo& info = mFileItem->metaInfo(/*autogen=*/false);
			if (info.isValid()) {
				sz = info.value("Dimensions").toSize();
			}
		}
		if (sz.isValid()) {
			TQString txt = TQString::number(sz.width())+"x"+TQString::number(sz.height());
			mLines.append( new CroppedLine(this, txt) );
		} else if (iconView()->itemTextPos()==TQIconView::Right) {
			// add empty line for they would nicely alligned;
			// for text at the bottom it doesn't look that nice
			mLines.append( new CroppedLine(this, TQString()));
		}
	}
	if (showFilesize) {
		mLines.append( new CroppedLine(this, TDEIO::convertSize(mFileItem->size())) );
	}

	calcRect();
}


void FileThumbnailViewItem::calcRect(const TQString&) {
	FileThumbnailView *view=static_cast<FileThumbnailView*>(iconView());
	bool isRight=view->itemTextPos()==TQIconView::Right;
	
	int textW=view->gridX();
	int thumbnailSize=FileViewConfig::thumbnailSize();
	if (isRight) {
		textW-=PADDING * 3 + thumbnailSize;
	} else {
		textW-=PADDING * 2;
	}
	
	int textH=0;
	TQValueVector<Line*>::ConstIterator it=mLines.begin();
	TQValueVector<Line*>::ConstIterator itEnd=mLines.end();
	for (;it!=itEnd; ++it) {
		(*it)->setWidth(textW);
		textH+=(*it)->height();
	}
	
	TQRect itemRect(x(), y(), view->gridX(), 0);
	TQRect itemPixmapRect(PADDING, PADDING, thumbnailSize, thumbnailSize);
	TQRect itemTextRect(0, 0, textW, textH);
	if (isRight) {
		itemRect.setHeight( TQMAX(thumbnailSize + PADDING*2, textH) );
		itemTextRect.moveLeft(thumbnailSize + PADDING * 2 );
		itemTextRect.moveTop((itemRect.height() - textH)/2);
	} else {
		itemPixmapRect.moveLeft( (itemRect.width() - itemPixmapRect.width()) / 2 );
		itemRect.setHeight(thumbnailSize + PADDING*3 + textH);
		itemTextRect.moveLeft(PADDING);
		itemTextRect.moveTop(thumbnailSize + PADDING * 2);
	}

	// Update rects
	// NOTE: this results in 3 calls to TQIconViewContainer(), which is costly if
	//       there are a lot (tens of thousands) of items, unfortunately there
	//       is no way to workaround this in current (14.1.1, 2024) TQt API
	if ( itemPixmapRect != pixmapRect() ) {
		setPixmapRect( itemPixmapRect );
	}
	if ( itemTextRect != textRect() ) {
		setTextRect( itemTextRect );
	}
	if ( itemRect != rect() ) {
		setItemRect( itemRect );
	}
}


void FileThumbnailViewItem::paintItem(TQPainter *p, const TQColorGroup &cg) {
	FileThumbnailView *view=static_cast<FileThumbnailView*>(iconView());
	Q_ASSERT(view);
	if (!view) return;

	bool isRight=view->itemTextPos()==TQIconView::Right;
	bool isShownItem=view->shownFileItem() && view->shownFileItem()->extraData(view)==this;
	bool isImage=!Archive::fileItemIsDirOrArchive(mFileItem);
	int textX, textY;
	int thumbnailSize=FileViewConfig::thumbnailSize();

	textX=textRect(false).x();
	textY=textRect(false).y();

	// Draw pixmap
	TQRect pRect = pixmapRect(false);
	int pixX = pRect.left() + ( thumbnailSize - pixmap()->width() ) / 2;
	int pixY = pRect.top() + ( thumbnailSize - pixmap()->height() ) / 2;
	p->drawPixmap( pixX, pixY, *pixmap() );

	TQColor bg;
	if ( isSelected() ) {
		bg=cg.highlight();
	} else {
		bg=cg.mid();
	}
	
	// Draw shown item indicator
	if (isShownItem) {
		TQPointArray pa(3);
		pa[0] = pixmapRect(false).bottomLeft();
		pa[0].rx() += pixmapRect(false).width() / 2;
		pa[0].ry() += PADDING - 1;
		pa[0].ry() -= SHOWN_ITEM_INDICATOR_SIZE;
		
		pa[1] = pa[0];
		pa[1].rx() -= SHOWN_ITEM_INDICATOR_SIZE;
		pa[1].ry() += SHOWN_ITEM_INDICATOR_SIZE;

		pa[2] = pa[1];
		pa[2].rx() += SHOWN_ITEM_INDICATOR_SIZE * 2;
		
		p->setBrush(cg.highlight());
		p->setPen(cg.base());
		p->drawPolygon(pa);
	}
	
	if (isImage || isSelected()) {
		// Draw frame
		TQRect frmRect=pixmapRect(false);
		frmRect.addCoords(-PADDING, -PADDING, PADDING, PADDING);
		
		p->setBrush(TQBrush());
		p->setPen(bg);
		p->drawRect(frmRect);
		if (isSelected()) {
			frmRect.addCoords(1, 1, -1, -1);
			p->drawRect(frmRect);
		}
	}

	// Draw text
	p->setPen(cg.text());
	p->setBackgroundColor(cg.base());
	int align = (isRight ? AlignAuto : AlignHCenter) | AlignTop;
	
	TQValueVector<Line*>::ConstIterator it=mLines.begin();
	TQValueVector<Line*>::ConstIterator itEnd=mLines.end();
	for (;it!=itEnd; ++it) {
		const Line* line=*it;
		line->paint(p, textX, textY, align);
		textY+=line->height();
	}
}


bool FileThumbnailViewItem::acceptDrop(const TQMimeSource* source) const {
	return KURLDrag::canDecode(source);
}


void FileThumbnailViewItem::dropped(TQDropEvent* event, const TQValueList<TQIconDragItem>&) {
	FileThumbnailView *view=static_cast<FileThumbnailView*>(iconView());
	emit view->dropped(event,mFileItem);
}

void FileThumbnailViewItem::setImageSize(const TQSize& size) {
	mImageSize=size;
	updateLines();
}

} // namespace
