/***************************************************************************
                          dcwidget.cpp  -  description
                             -------------------
    begin                : Don Mai 30 2002
    copyright            : (C) 2002-2005 by Mathias Küster
    email                : mathen@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>

#include <qapplication.h>
#include <qstyle.h>
#include <qpainter.h>
#include <q3header.h>
//Added by qt3to4:
#include <QPixmap>
#include <QStyleOption>

#include "dcwidget.h"

#include "../dctransferview.h"

#include <dclib/dcos.h>

/** */
DC_UserListItem::DC_UserListItem( Q3ListView *parent, const QString &text, const QPixmap & p )
	: DC_QCheckListItem( parent, text, p )
{
	int i;

	for(i=0;i<USERLISTITEM_MAX_COLUMNS;i++)
	{
		m_nCompareValue[i] = 0;
	}

	setCompareValue(0,text);
}

/** */
DC_UserListItem::DC_UserListItem( Q3ListView *parent, const QString &text, Type tt )
	: DC_QCheckListItem( parent, text, tt )
{
	int i;

	for(i=0;i<USERLISTITEM_MAX_COLUMNS;i++)
	{
		m_nCompareValue[i] = 0;
	}

	setCompareValue(0,text);
}

/** */
void DC_UserListItem::setCompareValue( int column, const QString & text )
{
	QString s;
	const char * b;

	s = text.leftJustify(8,0x01,TRUE).lower();
	b = s.ascii();

	m_nCompareValue[column] = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
	m_nCompareValue[column] <<= 32;
	m_nCompareValue[column] |= b[4] << 24 | b[5] << 16 | b[6] << 8 | b[7];
}

/** */
int DC_UserListItem::compare( Q3ListViewItem * i, int col, bool ascending ) const
{
	if ( col >= USERLISTITEM_MAX_COLUMNS )
	{
		return DC_QCheckListItem::compare(i,col,ascending);
	}

	// numeric compare
	if ( m_bSortTop && !((DC_QCheckListItem*)i)->m_bSortTop )
		return ascending ? -1 : 1;
	else if ( !m_bSortTop && ((DC_QCheckListItem*)i)->m_bSortTop )
		return ascending ? 1 : -1;
	else if ( m_nCompareValue[col] > ((DC_UserListItem*)i)->m_nCompareValue[col] )
		return 1;
	else if ( m_nCompareValue[col] < ((DC_UserListItem*)i)->m_nCompareValue[col] )
		return -1;
	else
		return DC_QCheckListItem::compare(i,col,ascending);
}

/** */
void DC_UserListItem::setText( int column, const QString & text )
{
	if ( column < USERLISTITEM_MAX_COLUMNS )
	{
		setCompareValue(column,text);
	}

	DC_QCheckListItem::setText(column,text);
}

/** */
DC_QCheckListItem::DC_QCheckListItem( Q3ListView *parent, const QString &text, const QPixmap & p )
	: Q3CheckListItem( parent, text, p )
{
	colorText = parent->colorGroup().text();

	m_bSortTop = FALSE;
}

/** */
DC_QCheckListItem::DC_QCheckListItem( Q3ListView *parent, const QString &text, Type tt )
	: Q3CheckListItem( parent, text, tt )
{
	colorText = parent->colorGroup().text();

	m_bSortTop = FALSE;
}

/** */
void DC_QCheckListItem::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align )
{
	if ( column == 0 )
	{
		QColorGroup _cg(cg);

		_cg.setColor( QColorGroup::Text, colorText );

		Q3CheckListItem::paintCell( p, _cg, column, width, align );
	}
	else
	{
		Q3CheckListItem::paintCell( p, cg, column, width, align );
	}
}

/** */
int DC_QCheckListItem::compare( Q3ListViewItem * i, int col, bool ascending ) const
{
	// numeric compare
	if ( m_bSortTop && !((DC_QCheckListItem*)i)->m_bSortTop )
		return ascending ? -1 : 1;
	else if ( !m_bSortTop && ((DC_QCheckListItem*)i)->m_bSortTop )
		return ascending ? 1 : -1;
	else if ( col == DC_QNumericSortItem::mycol )
		return DC_QNumericSortItem::mycompare(((DC_QCheckListItem*)i)->myvalue,myvalue,col,ascending);
	else
		return Q3ListViewItem::compare(i,col,ascending);
}

/** */
QString DC_QCheckListItem::key( int column, bool /*ascending*/ ) const
{
	return text( column ).lower();
}

/** */
int DC_QListViewItem::compare( Q3ListViewItem * i, int col, bool ascending ) const
{
	if(col==DC_QNumericSortItem::mycol)
		return DC_QNumericSortItem::mycompare(((DC_QListViewItem*)i)->myvalue,myvalue,col,ascending);
	else
		return Q3ListViewItem::compare(i,col,ascending);
}

/** */
int DC_QNumericSortItem::mycompare( ulonglong v1, ulonglong v2, int , bool ) const
{
	if(v1<v2) return -1;
	else if(v1==v2) return 0;
	else return 1;
}

/** */
QString DC_QListViewItem::key( int column, bool /*ascending*/ ) const
{
	return text( column ).lower();
}

/** */
void DC_ListResult::paintCell( QPainter * p, const QColorGroup & cg, int column, int width, int align )
{
	QColorGroup _cg( cg );
	QColor c = _cg.text();

	if ( column == 3 ) // nick
	{
		if ( g_pTransferView->IsUserInQueue( text(3), text(6) ) )
		{
			c = Qt::blue;
		}
	}

	_cg.setColor( QColorGroup::Text, c );

	Q3ListViewItem::paintCell( p, _cg, column, width, align );
}

/** Re-implemented to fix sorting search results by slots columns */
QString DC_ListResult::key( int column, bool ascending ) const
{
	// free slots column is 4, total slots column is 5
	if ( (column == 4) || (column == 5) )
	{
		//printf("Key=%s\n",(text( column ).rightJustify( 5, '0' )).ascii() );
		return text( column ).rightJustify( 5, '0' );
	}
	else
	{
		return DC_QListViewItem::key( column, ascending );
	}
}

/** */
DC_QProgressListItem::DC_QProgressListItem( DC_QProgressListItem *parent, const QString &text,
				int co, Type tt)
    : Q3ListViewItem( parent, text, QString::null )
{
	m_nColumn = co;
	myType = tt;
	init();
}

/** */
DC_QProgressListItem::DC_QProgressListItem( Q3ListViewItem *parent, const QString &text,
				int co, Type tt )
    : Q3ListViewItem( parent, text, QString::null )
{
	m_nColumn = co;
	myType = tt;
	init();
}

/** */
DC_QProgressListItem::DC_QProgressListItem( Q3ListView *parent, const QString &text,
				int co, Type tt )
    : Q3ListViewItem( parent, text )
{
	m_nColumn = co;
	myType = tt;
	init();
}

/** */
int DC_QProgressListItem::RTTI = 1;

/** */
int DC_QProgressListItem::rtti() const
{
	return RTTI;
}

/** */
void DC_QProgressListItem::init()
{
	exclusive = 0;
	// init progress bar
	m_ProgressBar = new QProgressBar(0);
	m_ProgressBar->setTextVisible(TRUE);
	m_bProgressEnable = TRUE;
	//m_ProgressBar->setIndicatorFollowsStyle(FALSE);
	resetProgress();
}

/** */
void DC_QProgressListItem::resetProgress()
{
	m_ProgressBar->reset();
	m_ProgressBar->setRange(0, 100);
	//m_ProgressBar->setTotalSteps(100);
}

/** */
void DC_QProgressListItem::setProgress( int i )
{
	m_ProgressBar->setValue(i);
}

/** */
DC_QProgressListItem::~DC_QProgressListItem()
{
	exclusive = 0; // so the children won't try to access us.
	delete m_ProgressBar;
}

/** */
void DC_QProgressListItem::setup()
{
	Q3ListViewItem::setup();
	int h = Q3ListViewItem::height();
	//h = QMAX( listView()->style().pixelMetric(QStyle::PM_ProgressBarChunkWidth, listView()), h );
	//h = QMAX( h, QApplication::globalStrut().height() );
	setHeight( h );
	m_ProgressBar->setFixedHeight(h-listView()->itemMargin());
	m_ProgressBar->setFixedWidth(40);
}

/** */
int DC_QProgressListItem::width( const QFontMetrics& fm, const Q3ListView* lv, int column) const
{
	int r = Q3ListViewItem::width( fm, lv, column );
	if ( (column == m_nColumn) && (m_bProgressEnable == TRUE) ) {
		r += lv->itemMargin();
		if ( !( myType == Controller && pixmap( 0 ) ) ) {
			QStyleOptionProgressBarV2 qso;
			qso.initFrom( m_ProgressBar );
			r +=  lv->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &qso, lv) + 4;
		}
	}

	return QMAX( r, QApplication::globalStrut().width() );
}

/*!
    Paints the item using the painter \a p and the color group \a cg.
    The item is in column \a column, has width \a width and has
    alignment \a align. (See Qt::AlignmentFlags for valid alignments.)
*/
void DC_QProgressListItem::paintCell( QPainter * p, const QColorGroup & cg,
			       int column, int width, int align )
{
	if ( !p )
		return;

	Q3ListView *lv = listView();
	if ( !lv )
		return;

	//const Qt::BackgroundMode bgmode = lv->viewport()->backgroundMode();
	const QColorGroup::ColorRole crole = lv->viewport()->backgroundRole(); //QPalette::backgroundRoleFromMode( bgmode );

	// we are not friends ...
//	if ( cg.brush( crole ) != lv->colorGroup().brush( crole ) )
		p->fillRect( 0, 0, width, Q3ListViewItem::height(), cg.brush( crole ) );
//	else
//		paintEmptyArea( p, QRect( 0, 0, width, QListViewItem::height() ) );

	if ( (column != m_nColumn) || (m_bProgressEnable == FALSE) )
	{
		// The rest is text, or for subclasses to change.
		Q3ListViewItem::paintCell( p, cg, column, width, align );
		return;
	}

	int marg = lv->itemMargin();
	int r = marg;

	QStyleOptionProgressBarV2 styleoption;
	styleoption.initFrom( m_ProgressBar );
	styleoption.maximum       = 100;
	styleoption.minimum       = 0;
	styleoption.progress      = m_ProgressBar->value();
	styleoption.text          = m_ProgressBar->text();
	styleoption.textAlignment = m_ProgressBar->alignment();
	styleoption.textVisible   = m_ProgressBar->isTextVisible();

	if ( isSelected() )
	{
		//styleflags |= QStyle::State_Selected;
		styleoption.state = styleoption.state | QStyle::State_Selected;
	}
	
	if ( Q3ListViewItem::isEnabled() && lv->isEnabled() )
	{
		//styleflags |= QStyle::State_Enabled;
		styleoption.state = styleoption.state | QStyle::State_Enabled;
	}

	int boxsize = lv->style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &styleoption, lv);
	QFontMetrics fm( lv->fontMetrics() );

	bool parentControl = FALSE;
	if ( Q3ListViewItem::parent() && Q3ListViewItem::parent()->rtti() == 1  &&
	   ((DC_QProgressListItem*) Q3ListViewItem::parent())->type() == Controller )
		parentControl = TRUE;

	//int styleflags = QStyle::State_None;

	if ( myType == ProgressBar )
	{
		p->save();

		int x = 0;
		if(!parentControl)
			x += 3;

		QRect bar;
		bar = m_ProgressBar->contentsRect();
		bar.setWidth(40);
		//QSharedDoubleBuffer * buffer = new QSharedDoubleBuffer( p, bar.x(), bar.y(), bar.width(), bar.height() );
#if QT_VERSION >= 0x030100
		QPoint pn = m_ProgressBar->backgroundOffset();
		p->setBrushOrigin( -pn.x(), -pn.y() );
#endif
		const QPixmap *bpm = m_ProgressBar->paletteBackgroundPixmap();
		if ( bpm )
			p->fillRect( bar, QBrush( m_ProgressBar->paletteBackgroundColor(), *bpm ) );
		else
			p->fillRect( bar, m_ProgressBar->paletteBackgroundColor() );
		//buffer->painter()->setFont( p->font() );

		//bar = QStyle::visualRect(m_ProgressBar->style().subRect(QStyle::SR_ProgressBarGroove, m_ProgressBar), m_ProgressBar );
		styleoption.rect = bar;
		m_ProgressBar->style()->drawControl(QStyle::CE_ProgressBarGroove, &styleoption, p, m_ProgressBar);

		//bar = QStyle::visualRect(m_ProgressBar->style().subRect(QStyle::SR_ProgressBarContents, m_ProgressBar), m_ProgressBar );
		m_ProgressBar->style()->drawControl(QStyle::CE_ProgressBarContents, &styleoption, p, m_ProgressBar);

		if (m_ProgressBar->isTextVisible())
		{
			//bar = QStyle::visualRect(m_ProgressBar->style().subRect(QStyle::SR_ProgressBarLabel, m_ProgressBar), m_ProgressBar );
			m_ProgressBar->style()->drawControl(QStyle::CE_ProgressBarLabel, &styleoption, p, m_ProgressBar);
		}
		r += boxsize + bar.width();

		p->restore();

		//delete buffer;
	}

	if ( align == Qt::AlignCenter )
	{
		QFontMetrics fm( lv->font() );
		r += (width - boxsize - fm.width(text()))/2;
		// the text should not be centered when we have a centered checkbox
		align &= ~Qt::AlignCenter;
	}

	p->translate( r, 0 );
	p->setPen( QPen( cg.text() ) );
	Q3ListViewItem::paintCell( p, cg, column, width - r, align );
}

/*!
    Draws the focus rectangle \a r using the color group \a cg on the
    painter \a p.
*/
void DC_QProgressListItem::paintFocus( QPainter *p, const QColorGroup & cg,
				 const QRect & r )
{
	bool intersect = TRUE;
	Q3ListView *lv = listView();

	if ( lv && lv->header()->mapToActual( 0 ) != 0 )
	{
		int xdepth = lv->treeStepSize() * ( depth() + ( lv->rootIsDecorated() ? 1 : 0) ) + lv->itemMargin();
		int p = lv->header()->cellPos( lv->header()->mapToActual( 0 ) );
		xdepth += p;
		intersect = r.intersects( QRect( p, r.y(), xdepth - p + 1, r.height() ) );
	}

	bool parentControl = FALSE;

	if ( Q3ListViewItem::parent() && Q3ListViewItem::parent()->rtti() == 1  &&
	   ((DC_QProgressListItem*) Q3ListViewItem::parent())->type() == Controller )
		parentControl = TRUE;

	if ( myType != Controller && intersect &&
	   (lv->rootIsDecorated() || myType == RadioButton || myType == ProgressBar ||
	   (myType == CheckBox && parentControl) ) )
	{
		QRect rect;
		int boxsize = 0; //lv->style().pixelMetric(QStyle::PM_ProgressBarChunkWidth, lv);
		if ( lv->columnAlignment(0) == Qt::AlignCenter )
		{
			QFontMetrics fm( lv->font() );
			int bx = (lv->columnWidth(0) - (boxsize + fm.width(text())))/2 + boxsize;
			if ( bx < 0 ) bx = 0;
			rect.setRect( r.x() + bx /*+ 5*/, r.y(), r.width() - bx /*- 5*/, r.height() );
		} else
			rect.setRect( r.x() + boxsize /*+ 5*/, r.y(), r.width() - boxsize /*- 5*/, r.height() );
		Q3ListViewItem::paintFocus(p, cg, rect);
	}
	else
	{
		Q3ListViewItem::paintFocus(p, cg, r);
	}
}

/** Returns the key used to sort the items.
 *  If the progress bar is enabled, we return a key like d069 or u071
 *  The initial letter stands for download or upload etc., the number is the percentage of the transfer.
 *  If the progress bar is not enabled or the column isn't the transfer column, returns QListViewItem::key() .
 *  QT Docs say ascending parameter can be ignored. 
 */
QString DC_QProgressListItem::key( int n, bool ascending ) const
{
	QString s;
	
	// printf("DC_QProgessListItem::key called for column: %d\n", n);
	
	// column 2 is Transfer column
	if ( (n == 2) && (m_bProgressEnable) )
	{
		s = s.setNum(m_ProgressBar->value());
		s = s.rightJustify(3, '0');
		s = sTransferState + s;
		// printf("Key for sorting transfer column is %s\n", s.ascii());
		return s;
	}
	else
	{
		return Q3ListViewItem::key( n, ascending );
	}
}

/** */
void DC_QProgressListItem::setTransferState( QString s )
{
	sTransferState = s;
}

/** sort top parts copied from DC_UserListItem */
int DC_FBListViewItem::compare( Q3ListViewItem * i, int col, bool ascending ) const
{
	if ( m_bSortTop && !((DC_FBListViewItem*)i)->m_bSortTop )
	{
		return ascending ? -1 : 1;
	}
	else if ( !m_bSortTop && ((DC_FBListViewItem*)i)->m_bSortTop )
	{
		return ascending ? 1 : -1;
	}
	else
	{
		return DC_QListViewItem::compare( i, col, ascending );
	}
}
