/*
 * kcmnewsticker.cpp
 *
 * Copyright (c) 2000 Frerich Raabe <raabe@kde.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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "kcmnewsticker.h"

#include <dcopclient.h>

#include <kapp.h>
#include <kcolorbtn.h>
#include <kcombobox.h>
#include <kfiledialog.h>
#include <kfontdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knuminput.h>
#include <kpopupmenu.h>

#include <qcheckbox.h>
#include <qdatastream.h>
#include <qdragobject.h>
#include <qfileinfo.h>
#include <qiconset.h>
#include <qlabel.h>
#include <qradiobutton.h>
#include <qslider.h>
#include <qtoolbutton.h>

	KCMNewsTicker::KCMNewsTicker(QWidget* parent,  const char* name)
: KCModule(parent, name)
{
	if (!kapp->dcopClient()->isAttached())
		kapp->dcopClient()->attach();

	_config = new KConfig("knewstickerrc", false, false);

	_child = new KCMNewsTickerWidget(this);

	// Change various properties of the view which the Qt Designer cannot
	// set at design time yet.
	_child->niInterval->setLabel(i18n("News query interval:"));
	_child->niInterval->setRange(0, 180, 1);

	_child->lvNewsSources->setAcceptDrops(true);
	_child->lvNewsSources->setShowSortIndicator(true);
	_child->lvNewsSources->installEventFilter(this);

	connect(_child->niInterval, SIGNAL(valueChanged(int)), SLOT(slotConfigChanged()));
	connect(_child->cbCustomNames, SIGNAL(clicked()), SLOT(slotConfigChanged()));
	connect(_child->cbEndlessScrolling, SIGNAL(clicked()), SLOT(slotConfigChanged()));
	connect(_child->cbScrollMostRecentOnly, SIGNAL(clicked()), SLOT(slotConfigChanged()));
	connect(_child->sliderScrollSpeed, SIGNAL(valueChanged(int)), SLOT(slotConfigChanged()));
	connect(_child->comboDirection, SIGNAL(activated(const QString &)), SLOT(slotConfigChanged()));
	connect(_child->colorForeground, SIGNAL(changed(const QColor &)), SLOT(slotConfigChanged()));
	connect(_child->colorBackground, SIGNAL(changed(const QColor &)), SLOT(slotConfigChanged()));
	connect(_child->colorHighlighted, SIGNAL(changed(const QColor &)), SLOT(slotConfigChanged()));
	connect(_child->cbUnderlineHighlighted, SIGNAL(clicked()), SLOT(slotConfigChanged()));
	connect(_child->tbUp, SIGNAL(clicked()), SLOT(slotConfigChanged()));
	connect(_child->tbDown, SIGNAL(clicked()), SLOT(slotConfigChanged()));

	connect(_child->lvNewsSources, SIGNAL(contextMenu(KListView *, QListViewItem *, const QPoint &)),
			SLOT(slotContextMenu(KListView *, QListViewItem *, const QPoint &)));
	connect(_child->lvNewsSources, SIGNAL(currentChanged(QListViewItem *)),
			SLOT(slotSelectionChanged(QListViewItem *)));
	connect(_child->bAdd, SIGNAL(clicked()), SLOT(slotAddNewsSource()));
	connect(_child->bRemove, SIGNAL(clicked()), SLOT(slotRemoveNewsSource()));
	connect(_child->bChooseFont, SIGNAL(clicked()), SLOT(slotChooseFont()));
	connect(_child->leName, SIGNAL(textChanged(const QString &)), SLOT(slotNameChanged(const QString &)));
	connect(_child->leSourceFile, SIGNAL(textChanged(const QString &)), SLOT(slotSourceFileChanged(const QString &)));
	connect(_child->sbMaxArticles, SIGNAL(valueChanged(int)), SLOT(slotMaxArticlesChanged(int)));
	connect(_child->tbUp, SIGNAL(clicked()), SLOT(slotMoveItemUp()));
	connect(_child->tbDown, SIGNAL(clicked()), SLOT(slotMoveItemDown()));
	connect(_child->tbBrowse, SIGNAL(clicked()), SLOT(slotBrowse()));

	load();

	_child->show();
}

void KCMNewsTicker::load()
{
	_config->setGroup("General");
	_child->niInterval->setValue(_config->readNumEntry("Interval", 30));
	_child->cbCustomNames->setChecked(_config->readBoolEntry("Custom names", false));
	_child->cbEndlessScrolling->setChecked(_config->readBoolEntry("Endless Scrolling", true));
	_child->cbScrollMostRecentOnly->setChecked(_config->readBoolEntry("Scroll most recent only", false));
	uint newsSources = _config->readNumEntry("News sources", 0);

	_config->setGroup("Scrolling");
	_child->sliderScrollSpeed->setValue(_config->readNumEntry("Speed", 80));
	QString direction = _config->readEntry("Direction", "Left");
	if (direction == "Left")
		_child->comboDirection->setCurrentItem(0);
	else if (direction == "Right")
		_child->comboDirection->setCurrentItem(1);
	else if (direction == "Up")
		_child->comboDirection->setCurrentItem(2);
	else
		_child->comboDirection->setCurrentItem(3);
	QFont stdFont = QFont("courier");
	_font = _config->readFontEntry("Font", &stdFont);
	_child->colorForeground->setColor(_config->readColorEntry("Foreground", &Qt::black));
	_child->colorBackground->setColor(_config->readColorEntry("Background", &Qt::white));
	_child->colorHighlighted->setColor(_config->readColorEntry("Highlighted", &Qt::red));
	_child->cbUnderlineHighlighted->setChecked(_config->readBoolEntry("Underline highlighted", true));

	_child->lvNewsSources->clear();
	if (newsSources == 0) {
		addNewsSource("dot.kde.org", "http://www.kde.org/dotkdeorg.rdf");
		addNewsSource("Slashdot", "http://slashdot.org/slashdot.rdf");
		addNewsSource("Freshmeat", "http://freshmeat.net/backend/fm.rdf");
		addNewsSource("Linux Weekly News", "http://lwn.net/headlines/rss");
	} else for (uint i = 0; i < newsSources; i++) {
		_config->setGroup(QString("News source #%1").arg(i));
		addNewsSource(_config->readEntry("Name"), _config->readEntry("Address"), _config->readNumEntry("Max articles", 10));
	}

	slotSelectionChanged(0);

	emit changed(false);
}

void KCMNewsTicker::save()
{
	_config->setGroup("General");
	_config->writeEntry("Interval", _child->niInterval->value());
	_config->writeEntry("Custom names", _child->cbCustomNames->isChecked());
	_config->writeEntry("Endless Scrolling", _child->cbEndlessScrolling->isChecked());
	_config->writeEntry("Scroll most recent only", _child->cbScrollMostRecentOnly->isChecked());
	_config->writeEntry("News sources", _child->lvNewsSources->childCount());

	_config->setGroup("Scrolling");
	_config->writeEntry("Speed", _child->sliderScrollSpeed->value());
	switch (int item = _child->comboDirection->currentItem()) {
		case 0: _config->writeEntry("Direction" ,"Left"); break;
		case 1: _config->writeEntry("Direction" ,"Right"); break;
		case 2: _config->writeEntry("Direction" ,"Up"); break;
		default: _config->writeEntry("Direction" ,"Down");
	}
	_config->writeEntry("Font", _font);
	_config->writeEntry("Foreground", _child->colorForeground->color());
	_config->writeEntry("Background", _child->colorBackground->color());
	_config->writeEntry("Highlighted", _child->colorHighlighted->color());
	_config->writeEntry("Underline highlighted", _child->cbUnderlineHighlighted->isChecked());

	uint i = 0;
	for (QListViewItemIterator it(_child->lvNewsSources); it.current() != 0; it++) {
		_config->setGroup(QString("News source #%1").arg(i++));
		_config->writeEntry("Name", it.current()->text(0));
		_config->writeEntry("Address", it.current()->text(1));
		_config->writeEntry("Max articles", it.current()->text(2));
	}

	_config->sync();

	QByteArray data;
	kapp->dcopClient()->send("knewsticker", "KNewsTicker", "reparseConfig()", data);

	emit changed(false);
}

void KCMNewsTicker::defaults()
{
	_child->niInterval->setValue(30);
	_child->cbCustomNames->setChecked(false);
	_child->cbEndlessScrolling->setChecked(true);
	_child->cbScrollMostRecentOnly->setChecked(false);

	_child->sliderScrollSpeed->setValue(80);
	_child->comboDirection->setCurrentItem(0);
	_font = QFont("courier");
	_child->colorForeground->setColor(Qt::black);
	_child->colorBackground->setColor(Qt::white);
	_child->colorHighlighted->setColor(Qt::red);
	_child->cbUnderlineHighlighted->setChecked(true);

	_child->lvNewsSources->clear();
	addNewsSource("dot.kde.org", "http://www.kde.org/dotkdeorg.rdf");
	addNewsSource("Slashdot", "http://slashdot.org/slashdot.rdf");
	addNewsSource("Freshmeat", "http://freshmeat.net/backend/fm.rdf");
	addNewsSource("Linux Weekly News", "http://lwn.net/headlines/rss");

	emit changed(true);
}

QString KCMNewsTicker::quickHelp() const
{
	return i18n("<h1>News Ticker</h1> This module allows you to configure the"
			" news ticker applet for KDE's panel. Here, you can configure"
			" general settings such as how often KNewsTicker will check for"
			" new articles as well as managing the list of news sources"
			" which KNewsTicker will query for new articles.");
}

void KCMNewsTicker::slotConfigChanged()
{
	emit changed(true);
}

bool KCMNewsTicker::eventFilter(QObject *o, QEvent *e)
{
	if (o == _child->lvNewsSources) {
		if (e->type() == QEvent::DragEnter) {
			QDragEnterEvent *event = static_cast<QDragEnterEvent *>(e);
			if (QTextDrag::canDecode(event)) {
				event->accept();
				return true;
			}
		} else if (e->type() == QEvent::Drop) {
			QString url;
			if (QTextDrag::decode(static_cast<QDropEvent *>(e), url)) {
				addNewsSource(i18n("Unknown"), url);
				return true;
			}
		}
	}

	return KCModule::eventFilter(o, e);
}

void KCMNewsTicker::resizeEvent(QResizeEvent *)
{
	_child->resize(width(), height());
}

void KCMNewsTicker::addNewsSource(const QString &name, const QString &url, uint maxArticles, bool select)
{
	QListViewItem *item = new QListViewItem(_child->lvNewsSources, name, url, QString::number(maxArticles));
	item->setPixmap(0, KGlobal::iconLoader()->loadIcon("news", KIcon::Small));
	if (select)
		_child->lvNewsSources->setCurrentItem(item);
	emit changed(true);
}

void KCMNewsTicker::addNewsSource(QListViewItem *item)
{
	addNewsSource(item->text(0), item->text(1), item->text(2).toInt(), true);
}

void KCMNewsTicker::removeNewsSource(QListViewItem *item)
{
	if (KMessageBox::warningYesNo(this, i18n("Do you really want to remove the news"
					" source '%1'?<br><br>Press 'Yes' to remove the news source from the list,"
					" press 'No' to keep it and close this dialog.").arg(item->text(0))) == KMessageBox::Yes) {
		_child->lvNewsSources->takeItem(item);
		emit changed(true);
	}
}

void KCMNewsTicker::slotContextMenu(KListView *, QListViewItem *item, const QPoint &)
{
	KPopupMenu *menu = new KPopupMenu();

	QIconSet addIcon = QIconSet(KGlobal::iconLoader()->loadIcon("news_subscribe", KIcon::Small));
	QIconSet removeIcon = QIconSet(KGlobal::iconLoader()->loadIcon("news_unsubscribe", KIcon::Small));

	menu->insertTitle(KGlobal::iconLoader()->loadIcon("knode", KIcon::Small), i18n("Edit news sources"));
	menu->insertItem(addIcon, i18n("&Add news source"), 0);
	if (item != 0)
		menu->insertItem(removeIcon, i18n("&Remove '%1'").arg(item->text(0)), 1);
	else {
		menu->insertItem(removeIcon, i18n("&Remove news source"), 1);
		menu->setItemEnabled(1, false);
	}

	uint result = menu->exec(QCursor::pos());

	switch (result) {
		case 0:
			if (item != 0)
				addNewsSource(item);
			else if (_child->lvNewsSources->childCount() > 0)
				addNewsSource(_child->lvNewsSources->firstChild());
			else
				addNewsSource(i18n("Unknown"), "", 10, true);
			break;
		case 1:
			removeNewsSource(item);
	}

	delete menu;
}

void KCMNewsTicker::slotChooseFont()
{
	KFontDialog fd(this, "Font Dialog", false, true);

	fd.setFont(_font);

	if (fd.exec() == KFontDialog::Accepted) {
		if (_font != fd.font()) {
			_font = fd.font();
			emit changed(true);
		}
	}
}

void KCMNewsTicker::slotAddNewsSource()
{
	if (_child->lvNewsSources->selectedItem() != 0)
		addNewsSource(_child->lvNewsSources->selectedItem());
	else if (_child->lvNewsSources->childCount() > 0)
		addNewsSource(_child->lvNewsSources->firstChild());
	else
		addNewsSource(i18n("Unknown"), "", 10, true);
}

void KCMNewsTicker::slotRemoveNewsSource()
{
	if (_child->lvNewsSources->selectedItem() != 0)
		removeNewsSource(_child->lvNewsSources->selectedItem());
}

void KCMNewsTicker::slotSelectionChanged(QListViewItem *item)
{
	bool itemSelected = item != 0;

	_child->bRemove->setEnabled(itemSelected);
	_child->lName->setEnabled(itemSelected);
	_child->leName->setEnabled(itemSelected);
	_child->lSourceFile->setEnabled(itemSelected);
	_child->leSourceFile->setEnabled(itemSelected);
	_child->tbBrowse->setEnabled(itemSelected);
	_child->lMaxArticles->setEnabled(itemSelected);
	_child->sbMaxArticles->setEnabled(itemSelected);
	_child->tbUp->setEnabled(itemSelected);
	_child->tbDown->setEnabled(itemSelected);

	if (itemSelected) {
		_child->leName->setText(item->text(0));
		_child->leSourceFile->setText(item->text(1));
		_child->sbMaxArticles->setValue(item->text(2).toInt());
	}
}

void KCMNewsTicker::slotNameChanged(const QString &name)
{
	QListViewItem *item = _child->lvNewsSources->selectedItem();

	if (item == 0)
		return;

	if (item->text(0) != name) {
		item->setText(0, name);
		emit changed(true);
	}
}

void KCMNewsTicker::slotSourceFileChanged(const QString &sourceFile)
{
	QListViewItem *item = _child->lvNewsSources->selectedItem();

	if (item == 0)
		return;

	if (item->text(1) != sourceFile) {
		item->setText(1, sourceFile);
		emit changed(true);
	}
}

void KCMNewsTicker::slotMaxArticlesChanged(int maxArticles)
{
	QListViewItem *item = _child->lvNewsSources->selectedItem();

	if (item == 0)
		return;

	if (item->text(2).toInt() != maxArticles) {
		item->setText(2, QString::number(maxArticles));
		emit changed(true);
	}
}

void KCMNewsTicker::slotMoveItemUp()
{
	QListViewItem *item = _child->lvNewsSources->selectedItem();

	if (item == 0)
		return;

	if (item->itemAbove() != 0)
		item->itemAbove()->moveItem(item);
}

void KCMNewsTicker::slotMoveItemDown()
{
	QListViewItem *item = _child->lvNewsSources->selectedItem();

	if (item == 0)
		return;

	if (item->itemBelow() != 0)
		item->moveItem(item->itemBelow());
}

void KCMNewsTicker::slotBrowse()
{
	QString sourceFile = KFileDialog::getOpenFileName(QString::null, "*", this);

	if (QFileInfo(sourceFile).exists()) {
		_child->leSourceFile->setText(sourceFile);
		slotSourceFileChanged(sourceFile);
	}
}

extern "C"
{
	KCModule *create_newsticker(QWidget *parent, const char *name)
	{
		KGlobal::locale()->insertCatalogue("kcmnewsticker");
		return new KCMNewsTicker(parent, name);
	};
}

#include "kcmnewsticker.moc"
