/***************************************************************************
 *   Copyright (C) 2003 by S�astien Laot                                 *
 *   slaout@linux62.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "basketlistview.h"
#include <tqregexp.h>
#include <tdeglobalsettings.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <kstringhandler.h>
#include <tqpainter.h>
#include <tqbitmap.h>
#include <tqpixmapcache.h>
#include <tqtooltip.h>
#include <iostream>
#include <kdebug.h>
#include "global.h"
#include "bnpview.h"
#include "basket.h"
#include "tools.h"
#include "settings.h"
#include "notedrag.h"

/** class BasketListViewItem: */

BasketListViewItem::BasketListViewItem(TQListView *parent, Basket *basket)
	: TQListViewItem(parent), m_basket(basket)
	, m_isUnderDrag(false)
	, m_isAbbreviated(false)
{
	setDropEnabled(true);
}

BasketListViewItem::BasketListViewItem(TQListViewItem *parent, Basket *basket)
	: TQListViewItem(parent), m_basket(basket)
	, m_isUnderDrag(false)
	, m_isAbbreviated(false)
{
	setDropEnabled(true);
}

BasketListViewItem::BasketListViewItem(TQListView *parent, TQListViewItem *after, Basket *basket)
	: TQListViewItem(parent, after), m_basket(basket)
	, m_isUnderDrag(false)
	, m_isAbbreviated(false)
{
	setDropEnabled(true);
}

BasketListViewItem::BasketListViewItem(TQListViewItem *parent, TQListViewItem *after, Basket *basket)
	: TQListViewItem(parent, after), m_basket(basket)
	, m_isUnderDrag(false)
	, m_isAbbreviated(false)
{
	setDropEnabled(true);
}

BasketListViewItem::~BasketListViewItem()
{
}

bool BasketListViewItem::acceptDrop(const TQMimeSource *) const
{
	std::cout << "accept" << std::endl;
	return true;
}

void BasketListViewItem::dropped(TQDropEvent *event)
{
	std::cout << "Dropping into basket " << m_basket->name() << std::endl;
	m_basket->contentsDropEvent(event);
	//Global::bnpView->currentBasket()->contentsDropEvent(event); // FIXME
}

int BasketListViewItem::width(const TQFontMetrics &/* fontMetrics */, const TQListView */*listView*/, int /* column */) const
{
	return listView()->visibleWidth() + 100;
/*
	int BASKET_ICON_SIZE = 16;
	int MARGIN = 1;

	TQRect textRect = fontMetrics.boundingRect(0, 0, / *width=* /1, 500000, TQt::AlignAuto | TQt::AlignTop | TQt::ShowPrefix, text(column));

	return MARGIN + BASKET_ICON_SIZE + MARGIN + textRect.width() +   BASKET_ICON_SIZE/2   + MARGIN;
*/
}

TQString BasketListViewItem::escapedName(const TQString &string)
{
	// Underlining the Alt+Letter shortcut (and escape all other '&' characters), if any:
	TQString basketName = string;
	basketName.replace('&', "&&"); // First escape all the amperstamp
	TQString letter; // Find the letter
	TQString altKey   = /*i18n(*/"Alt"/*)*/;   //i18n("The [Alt] key, as shown in shortcuts like Alt+C...", "Alt");
	TQString shiftKey = /*i18n(*/"Shift"/*)*/; //i18n("The [Shift] key, as shown in shortcuts like Alt+Shift+1...", "Shift");
	TQRegExp altLetterExp(      TQString("^%1\\+(.)$").arg(altKey)                );
	TQRegExp altShiftLetterExp( TQString("^%1\\+%2\\+(.)$").arg(altKey, shiftKey) );
	if (altLetterExp.search(m_basket->shortcut().toStringInternal()) != -1)
		letter = altLetterExp.cap(1);
	if (letter.isEmpty() && altShiftLetterExp.search(m_basket->shortcut().toStringInternal()) != -1)
		letter = altShiftLetterExp.cap(1);
	if (!letter.isEmpty()) {
		int index = basketName.find(letter, /*index=*/0, /*caseSensitive=*/false);
		if (index != -1)
			basketName.insert(index, '&');
	}
	return basketName;
}

void BasketListViewItem::setup()
{
	int BASKET_ICON_SIZE = 16;
	int MARGIN = 1;

	setText(/*column=*/0, escapedName(m_basket->basketName()));

	widthChanged();
	TQRect textRect = listView()->fontMetrics().boundingRect(0, 0, /*width=*/1, 500000, TQt::AlignAuto | TQt::AlignTop | TQt::ShowPrefix, text(/*column=*/0));

	int height = MARGIN + TQMAX(BASKET_ICON_SIZE, textRect.height()) + MARGIN;
	setHeight(height);

	TQPixmap icon = kapp->iconLoader()->loadIcon(m_basket->icon(), TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0L, /*canReturnNull=*/false);

	setPixmap(/*column=*/0, icon);

	repaint();
}

BasketListViewItem* BasketListViewItem::lastChild()
{
	TQListViewItem *child = firstChild();
	while (child) {
		if (child->nextSibling())
			child = child->nextSibling();
		else
			return (BasketListViewItem*)child;
	}
	return 0;
}

BasketListViewItem* BasketListViewItem::prevSibling()
{
	BasketListViewItem *item = this;
	while (item) {
		if (item->nextSibling() == this)
			return item;
		item = (BasketListViewItem*)(item->itemAbove());
	}
	return 0;
}

BasketListViewItem* BasketListViewItem::shownItemAbove()
{
	BasketListViewItem *item = (BasketListViewItem*)itemAbove();
	while (item) {
		if (item->isShown())
			return item;
		item = (BasketListViewItem*)(item->itemAbove());
	}
	return 0;
}

BasketListViewItem* BasketListViewItem::shownItemBelow()
{
	BasketListViewItem *item = (BasketListViewItem*)itemBelow();
	while (item) {
		if (item->isShown())
			return item;
		item = (BasketListViewItem*)(item->itemBelow());
	}
	return 0;
}

TQStringList BasketListViewItem::childNamesTree(int deep)
{
	TQStringList result;
	for (TQListViewItem *child = firstChild(); child; child = child->nextSibling()) {
		BasketListViewItem *item = (BasketListViewItem*)child;
		// Compute indentation spaces:
		TQString spaces;
		for (int i = 0; i < deep; ++i)
			spaces += "  ";
		// Append the name:
		result.append(spaces + item->basket()->basketName());
		// Append the childs:
		if (child->firstChild()) {
			TQStringList childs = item->childNamesTree(deep + 1);
			for (TQStringList::iterator it = childs.begin(); it != childs.end(); ++it)
				result.append(*it);
		}
	}
	return result;
}

void BasketListViewItem::moveChildsBaskets()
{
	TQListViewItem *insertAfterThis = this;
	TQListViewItem *nextOne;
	for (TQListViewItem *child = firstChild(); child; child = nextOne) {
		nextOne = child->nextSibling();
		// Re-insert the item with the good parent:
		takeItem(child);
		if (parent())
			parent()->insertItem(child);
		else
			listView()->insertItem(child);
		// And move it at the good place:
		child->moveItem(insertAfterThis);
		insertAfterThis = child;
	}
}

void BasketListViewItem::ensureVisible()
{
	BasketListViewItem *item = this;
	while (item->parent()) {
		item = (BasketListViewItem*)(item->parent());
		item->setOpen(true);
	}
}

bool BasketListViewItem::isShown()
{
	TQListViewItem *item = parent();
	while (item) {
		if (!item->isOpen())
			return false;
		item = item->parent();
	}
	return true;
}

bool BasketListViewItem::isCurrentBasket()
{
	return basket() == Global::bnpView->currentBasket();
}

// TODO: Move this function from item.cpp to class Tools:
extern void drawGradient( TQPainter *p, const TQColor &colorTop, const TQColor & colorBottom,
						  int x, int y, int w, int h,
						  bool sunken, bool horz, bool flat  ); /*const*/

TQPixmap BasketListViewItem::circledTextPixmap(const TQString &text, int height, const TQFont &font, const TQColor &color)
{
	TQString key = TQString("BLI-%1.%2.%3.%4")
		.arg(text).arg(height).arg(font.toString()).arg(color.rgb());
	if (TQPixmap* cached=TQPixmapCache::find(key)) {
		return *cached;
	}

	// Compute the sizes of the image components:
	TQRect textRect = TQFontMetrics(font).boundingRect(0, 0, /*width=*/1, height, TQt::AlignAuto | TQt::AlignTop, text);
	int xMargin = height / 6;
	int width   = xMargin + textRect.width() + xMargin;

	// Create the gradient image:
	TQPixmap gradient(3 * width, 3 * height); // We double the size to be able to smooth scale down it (== antialiased curves)
	TQPainter gradientPainter(&gradient);
#if 1 // Enable the new look of the gradient:
	TQColor topColor       = TDEGlobalSettings::highlightColor().light(130); //120
	TQColor topMidColor    = TDEGlobalSettings::highlightColor().light(105); //105
	TQColor bottomMidColor = TDEGlobalSettings::highlightColor().dark(130);  //120
	TQColor bottomColor    = TDEGlobalSettings::highlightColor();
	drawGradient(&gradientPainter, topColor, topMidColor,
				  0, 0, gradient.width(), gradient.height() / 2, /*sunken=*/false, /*horz=*/true, /*flat=*/false);
	drawGradient(&gradientPainter, bottomMidColor, bottomColor,
				  0, gradient.height() / 2, gradient.width(), gradient.height() - gradient.height() / 2, /*sunken=*/false, /*horz=*/true, /*flat=*/false);
	gradientPainter.fillRect(0, 0, gradient.width(), 3, TDEGlobalSettings::highlightColor());
#else
	drawGradient(&gradientPainter, TDEGlobalSettings::highlightColor(), TDEGlobalSettings::highlightColor().dark(),
				  0, 0, gradient.width(), gradient.height(), /*sunken=*/false, /*horz=*/true, /*flat=*/false);
#endif
	gradientPainter.end();

	// Draw the curved rectangle:
	TQBitmap curvedRectangle(3 * width, 3 * height);
	curvedRectangle.fill(TQt::color0);
	TQPainter curvePainter(&curvedRectangle);
	curvePainter.setPen(TQt::color1);
	curvePainter.setBrush(TQt::color1);
	curvePainter.setClipRect(0, 0, 3*(height / 5), 3*(height)); // If the width is small, don't fill the right part of the pixmap
	curvePainter.drawEllipse(0, 3*(-height / 4), 3*(height), 3*(height * 3 / 2)); // Don't forget we double the sizes
	curvePainter.setClipRect(3*(width - height / 5), 0, 3*(height / 5), 3*(height));
	curvePainter.drawEllipse(3*(width - height), 3*(-height / 4), 3*(height), 3*(height * 3 / 2));
	curvePainter.setClipping(false);
	curvePainter.fillRect(3*(height / 6), 0, 3*(width - 2 * height / 6), 3*(height), curvePainter.brush());
	curvePainter.end();

	// Apply the curved rectangle as the mask of the gradient:
	gradient.setMask(curvedRectangle);
	TQImage resultImage = gradient.convertToImage();
	resultImage.setAlphaBuffer(true);

	// Scale down the image smoothly to get anti-aliasing:
	TQPixmap pmScaled;
	pmScaled.convertFromImage(resultImage.smoothScale(width, height));

	// Draw the text, and return the result:
	TQPainter painter(&pmScaled);
	painter.setPen(color);
	painter.setFont(font);
	painter.drawText(0+1, 0, width, height, TQt::AlignHCenter | TQt::AlignVCenter, text);
	painter.end();

	TQPixmapCache::insert(key, pmScaled);

	return pmScaled;
}

TQPixmap BasketListViewItem::foundCountPixmap(bool isLoading, int countFound, bool childsAreLoading, int countChildsFound, const TQFont &font, int height)
{
	if (isLoading)
		return TQPixmap();

	TQFont boldFont(font);
	boldFont.setBold(true);

	TQString text;
	if (childsAreLoading) {
		if (countChildsFound > 0)
			text = i18n("%1+%2+").arg(TQString::number(countFound), TQString::number(countChildsFound));
		else
			text = i18n("%1+").arg(TQString::number(countFound));
	} else {
		if (countChildsFound > 0)
			text = i18n("%1+%2").arg(TQString::number(countFound), TQString::number(countChildsFound));
		else if (countFound > 0)
			text = TQString::number(countFound);
		else
			return TQPixmap();
	}

	return circledTextPixmap(text, height, boldFont, TDEGlobalSettings::highlightedTextColor());
}

bool BasketListViewItem::haveChildsLoading()
{
	TQListViewItem *child = firstChild();
	while (child) {
		BasketListViewItem *childItem = (BasketListViewItem*)child;
		if (!childItem->basket()->isLoaded() && !childItem->basket()->isLocked())
			return true;
		if (childItem->haveChildsLoading())
			return true;
		child = child->nextSibling();
	}
	return false;
}

bool BasketListViewItem::haveHiddenChildsLoading()
{
	if (isOpen())
		return false;
	return haveChildsLoading();
}

bool BasketListViewItem::haveChildsLocked()
{
	TQListViewItem *child = firstChild();
	while (child) {
		BasketListViewItem *childItem = (BasketListViewItem*)child;
		if (/*!*/childItem->basket()->isLocked())
			return true;
		if (childItem->haveChildsLocked())
			return true;
		child = child->nextSibling();
	}
	return false;
}

bool BasketListViewItem::haveHiddenChildsLocked()
{
	if (isOpen())
		return false;
	return haveChildsLocked();
}

int BasketListViewItem::countChildsFound()
{
	int count = 0;
	TQListViewItem *child = firstChild();
	while (child) {
		BasketListViewItem *childItem = (BasketListViewItem*)child;
		count += childItem->basket()->countFounds();
		count += childItem->countChildsFound();
		child = child->nextSibling();
	}
	return count;
}

int BasketListViewItem::countHiddenChildsFound()
{
	if (isOpen())
		return 0;
	return countChildsFound();
}

void BasketListViewItem::paintCell(TQPainter *painter, const TQColorGroup &/*colorGroup*/, int /*column*/, int width, int /*align*/)
{
	// Workaround a TQt bug:
	// When the splitter is moved to hide the tree view and then the application is restarted,
	// TQt try to draw items with a negative size!
	if (width <= 0) {
		std::cout << "width <= 0" << std::endl;
		return;
	}

	int BASKET_ICON_SIZE = 16;
	int MARGIN = 1;


	// If we are filtering all baskets, and are effectively filtering on something:
	bool showLoadingIcon = false;
	bool showEncryptedIcon = false;
	TQPixmap countPixmap;
	bool showCountPixmap = Global::bnpView->isFilteringAllBaskets() &&
		Global::bnpView->currentBasket()->decoration()->filterBar()->filterData().isFiltering;
	if (showCountPixmap) {
		showLoadingIcon = (!m_basket->isLoaded() && !m_basket->isLocked()) || haveHiddenChildsLoading();
		showEncryptedIcon = m_basket->isLocked() || haveHiddenChildsLocked();
		countPixmap = foundCountPixmap(!m_basket->isLoaded(), m_basket->countFounds(), haveHiddenChildsLoading() || haveHiddenChildsLocked(),
										countHiddenChildsFound(), listView()->font(), height() - 2 * MARGIN);
	}
	int effectiveWidth = width - (countPixmap.isNull() ? 0 : countPixmap.width() + MARGIN)
			- (showLoadingIcon || showEncryptedIcon ? BASKET_ICON_SIZE + MARGIN : 0)/*
			- (showEncryptedIcon ? BASKET_ICON_SIZE + MARGIN : 0)*/;


	bool drawRoundRect = m_basket->backgroundColorSetting().isValid() || m_basket->textColorSetting().isValid();
	TQColor textColor = (drawRoundRect ? m_basket->textColor() : (isCurrentBasket() ? TDEGlobalSettings::highlightedTextColor() : TDEGlobalSettings::textColor()));

	BasketListViewItem *shownAbove = shownItemAbove();
	BasketListViewItem *shownBelow = shownItemBelow();

	// Don't forget to update the key computation if parameters
	// affecting the rendering logic change
	TQString key = TQString("BLVI::pC-%1.%2.%3.%4.%5.%6.%7.%8.%9.%10.%11.%12.%13.%14.%15")
		.arg(effectiveWidth)
		.arg(drawRoundRect)
		.arg(textColor.rgb())
		.arg(m_basket->backgroundColor().rgb())
		.arg(isCurrentBasket())
		.arg(shownBelow && shownBelow->isCurrentBasket())
		.arg(shownAbove && shownAbove->isCurrentBasket())
		.arg(showLoadingIcon)
		.arg(showEncryptedIcon)
		.arg(showCountPixmap)
		.arg(m_basket->countFounds())
		.arg(countHiddenChildsFound())
		.arg(m_isUnderDrag)
		.arg(m_basket->basketName())
		.arg(m_basket->icon());
	if (TQPixmap* cached = TQPixmapCache::find(key)) {
		// TQt's documentation recommends copying the pointer
		// into a TQPixmap immediately
		TQPixmap cachedBuffer = *cached;
		painter->drawPixmap(0, 0, cachedBuffer);
		return;
	}

	// Bufferize the drawing of items (otherwize, resizing the splitter make the tree act like a Christmas Tree ;-D ):
	TQPixmap theBuffer(width, height());
	TQPainter thePainter(&theBuffer);

	// Fill with the basket background color:
	TQColor background = (isCurrentBasket() ? TDEGlobalSettings::highlightColor() : listView()->paletteBackgroundColor());
	thePainter.fillRect(0, 0, width, height(), background);

	int textWidth = effectiveWidth - MARGIN - BASKET_ICON_SIZE - MARGIN - MARGIN;

	// Draw the rounded rectangle:
	if (drawRoundRect) {
		TQRect textRect = listView()->fontMetrics().boundingRect(0, 0, /*width=*/1, 500000, TQt::AlignAuto | TQt::AlignTop | TQt::ShowPrefix, text(/*column=*/0));
		int xRound = MARGIN;
		int yRound = MARGIN;
		int hRound = height() - 2 * MARGIN;
		int wRound = TQMIN(BASKET_ICON_SIZE + MARGIN + textRect.width() + hRound/2,  effectiveWidth - MARGIN - MARGIN);
		if (wRound > 0) { // Do not crash if there is no space anymore to draw the rounded rectangle:
			TQPixmap buffer(wRound * 2, hRound * 2);
			buffer.fill(background);
			TQPainter pBuffer(&buffer);
			TQColor colorRound = m_basket->backgroundColor();
			pBuffer.setPen(colorRound);
			pBuffer.setBrush(colorRound);
			if (wRound > hRound) { // If the rectangle is smaller in width than in height, don't overlap ellipses...
				pBuffer.drawEllipse(0,                                 0, hRound * 2, hRound * 2);
				pBuffer.drawEllipse(wRound * 2 - hRound * 2, 0, hRound * 2, hRound * 2);
				pBuffer.fillRect(hRound*2/2, 0, wRound * 2 - hRound * 2, hRound * 2, colorRound);
			} else
				pBuffer.drawEllipse(0, 0, wRound * 2, hRound * 2);
				pBuffer.end();
				TQImage imageToScale = buffer.convertToImage();
				TQPixmap pmScaled;
				pmScaled.convertFromImage(imageToScale.smoothScale(wRound, hRound));
				thePainter.drawPixmap(xRound, yRound, pmScaled);
				textWidth -= hRound/2;
		}
	}

	TQColor bgColor  = listView()->paletteBackgroundColor();
	TQColor selColor = TDEGlobalSettings::highlightColor();
	TQColor midColor = Tools::mixColor(bgColor, selColor);
	// Draw the left selection roundings:
	if (isCurrentBasket()) {
		thePainter.setPen(bgColor);
		thePainter.drawPoint(0, 0);
		thePainter.drawPoint(1, 0);
		thePainter.drawPoint(0, 1);
		thePainter.drawPoint(0, height() - 1);
		thePainter.drawPoint(1, height() - 1);
		thePainter.drawPoint(0, height() - 2);
		thePainter.setPen(midColor);
		thePainter.drawPoint(2, 0);
		thePainter.drawPoint(0, 2);
		thePainter.drawPoint(2, height() - 1);
		thePainter.drawPoint(0, height() - 3);
	}
	// Draw the bottom-right selection roundings:
	//BasketListViewItem *shownBelow = shownItemBelow();
	if (shownBelow && shownBelow->isCurrentBasket()) {
		thePainter.setPen(selColor);
		thePainter.drawPoint(width - 1, height() - 1);
		thePainter.drawPoint(width - 2, height() - 1);
		thePainter.drawPoint(width - 1, height() - 2);
		thePainter.setPen(midColor);
		thePainter.drawPoint(width - 3, height() - 1);
		thePainter.drawPoint(width - 1, height() - 3);
	}
	// Draw the top-right selection roundings:
	//	BasketListViewItem *shownAbove = shownItemAbove();
	if (shownAbove && shownAbove->isCurrentBasket()) {
		thePainter.setPen(selColor);
		thePainter.drawPoint(width - 1, 0);
		thePainter.drawPoint(width - 2, 0);
		thePainter.drawPoint(width - 1, 1);
		thePainter.setPen(midColor);
		thePainter.drawPoint(width - 3, 0);
		thePainter.drawPoint(width - 1, 2);
	}

	// Draw the icon and text:
	int yPixmap = (height() - BASKET_ICON_SIZE) / 2;
	thePainter.drawPixmap(MARGIN, yPixmap, *pixmap(/*column=*/0));
	thePainter.setPen(textColor);
	if (textWidth > 0) { // IF there is space left to draw the text:
		int xText = MARGIN + BASKET_ICON_SIZE + MARGIN;
		TQString theText = m_basket->basketName();
		if (painter->fontMetrics().width(theText) > textWidth) {
			theText = KStringHandler::rPixelSqueeze(theText, painter->fontMetrics(), textWidth);
			m_isAbbreviated = true;
		}
		else {
			m_isAbbreviated = false;
		}
		theText = escapedName(theText);
		thePainter.drawText(xText, 0, textWidth, height(), TQt::AlignAuto | TQt::AlignVCenter | TQt::ShowPrefix, theText);
	}

	// If we are filtering all baskets, and are effectively filtering on something:
	if (!countPixmap.isNull())
	{
		thePainter.drawPixmap(effectiveWidth, 1, countPixmap);
		effectiveWidth += countPixmap.width() + MARGIN;
	}
	if (showLoadingIcon) {
		TQPixmap icon = kapp->iconLoader()->loadIcon("edit-find", TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0L, /*canReturnNull=*/false);
		thePainter.drawPixmap(effectiveWidth, 0, icon);
		effectiveWidth += BASKET_ICON_SIZE + MARGIN;
	}
	if (showEncryptedIcon && !showLoadingIcon) {
		TQPixmap icon = kapp->iconLoader()->loadIcon("encrypted", TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0L, /*canReturnNull=*/false);
		thePainter.drawPixmap(effectiveWidth, 0, icon);
	}

	if (m_isUnderDrag) {
		thePainter.drawWinFocusRect(0, 0, width, height());
	}
	thePainter.end();

	TQPixmapCache::insert(key, theBuffer);
	// Apply the buffer:
	painter->drawPixmap(0, 0, theBuffer);
}

void BasketListViewItem::setUnderDrag(bool underDrag)
{
	m_isUnderDrag = underDrag;
}

bool BasketListViewItem::isAbbreviated()
{
	return m_isAbbreviated;
}

/** class BasketListViewToolTip: */

class BasketTreeListView_ToolTip : public TQToolTip {
public:
	BasketTreeListView_ToolTip(BasketTreeListView* basketView)
		: TQToolTip(basketView->viewport())
		, m_basketView(basketView)
	{}
public:
	void maybeTip(const TQPoint& pos)
	{
		TQListViewItem *item = m_basketView->itemAt(m_basketView->contentsToViewport(pos));
		BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
		if (bitem && bitem->isAbbreviated()) {
			tip(m_basketView->itemRect(bitem), bitem->basket()->basketName());
		}
	}
private:
	BasketTreeListView* m_basketView;
};

/** class BasketTreeListView: */

BasketTreeListView::BasketTreeListView(TQWidget *parent, const char *name)
	: TDEListView(parent, name), m_autoOpenItem(0)
	, m_itemUnderDrag(0)
{
	setWFlags(TQt::WStaticContents | WNoAutoErase);
	clearWFlags(TQt::WStaticContents | WNoAutoErase);
	//viewport()->clearWFlags(TQt::WStaticContents);
	connect( &m_autoOpenTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(autoOpen()) );

	new BasketTreeListView_ToolTip(this);
}

void BasketTreeListView::viewportResizeEvent(TQResizeEvent *event)
{
	TDEListView::viewportResizeEvent(event);
	triggerUpdate();
}

void BasketTreeListView::contentsDragEnterEvent(TQDragEnterEvent *event)
{
	if (event->provides("application/x-qlistviewitem")) {
		TQListViewItemIterator it(this); // TODO: Don't show expanders if it's not a basket drag...
		while (it.current()) {
			TQListViewItem *item = it.current();
			if (!item->firstChild()) {
				item->setExpandable(true);
				item->setOpen(true);
			}
			++it;
		}
		update();
	}

	TDEListView::contentsDragEnterEvent(event);
}

void BasketTreeListView::removeExpands()
{
	TQListViewItemIterator it(this);
	while (it.current()) {
		TQListViewItem *item = it.current();
		if (!item->firstChild())
			item->setExpandable(false);
		++it;
	}
	viewport()->update();
}

void BasketTreeListView::contentsDragLeaveEvent(TQDragLeaveEvent *event)
{
	std::cout << "BasketTreeListView::contentsDragLeaveEvent" << std::endl;
	m_autoOpenItem = 0;
	m_autoOpenTimer.stop();
	setItemUnderDrag(0);
	removeExpands();
	TDEListView::contentsDragLeaveEvent(event);
}

void BasketTreeListView::contentsDropEvent(TQDropEvent *event)
{
	std::cout << "BasketTreeListView::contentsDropEvent()" << std::endl;
	if (event->provides("application/x-qlistviewitem"))
	{
		TDEListView::contentsDropEvent(event);
	}
	else {
		std::cout << "Forwarding dropped data to the basket" << std::endl;
		TQListViewItem *item = itemAt(contentsToViewport(event->pos()));
		BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
		if (bitem) {
			bitem->basket()->blindDrop(event);
		}
		else {
			std::cout << "Forwarding failed: no bitem found" << std::endl;
		}
	}

	m_autoOpenItem = 0;
	m_autoOpenTimer.stop();
	setItemUnderDrag(0);
	removeExpands();

	Global::bnpView->save(); // TODO: Don't save if it was not a basket drop...
}

void BasketTreeListView::contentsDragMoveEvent(TQDragMoveEvent *event)
{
	std::cout << "BasketTreeListView::contentsDragMoveEvent" << std::endl;
	if (event->provides("application/x-qlistviewitem"))
		TDEListView::contentsDragMoveEvent(event);
	else {
		TQListViewItem *item = itemAt(contentsToViewport(event->pos()));
		BasketListViewItem* bitem = dynamic_cast<BasketListViewItem*>(item);
		if (m_autoOpenItem != item) {
			m_autoOpenItem = item;
			m_autoOpenTimer.start(1700, /*singleShot=*/true);
		}
		if (item) {
			event->acceptAction(true);
			event->accept(true);
		}
		setItemUnderDrag(bitem);

		TDEListView::contentsDragMoveEvent(event); // FIXME: ADDED
	}
}

void BasketTreeListView::setItemUnderDrag(BasketListViewItem* item)
{
	if (m_itemUnderDrag != item) {
		if (m_itemUnderDrag) {
			// Remove drag status from the old item
			m_itemUnderDrag->setUnderDrag(false);
			repaintItem(m_itemUnderDrag);
		}

		m_itemUnderDrag = item;

		if (m_itemUnderDrag) {
			// add drag status to the new item
			m_itemUnderDrag->setUnderDrag(true);
			repaintItem(m_itemUnderDrag);
		}
	}
}

void BasketTreeListView::autoOpen()
{
	BasketListViewItem *item = (BasketListViewItem*)m_autoOpenItem;
	if (item)
		Global::bnpView->setCurrentBasket(item->basket());
}

void BasketTreeListView::resizeEvent(TQResizeEvent *event)
{
	TDEListView::resizeEvent(event);
}

void BasketTreeListView::paintEmptyArea(TQPainter *painter, const TQRect &rect)
{
	TQListView::paintEmptyArea(painter, rect);

	BasketListViewItem *last = Global::bnpView->lastListViewItem();
	if (last && !last->isShown())
		last = last->shownItemAbove();
	if (last && last->isCurrentBasket()) {
		int y = last->itemPos() + last->height();
		TQColor bgColor  = paletteBackgroundColor();
		TQColor selColor = TDEGlobalSettings::highlightColor();
		TQColor midColor = Tools::mixColor(bgColor, selColor);
		painter->setPen(selColor);
		painter->drawPoint(visibleWidth() - 1, y);
		painter->drawPoint(visibleWidth() - 2, y);
		painter->drawPoint(visibleWidth() - 1, y + 1);
		painter->setPen(midColor);
		painter->drawPoint(visibleWidth() - 3, y);
		painter->drawPoint(visibleWidth() - 1, y + 2);
	}
}

/** We should NEVER get focus (because of TQWidget::NoFocus focusPolicy())
 * but TDEListView can programatically give us the focus.
 * So we give it to the basket.
 */
void BasketTreeListView::focusInEvent(TQFocusEvent*)
{
	//TDEListView::focusInEvent(event);
	Basket *basket = Global::bnpView->currentBasket();
	if (basket)
		basket->setFocus();
}

#include "basketlistview.moc"
