/***********************************************************************************
* CPU Load: Plasmoid to monitor CPU Load.
* Copyright (C) 2008  Alexey Tyapkin
*
* 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.
*
***********************************************************************************/
#include "cpuload.h"
#include <QPainter>
#include <QFontMetrics>
#include <QSizeF>
#include <QBitmap>
#include <QFile>
#include <plasma/svg.h>
#include <plasma/theme.h>

#include <stdio.h>



cpuload::cpuload ( QObject *parent, const QVariantList &args )
		: Plasma::Applet ( parent, args ),
		m_icon ( "document" )
{

	iXCount=cpuload::columns;
	iYCount=cpuload::rows;
	iXStep=cpuload::cellWidth;
	iYStep=cpuload::cellHeight;
	userColor=QColor ( cpuload::cUser );
	diskColor=QColor ( cpuload::cDisk );
	niceColor=QColor ( cpuload::cNice );
	systemColor=QColor ( cpuload::cSystem );
	gridColor= QColor( cpuload::cGrid );

	cpuLoadLabelColor= QColor(cpuload::cCPULoadLabel);
	cpuLoadValueColor= QColor(cpuload::cCPULoadValue);
	cpuNameColor= QColor(cpuload::cCPUName);

	iCpuLoad=0;
	iCPULoadLabel=cpuload::CPULoadLabelFontSize;
	iCPULoadValue=cpuload::CPULoadValueFontSize;
	iCPUName=cpuload::CPUNameFontSize;
	iGraphInfo=cpuload::GraphInfoFontSize;

	plasmoidFont=QFont(cpuload::defaultFontFamily);

	readConfig();

	iWidth=iXCount*iXStep;
	iHeight=iYCount*iYStep;
	iWidth1=iWidth-2;
	iWidth2=iWidth-4;
	cfg_dialog=NULL;
	preview=NULL;
	vIdle=QVector<int>(101);
	vLoad=QVector<int>(101);
	cpuInfo[0]="User";
	cpuInfo[1]="System";
	cpuInfo[2]="Nice";
	cpuInfo[3]="Disk";

	for (int i=0; i < vIdle.size(); i++) {
		vIdle.replace(i, (int)(i * iHeight / 100));
		vLoad.replace(i, (int)(iHeight - i * iHeight/100));
	}

	QFile file ( "/proc/cpuinfo" );
	if ( file.open ( QIODevice::ReadOnly ) )
	{
		QTextStream t ( &file );
		QString buf;
	
		while ( (buf=t.readLine()) != NULL )
		{
			if ( buf.startsWith ( "model name" ) )
			{
				sCpuModel=buf.split(":")[1];
				break;
			}
		}
	}else sCpuModel="";
	if (file.isOpen()) {
		file.close();
	}

	setHasConfigurationInterface( true );

	plasmoidFont.setBold ( true );
	plasmoidFont.setPointSize ( iGraphInfo );
	iWidth3=QFontMetrics(plasmoidFont).width( QString ( "System" ) )+6;
	plasmoidFont.setPointSize ( iCPULoadValue );
	if (iWidth3 < QFontMetrics(plasmoidFont).width( QString ( "100%" ) )+6 ) {
		iWidth3=QFontMetrics(plasmoidFont).width( QString ( "100%" ) )+6;
	}
	plasmoidFont.setPointSize ( iCPUName );
	iHeight1=(QFontMetrics(plasmoidFont).width ( sCpuModel ) / (iWidth+iWidth3) + 1)*QFontMetrics(plasmoidFont).height();
	rGraphErase=QRect(iWidth-2,0,2,iHeight);

	iHeight3=computeHeight3(plasmoidFont, iHeight, iYStep, iGraphInfo, iCPULoadValue);

	rCPUValue=QRect(iWidth+1,iHeight3+1,iWidth3-3,iHeight-iHeight3-2);
	setCacheMode(QGraphicsItem::NoCache);

	resize ( contentSizeHint());
        prepareGeometryChange();
        updateGeometry();
        update();
}

int cpuload::computeHeight3(QFont f, int height, int ystep, int infoSize, int loadSize) 
{
	QFont pFont=f;
	int tmpHeight, bufHeight;

	pFont.setBold ( true );
	pFont.setPointSize ( infoSize );
	tmpHeight=(pFont.pointSize())*4+2;
	pFont.setPointSize ( loadSize );
	bufHeight=pFont.pointSize()+2;

	if (tmpHeight <= height/2 && bufHeight <= height/2) {
		tmpHeight = height/2;
	}else {
		if ( bufHeight > height/2 ) {
			tmpHeight=height-bufHeight;
		}else{
			int tmp=tmpHeight/ystep+1;
			if ((tmp*ystep) < (height-bufHeight)) {
				tmpHeight=tmp*ystep;
			}
		}
	}
	if (tmpHeight > (height-bufHeight)) {
		tmpHeight=height-bufHeight;
	}
	return tmpHeight;
}
void cpuload::clicked ( QAbstractButton *button) 
{
	if (cfg.buttonBox->buttonRole(button) == QDialogButtonBox::ResetRole) {
		defaultsToCfg();
		updatePreview();
	}
}

void cpuload::defaultsToCfg()
{
	cfg.iColumns->setValue(cpuload::columns);
	cfg.iRows->setValue(cpuload::rows);
	cfg.iCellWidth->setValue(cpuload::cellWidth);
	cfg.iCellHeight->setValue(cpuload::cellHeight);
	cfg.cUser->setColor(QColor ( cpuload::cUser ));
	cfg.cSystem->setColor(QColor ( cpuload::cSystem ));
	cfg.cDisk->setColor(QColor ( cpuload::cDisk ));
	cfg.cNice->setColor(QColor ( cpuload::cNice ));
	cfg.cGrid->setColor(QColor( cpuload::cGrid ));
	cfg.cCPULoadLabel->setColor( cpuload::cCPULoadLabel );
	cfg.cCPULoadValue->setColor( cpuload::cCPULoadValue );
	cfg.cCPUName->setColor( cpuload::cCPUName );
	cfg.iCPULoadLabel->setValue( cpuload::CPULoadLabelFontSize );
	cfg.iCPULoadValue->setValue( cpuload::CPULoadValueFontSize );
	cfg.iCPUName->setValue( cpuload::CPUNameFontSize );
	cfg.iGraphInfo->setValue( cpuload::GraphInfoFontSize );
	cfg.font->setCurrentFont( cpuload::defaultFontFamily );
}

void cpuload::plasmoidToCfg()
{
	cfg.iColumns->setValue(iXCount);
	cfg.iRows->setValue(iYCount);
	cfg.iCellWidth->setValue(iXStep);
	cfg.iCellHeight->setValue(iYStep);
	cfg.cUser->setColor(userColor);
	cfg.cSystem->setColor(systemColor);
	cfg.cDisk->setColor(diskColor);
	cfg.cNice->setColor(niceColor);
	cfg.cGrid->setColor(gridColor);
	cfg.cCPULoadLabel->setColor(cpuLoadLabelColor);
	cfg.cCPULoadValue->setColor(cpuLoadValueColor);
	cfg.cCPUName->setColor(cpuNameColor);
	cfg.iCPULoadLabel->setValue(iCPULoadLabel);
	cfg.iCPULoadValue->setValue(iCPULoadValue);
	cfg.iCPUName->setValue(iCPUName);
	cfg.iGraphInfo->setValue(iGraphInfo);
	cfg.font->setCurrentFont(plasmoidFont);
}

void cpuload::readConfig() {
	KConfigGroup cg = config();
	if (cg.hasKey("iXCount"))
		iXCount=cg.readEntry("iXCount", iXCount);
	if (cg.hasKey("iYCount"))
		iYCount=cg.readEntry("iYCount", iYCount);
	if (cg.hasKey("iXStep"))
		iXStep=cg.readEntry("iXStep", iXStep);
	if (cg.hasKey("iYStep"))
		iYStep=cg.readEntry("iYStep", iYStep);
	if (cg.hasKey("userColor"))
		userColor=QColor(cg.readEntry("userColor", userColor.name()));
	if (cg.hasKey("systemColor"))
		systemColor=QColor(cg.readEntry("systemColor", systemColor.name()));
	if (cg.hasKey("diskColor"))
		diskColor=QColor(cg.readEntry("diskColor", diskColor.name()));
	if (cg.hasKey("niceColor"))
		niceColor=QColor(cg.readEntry("niceColor", niceColor.name()));
	if (cg.hasKey("gridColor"))
		gridColor=QColor(cg.readEntry("gridColor", gridColor.name()));
	if (cg.hasKey("cpuLoadLabelColor"))
		cpuLoadLabelColor=QColor(cg.readEntry("cpuLoadLabelColor", cpuLoadLabelColor.name()));
	if (cg.hasKey("cpuLoadValueColor"))
		cpuLoadValueColor=QColor(cg.readEntry("cpuLoadValueColor", cpuLoadValueColor.name()));
	if (cg.hasKey("cpuNameColor"))
		cpuNameColor=QColor(cg.readEntry("cpuNameColor", cpuNameColor.name()));
	if (cg.hasKey("iCPULoadLabel"))
		iCPULoadLabel=cg.readEntry("iCPULoadLabel", iCPULoadLabel);
	if (cg.hasKey("iCPULoadValue"))
		iCPULoadValue=cg.readEntry("iCPULoadValue", iCPULoadValue);
	if (cg.hasKey("iCPUName"))
		iCPUName=cg.readEntry("iCPUName", iCPUName);
	if (cg.hasKey("iGraphInfo"))
		iGraphInfo=cg.readEntry("iGraphInfo", iGraphInfo);
	if (cg.hasKey("plasmoidFont"))
		plasmoidFont=QFont(cg.readEntry("plasmoidFont", plasmoidFont.family()));
}

void cpuload::writeConfig() {
	KConfigGroup cg = config();
	cg.writeEntry("iXCount", iXCount);
	cg.writeEntry("iYCount", iYCount);
	cg.writeEntry("iXStep", iXStep);
	cg.writeEntry("iYStep", iYStep);
	cg.writeEntry("userColor", userColor.name());
	cg.writeEntry("systemColor", systemColor.name());
	cg.writeEntry("diskColor", diskColor.name());
	cg.writeEntry("niceColor", niceColor.name());
	cg.writeEntry("gridColor", gridColor.name());
	cg.writeEntry("cpuLoadLabelColor", cpuLoadLabelColor.name());
	cg.writeEntry("cpuLoadValueColor", cpuLoadValueColor.name());
	cg.writeEntry("cpuNameColor", cpuNameColor.name());
	cg.writeEntry("iCPULoadLabel", iCPULoadLabel);
	cg.writeEntry("iCPULoadValue", iCPULoadValue);
	cg.writeEntry("iCPUName", iCPUName);
	cg.writeEntry("iGraphInfo", iGraphInfo);
	cg.writeEntry("plasmoidFont", plasmoidFont.family());
	emit configNeedsSaving();
}

void cpuload::cfgToPlasmoid()
{
	iXCount=cfg.iColumns->value();
	iYCount=cfg.iRows->value();
	iXStep=cfg.iCellWidth->value();
	iYStep=cfg.iCellHeight->value();
	userColor=cfg.cUser->color();
	systemColor=cfg.cSystem->color();
	diskColor=cfg.cDisk->color();
	niceColor=cfg.cNice->color();
	gridColor=cfg.cGrid->color();
	cpuLoadLabelColor=cfg.cCPULoadLabel->color();
	cpuLoadValueColor=cfg.cCPULoadValue->color();
	cpuNameColor=cfg.cCPUName->color();
	iCPULoadLabel=cfg.iCPULoadLabel->value();
	iCPULoadValue=cfg.iCPULoadValue->value();
	iCPUName=cfg.iCPUName->value();
	iGraphInfo=cfg.iGraphInfo->value();
	plasmoidFont=cfg.font->currentFont();

	writeConfig();

	iWidth=iXCount*iXStep;
	iHeight=iYCount*iYStep;
	iWidth1=iWidth-2;
	iWidth2=iWidth-4;
	for (int i=0; i < vIdle.size(); i++) {
		vIdle.replace(i, (int)(i * iHeight / 100));
		vLoad.replace(i, (int)(iHeight - i * iHeight/100));
	}

	plasmoidFont.setBold ( true );
	plasmoidFont.setPointSize ( iGraphInfo );
	iWidth3=QFontMetrics(plasmoidFont).width( QString ( "System" ) )+6;
	plasmoidFont.setPointSize ( iCPULoadValue );
	if (iWidth3 < QFontMetrics(plasmoidFont).width( QString ( "100%" ) )+6 ) {
		iWidth3=QFontMetrics(plasmoidFont).width( QString ( "100%" ) )+6;
	}
	plasmoidFont.setPointSize ( iCPUName );
	iHeight1=(QFontMetrics(plasmoidFont).width ( sCpuModel ) / (iWidth+iWidth3) + 1)*QFontMetrics(plasmoidFont).height();
	rGraphErase=QRect(iWidth-2,0,2,iHeight);

	iHeight3=computeHeight3(plasmoidFont, iHeight, iYStep, iGraphInfo, iCPULoadValue);
	rCPUValue=QRect(iWidth+1,iHeight3+1,iWidth3-3,iHeight-iHeight3-2);

	if (pm != NULL) delete pm;
	if (dpm != NULL) delete dpm;
	if (mask != NULL) delete mask;
	pm=new QPixmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	dpm=new QPixmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	mask=new QBitmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	pm->fill ( Qt::transparent );
	dpm->fill ( Qt::transparent );
	mask->fill ( Qt::color0 );

	QPainter p;

	iCPU=iCPU1=iCPU2=99*iHeight/100;

	iSCPU=iSCPU1=iSCPU2=iHeight;

	iNCPU=iNCPU1=iNCPU2=iHeight;

	iDCPU=iDCPU1=iDCPU2=iHeight;

	p.begin ( dpm );
	DrawGrid(&p, iXCount, iYCount, iXStep, iYStep, iWidth3, iHeight3, gridColor);
	DrawText(&p, iXCount, iYCount, iXStep, iYStep, iWidth3, iHeight3, iHeight1, userColor, systemColor, diskColor, niceColor, cpuLoadLabelColor, cpuNameColor, plasmoidFont, iGraphInfo, iCPULoadLabel, iCPUName);

	plasmoidFont.setPointSize ( iCPULoadValue );
	p.setPen ( cpuLoadValueColor );
	p.drawText ( rCPUValue, Qt::AlignRight | Qt::AlignVCenter, "0%");

	p.end();


	resize ( contentSizeHint());
        prepareGeometryChange();
        updateGeometry();
        update();
}

void cpuload::DrawText(QPainter *p, int iCols, int iRows, int iCellWidth, int iCellHeight, int iInfoWidth, int iInfoHeight, int iNameHeight, QColor cUser, QColor cSystem, QColor cDisk, QColor cNice, QColor cCpuLoadLabel, QColor cCpuName, QFont font, int szInfo, int szCpuLoadLabel, int szCpuName)
{
	int i=0;
	int iiWidth,iiHeight;
	QFont pFont=font;

	iiWidth=iCols*iCellWidth;
	iiHeight=iRows*iCellHeight;

	int iStep=(iInfoHeight-2)/4;
	int iStep2=iStep*2;
	pFont.setBold ( true );
	pFont.setPointSize ( szInfo );
	pens[0]=QPen( cUser );
	pens[1]=QPen( cSystem );
	pens[2]=QPen( cNice );
	pens[3]=QPen( cDisk );

	p->setFont ( pFont );
	for (i=0; i<4 ;i++) {
		p->setPen ( pens[i] );
		p->drawText ( iiWidth+1,1+iStep*i, iInfoWidth-2, iStep2, Qt::AlignHCenter|Qt::AlignTop, cpuInfo[i] );
	}
	pFont.setPointSize ( szCpuLoadLabel );
	p->setFont ( pFont );
	p->setPen ( cCpuLoadLabel );
	p->drawText ( 0, 0, iiWidth, iiHeight, Qt::AlignCenter, QString ( "CPU Load" ) );
	pFont.setPointSize ( szCpuName );
	p->setFont ( pFont );
	p->setPen ( cCpuName );
	p->drawText ( 0, iiHeight+1, iiWidth+iInfoWidth, iNameHeight-2, Qt::AlignCenter | Qt::TextWordWrap, QString ( sCpuModel ) );
}

void cpuload::DrawGrid(QPainter *p, int iCols, int iRows, int iCellWidth, int iCellHeight, int iInfoWidth, int iInfoHeight, QColor cGridColor)
{
	int i=0;
	int iiWidth,iiHeight;

	iiWidth=iCols*iCellWidth;
	iiHeight=iRows*iCellHeight;
	p->setPen ( cGridColor );
	for ( i=0;i<=iCols;i++ ) p->drawLine ( i*iCellWidth,1,i*iCellWidth,iiHeight );
	for ( i=0;i<=iRows;i++ ) p->drawLine ( 1,i*iCellHeight,iiWidth,i*iCellHeight );
	
	p->drawRect (iiWidth,0,iInfoWidth-1,iiHeight);
	p->drawLine ( iiWidth,iInfoHeight,iiWidth+iInfoWidth-1,iInfoHeight );
}

void cpuload::showConfigurationInterface()
{
	if (cfg_dialog == 0) {
		cfg_dialog = new QDialog;

		cfg.setupUi(cfg_dialog);

		connect( cfg.iColumns, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iRows, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iCellWidth, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iCellHeight, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );

		connect( cfg.font, SIGNAL(currentFontChanged (const QFont &)), this, SLOT(updatePreview()) );
		connect( cfg.iCPUName, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iCPULoadLabel, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iCPULoadValue, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );
		connect( cfg.iGraphInfo, SIGNAL(valueChanged(int)), this, SLOT(updatePreview()) );

		connect( cfg.cGrid, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cUser, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cSystem, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cDisk, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cNice, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cCPULoadLabel, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cCPULoadValue, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );
		connect( cfg.cCPUName, SIGNAL(changed(const QColor&)), this, SLOT(updatePreview()) );

		connect( cfg.buttonBox, SIGNAL(accepted()), this, SLOT(cfgToPlasmoid()) );
		connect( cfg.buttonBox, SIGNAL(clicked ( QAbstractButton *)), this, SLOT(clicked ( QAbstractButton *)) );

	}

	plasmoidToCfg();

	if (preview == 0) {
		preview=new QPixmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
		preview->fill ( Qt::transparent );
		QPainter p;
		p.begin ( preview );
			DrawGrid(&p, iXCount, iYCount, iXStep, iYStep, iWidth3, iHeight/2, Qt::red);
		p.end();
		cfg.label->setPixmap(*preview);
		cfg.label->setFixedSize(preview->size());
		cfg.label->adjustSize();
		cfg_dialog->adjustSize();
	}
	
	updatePreview();
	cfg_dialog->show();
}

void cpuload::updatePreview()
{
	int iiWidth, iiHeight, iiWidth3, iiHeight1, iiHeight3;
	QVector<int> fakeUserLoad;
	QVector<int> fakeSysLoad;
	QVector<int> fakeNiceLoad;
	QVector<int> fakeDiskLoad;
	QPainterPath fakeUserPath;
	QPainterPath fakeSysPath;
	QPainterPath fakeNicePath;
	QPainterPath fakeDiskPath;

	fakeUserLoad << 100 << 100 << 100 << 9 << 3 << 3 << 8 << 8 << 27 << 27 << 29 << 29 << 9 << 9 << 6 << 6 << 7 << 7 << 7 << 7 << 7 << 12 << 12 << 7 << 8 << 8 << 8 << 4 << 9 << 5 << 5 << 7 << 7 << 7 << 7 << 7 << 7 << 12 << 12 << 8 << 8 << 12 << 12 << 5 << 5 << 5 << 5 << 7 << 7 << 6 << 6 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 15 << 9 << 9 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 4 << 4 << 5 << 6 << 6 << 6 << 6 << 13 << 13 << 5 << 5 << 6 << 6 << 5 << 5 << 5 << 5 << 4 << 4 << 5 << 5 << 6 << 6 << 5 << 6 << 6 << 11 << 7 << 7 << 55 << 55 << 55 << 55 << 58 << 58 << 18 << 18 << 58 << 58 << 71 << 53 << 53 << 53 << 54 << 54 << 52 << 52 << 78 << 78 << 83 << 83 << 12 << 12 << 55 << 55 << 55 << 19 << 19 << 5 << 5 << 14 << 5 << 5 << 6 << 6 << 6 << 14 << 3 << 3 << 6 << 6 << 6 << 5 << 6 << 5 << 5 << 5 << 5 << 7 << 7 << 5 << 5 << 5 << 7 << 4 << 4 << 12 << 4 << 4 << 7 << 3 << 3 << 5 << 5 << 5 << 5 << 6 << 6 << 6 << 2 << 2 << 15 << 15 << 7 << 7 << 9 << 9 << 15 << 4 << 4 << 10 << 10 << 9 << 3 << 3 << 7 << 6 << 6 << 100 << 100 << 100 ;
	fakeSysLoad << 1 << 5 << 5 << 3 << 1 << 5 << 4 << 0 << 4 << 0 << 0 << 3 << 2 << 1 << 4 << 2 ;
	fakeNiceLoad << 30 << 33 << 30 << 45 << 0 << 15 << 35 << 30 << 20 << 0 << 0 << 20 << 22 << 25 << 24 << 30 ;
	fakeDiskLoad << 12 << 26 << 26 << 9 << 3 << 3 << 8 << 8 << 27 << 27 << 29 << 29 << 9 << 9 << 6 << 6 << 7 << 7 << 7 << 7 << 7 << 12 << 12 << 7 << 8 << 8 << 8 << 4 << 9 << 5 << 5 << 7 << 7 << 7 << 7 << 7 << 7 << 12 << 12 << 8 << 8 << 12 << 12 << 5 << 5 << 5 << 5 << 7 << 7 << 6 << 6 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 5 << 15 << 9 << 9 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 6 << 4 << 4 << 5 << 6 << 6 << 6 << 6 << 13 << 13 << 5 << 5 << 6 << 6 << 5 << 5 << 5 << 5 << 4 << 4 << 5 << 5 << 6 << 6 << 5 << 6 << 6 << 11 << 7 << 7 << 35 << 35 << 35 << 35 << 28 << 28 << 18 << 18 << 28 << 28 << 21 << 33 << 33 << 23 << 24 << 24 << 32 << 32 << 48 << 48 << 53 << 23 << 12 << 12 << 25 << 25 << 25 << 9 << 9 << 5 << 5 << 4 << 5 << 5 << 6 << 6 << 3 << 4 << 3 << 3 << 6 << 6 << 6 << 5 << 6 << 5 << 5 << 5 << 5 << 7 << 7 << 5 << 5 << 5 << 7 << 4 << 4 << 12 << 4 << 4 << 7 << 3 << 3 << 5 << 5 << 5 << 5 << 6 << 6 << 6 << 2 << 2 << 15 << 15 << 7 << 7 << 9 << 9 << 15 << 4 << 4 << 10 << 10 << 9 << 3 << 3 << 7 << 6 << 6 << 6 << 6 << 6 ;

	if (preview != NULL) {
		delete preview;
	}
	iiWidth=cfg.iColumns->value()*cfg.iCellWidth->value();
	iiHeight=cfg.iRows->value()*cfg.iCellHeight->value();

	int i;
	for (i=0; i<fakeUserLoad.size();i++) {
		fakeUserLoad.replace(i,iiHeight - fakeUserLoad.at(i) * iiHeight / 100); 
	}
	for (i=0; i<fakeSysLoad.size();i++) {
		fakeSysLoad.replace(i,iiHeight - fakeSysLoad.at(i) * iiHeight / 100); 
	}
	for (i=0; i<fakeNiceLoad.size();i++) {
		fakeNiceLoad.replace(i,iiHeight - fakeNiceLoad.at(i) * iiHeight / 100);
	} 
	for (i=0; i<fakeDiskLoad.size();i++) {
		fakeDiskLoad.replace(i,iiHeight - fakeDiskLoad.at(i) * iiHeight / 100); 
	}
	for (i=0; i < iiWidth ; i+=2) {
		if (i==0) {
			fakeUserPath.moveTo(iiWidth,fakeUserLoad.at(i));
			fakeSysPath.moveTo(iiWidth,fakeSysLoad.at(i));
			fakeNicePath.moveTo(iiWidth,fakeNiceLoad.at(i));
			fakeDiskPath.moveTo(iiWidth,fakeDiskLoad.at(i));
		}else {
			fakeUserPath.lineTo(iiWidth-i,fakeUserLoad.at(i%fakeUserLoad.size()));
			fakeSysPath.lineTo(iiWidth-i,fakeSysLoad.at(i%fakeSysLoad.size()));
			fakeNicePath.lineTo(iiWidth-i,fakeNiceLoad.at(i%fakeNiceLoad.size()));
			fakeDiskPath.lineTo(iiWidth-i,fakeDiskLoad.at(i%fakeDiskLoad.size()));
		}
	}

	QFont pFont=cfg.font->currentFont();
	pFont.setBold ( true );
	pFont.setPointSize ( cfg.iGraphInfo->value() );
	iiWidth3=QFontMetrics(pFont).width( QString ( "System" ) )+6;
	pFont.setPointSize ( cfg.iCPULoadValue->value() );
	if (iiWidth3 < QFontMetrics(pFont).width( QString ( "100%" ) )+6 ) {
		iiWidth3=QFontMetrics(pFont).width( QString ( "100%" ) )+6;
	}

	iiHeight3=computeHeight3(pFont, iiHeight, cfg.iCellHeight->value(), cfg.iGraphInfo->value(), cfg.iCPULoadValue->value());
	pFont.setPointSize ( cfg.iCPUName->value() );
	iiHeight1=(QFontMetrics(pFont).width ( sCpuModel ) / (iiWidth+iiWidth3) + 1)*QFontMetrics(pFont).height();



	preview=new QPixmap ( QSize ( iiWidth+iiWidth3,iiHeight+iiHeight1+1 ) );
	preview->fill ( Qt::transparent );
	QPainter p;
	p.begin ( preview );
		DrawGrid(&p, cfg.iColumns->value(), cfg.iRows->value(), cfg.iCellWidth->value(), cfg.iCellHeight->value(), iiWidth3, iiHeight3, cfg.cGrid->color());
		DrawText(&p, cfg.iColumns->value(), cfg.iRows->value(), cfg.iCellWidth->value(), cfg.iCellHeight->value(), iiWidth3, iiHeight3, iiHeight1, cfg.cUser->color(), cfg.cSystem->color(), cfg.cDisk->color(), cfg.cNice->color(), cfg.cCPULoadLabel->color(), cfg.cCPUName->color(), cfg.font->currentFont(), cfg.iGraphInfo->value(), cfg.iCPULoadLabel->value(), cfg.iCPUName->value());
		pFont.setPointSize ( cfg.iCPULoadValue->value() );
		p.setFont(pFont);
		p.setPen ( cfg.cCPULoadValue->color() );
		p.drawText ( iiWidth+1,iiHeight3+1,iiWidth3-3,iiHeight-iiHeight3-2, Qt::AlignRight | Qt::AlignVCenter, "100%");
		p.setPen ( QPen ( cfg.cDisk->color(), 1 ) );
		p.drawPath ( fakeDiskPath ) ;
		p.setPen ( QPen ( cfg.cSystem->color(), 1 ) );
		p.drawPath ( fakeSysPath ) ;
		p.setPen ( QPen ( cfg.cUser->color(), 1 ) );
		p.drawPath ( fakeUserPath ) ;
	p.end();
	cfg.label->setPixmap(*preview);
	cfg.label->setFixedSize(preview->size());
	cfg.label->adjustSize();
	QString tmp;
	cfg.plasmoidSize->setText("Plasmoid size will be "+tmp.sprintf("%d x %d",(iiWidth+iiWidth3), (iiHeight+iiHeight1)));
	cfg_dialog->adjustSize();
}

cpuload::~cpuload()
{
	if (pm != NULL) delete pm;
	if (dpm != NULL) delete dpm;
	if (mask != NULL) delete mask;
	if (cfg_dialog != NULL) delete cfg_dialog;
	if (preview != NULL) delete preview;
	if ( hasFailedToLaunch() )
	{
		// Do some cleanup here
	}
	else
	{
		// Save settings
	}
}

void cpuload::init()
{
	pm=new QPixmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	dpm=new QPixmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	mask=new QBitmap ( QSize ( iWidth+iWidth3,iHeight+iHeight1+1 ) );
	pm->fill ( Qt::transparent );
	dpm->fill ( Qt::transparent );
	mask->fill ( Qt::color0 );

	QPainter p;

	iCPU=iCPU1=iCPU2=99*iHeight/100;

	iSCPU=iSCPU1=iSCPU2=iHeight;

	iNCPU=iNCPU1=iNCPU2=iHeight;

	iDCPU=iDCPU1=iDCPU2=iHeight;

	p.begin ( dpm );
	DrawGrid(&p, iXCount, iYCount, iXStep, iYStep, iWidth3, iHeight3, gridColor);
	DrawText(&p, iXCount, iYCount, iXStep, iYStep, iWidth3, iHeight3, iHeight1, userColor, systemColor, diskColor, niceColor, cpuLoadLabelColor, cpuNameColor, plasmoidFont, iGraphInfo, iCPULoadLabel, iCPUName);

	p.end();


	Plasma::DataEngine *cpu = dataEngine ( "cpuload" );
	cpu->connectSource ( "Average CPU Usage", this, 500 );
	setBackgroundHints(TranslucentBackground);

	resize ( contentSizeHint());
        prepareGeometryChange();
        updateGeometry();
        update();
}

QSizeF cpuload::contentSizeHint() const
{
	QSizeF sizeHint = QSizeF(iWidth+iWidth3 +30,iHeight+ iHeight1 +30);
	return sizeHint;
}


void cpuload::paintInterface ( QPainter *p,
                               const QStyleOptionGraphicsItem *option, const QRect &contentsRect )
{
	p->setRenderHint ( QPainter::SmoothPixmapTransform );
	p->setRenderHint ( QPainter::Antialiasing );

	p->drawPixmap ( 15,15,*dpm );
	p->drawPixmap ( 15,15,*pm );
}

void cpuload::dataUpdated ( const QString& source, const Plasma::DataEngine::Data &data )
{

	if ( source == "0" || source == "Average CPU Usage" )
	{

		iCPU2=iCPU1;
		iCPU1=iCPU;
		iCPU= vIdle.at(data["iIdle"].toInt());

		iSCPU2=iSCPU1;
		iSCPU1=iSCPU;
		iSCPU= vLoad.at(data["iSys"].toInt());

		iNCPU2=iNCPU1;
		iNCPU1=iNCPU;
		iNCPU= vLoad.at(data["iNice"].toInt());

		iDCPU2=iDCPU1;
		iDCPU1=iDCPU;
		iDCPU= vLoad.at(data["iDisk"].toInt());

		QPixmap tmp=QPixmap ( *pm );
		QPainter p;

		p.begin ( pm );
		p.drawPixmap ( -2,0,tmp );

		if ( cpuload::test ( iSCPU,iSCPU1, iSCPU2, iNCPU, iNCPU1, iNCPU2 ) )
		{
			cpuNiceGraph = QPainterPath() ;
			p.setPen ( QPen ( niceColor, 1 ) );
			cpuNiceGraph.moveTo ( QPointF ( iWidth2, iNCPU2 ) ) ;
			cpuNiceGraph.lineTo ( iWidth1, iNCPU1 ) ;
			cpuNiceGraph.lineTo ( iWidth, iNCPU ) ;
			p.drawPath ( cpuNiceGraph ) ;
		}


		if ( cpuload::test ( iNCPU, iNCPU1, iNCPU2, iDCPU, iDCPU1, iDCPU2 ) )
		{
			cpuDiskGraph = QPainterPath() ;
			p.setPen ( QPen ( diskColor, 1 ) );
			cpuDiskGraph.moveTo ( QPointF ( iWidth2, iDCPU2 ) ) ;
			cpuDiskGraph.lineTo ( iWidth1, iDCPU1 ) ;
			cpuDiskGraph.lineTo ( iWidth, iDCPU ) ;
			p.drawPath ( cpuDiskGraph ) ;
		}

		cpuSysGraph = QPainterPath() ;
		p.setPen ( QPen ( systemColor, 1 ) );
		cpuSysGraph.moveTo ( QPointF ( iWidth2, iSCPU2 ) ) ;
		cpuSysGraph.lineTo ( iWidth1, iSCPU1 ) ;
		cpuSysGraph.lineTo ( iWidth, iSCPU ) ;
		p.drawPath ( cpuSysGraph ) ;

		cpuGraph = QPainterPath() ;
		p.setPen ( QPen ( userColor, 1 ) );
		cpuGraph.moveTo ( QPointF ( iWidth2, iCPU2 ) ) ;
		cpuGraph.lineTo ( iWidth1, iCPU1 ) ;
		cpuGraph.lineTo ( iWidth, iCPU ) ;
		p.drawPath ( cpuGraph ) ;
		p.end();

		QBitmap tmpMask=QBitmap ( *mask );
		mask->fill ( Qt::color0 );
		p.begin ( mask );
		p.drawPixmap ( -2,0,tmpMask );
		p.setPen ( QPen ( Qt::color1,1 ) );


		if ( cpuload::test ( iSCPU,iSCPU1, iSCPU2, iNCPU, iNCPU1, iNCPU2 ) )
		{
			p.drawPath ( cpuNiceGraph ) ;
		}
		if ( cpuload::test ( iNCPU, iNCPU1, iNCPU2, iDCPU, iDCPU1, iDCPU2 ) )
		{
			p.drawPath ( cpuDiskGraph ) ;
		}
		p.drawPath ( cpuSysGraph ) ;
		p.drawPath ( cpuGraph ) ;
		p.end();

		pm->setMask ( *mask );

		if (iCpuLoad != data["iLoad"].toInt()) {
			p.begin(dpm);
			p.setCompositionMode(QPainter::CompositionMode_Clear);
			p.fillRect ( rCPUValue, Qt::transparent );
			plasmoidFont.setBold ( true );
			plasmoidFont.setPointSize ( iCPULoadValue );
			p.setFont(plasmoidFont);
			p.setPen ( cpuLoadValueColor );
			p.drawText ( rCPUValue, Qt::AlignRight | Qt::AlignVCenter, data["iLoad"].toString()+"%");
			
			p.end();
		}
		iCpuLoad=data["iLoad"].toInt();

		update();

	}
}


#include "cpuload.moc"
