/* This file is part of the KDE Linux Kernel Configurator
   Copyright (c) 2001 Malte Starostik <malte@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; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

// $Id: configlist.cpp,v 1.14 2002/03/13 21:32:23 malte Exp $

#include <qheader.h>
#include <qtimer.h>

#include <kiconloader.h>
#include <klocale.h>
#include <kstandarddirs.h>

#include "configparser.h"
#include "configlist.moc"

using namespace Config;

void ConfigListItem::setOpen(const bool open)
{
	if (m_node->type() == Node::Menu)
		setPixmap(0, open ? SmallIcon("down") : SmallIcon("forward"));

	KListViewItem::setOpen(open);
}

void ConfigListItem::initialize()
{
	switch (m_node->type())
	{
		case Node::Root:
			setText(0, static_cast<RootNode *>(m_node)->name()->text());
			setPixmap(0, SmallIcon("penguin"));
			break;
		case Node::Menu:
			setText(0, static_cast<MenuNode *>(m_node)->comment()->text());
			setPixmap(0, SmallIcon("forward"));
			break;
		case Node::Comment:
		case Node::Text:
			setText(0, static_cast<TextNodeBase *>(m_node)->text());
			setPixmap(0, SmallIcon("idea"));
			break;
		case Node::Input:
		{
			InputNode *input = static_cast<InputNode *>(m_node);
			setText(0, input->prompt());
			switch (input->inputType())
			{
				case InputNode::Bool:
					if (input->value() == "y")
						setPixmap(0, locate("data", "kcmlinuz/data/yes.png"));
					else
						setPixmap(0, locate("data", "kcmlinuz/data/no.png"));
					break;
				case InputNode::Hex:
				case InputNode::Int:
				case InputNode::String:
					setText(1, input->value());
					break;
				case InputNode::Tristate:
					if (input->value() == "m")
						setPixmap(0, locate("data", "kcmlinuz/data/module.png"));
					else if (input->value() == "y")
						setPixmap(0, locate("data", "kcmlinuz/data/yes.png"));
					else
						setPixmap(0, locate("data", "kcmlinuz/data/no.png"));
					break;
				default:
					break;
			}
			break;
		}
		case Node::Choice:
		{
			ChoiceNode *choice = static_cast<ChoiceNode *>(m_node);
			setText(0, choice->prompt());
			if (!firstChild())
			{
				ChoiceListItem *kid = 0;
				int i = 0;
				for (QStringList::ConstIterator it = choice->labels().begin();
					it != choice->labels().end();
					++it)
				{
					kid = new ChoiceListItem(this, kid, i++);
					kid->initialize();
				}
			}
			else
				for (QListViewItem *it = firstChild(); it; it = it->nextSibling())
					static_cast<ChoiceListItem *>(it)->initialize();
		}
		default:
			break;
	}

	// Index children by node
	ItemDict dict;
    dict.setAutoDelete(true); // will delete remaining items
	for (QListViewItem *it = firstChild(); it; it = it->nextSibling())
		if (static_cast<ConfigListItem *>(it)->m_node != m_node)
			dict.insert(static_cast<ConfigListItem *>(it)->m_node, it);

	buildTree(m_node, dict);
}

void ConfigListItem::activate()
{
	QPoint pt;
	if (m_node->type() == Node::Input &&
		(!activatedPos(pt) || QRect(0, 0, height(), height()).contains(pt)))
	{
		InputNode *input = static_cast<InputNode *>(m_node);
		if (input->inputType() == InputNode::Bool)
			static_cast<BoolInputNode *>(input)->toggle();
		else if (input->inputType() == InputNode::Tristate)
			static_cast<TristateInputNode *>(input)->advance();
		else
			return;
		static_cast<ConfigListView *>(listView())->apply();
	}
}

QListViewItem *ConfigListItem::buildTree(Node *node, ItemDict &dict, QListViewItem *after)
{
	if (node->type() != Node::Root &&
		node->type() != Node::Menu &&
		node->type() != Node::If)
		return after;

	NodeList *kids = static_cast<BranchNodeBase *>(node)->children();
	if (kids)
	{
		// Insert / update the nodes that are still there or new
		for (Node *kid = kids->first(); (kid = kids->current()); kids->next())
		{
			if (kid->type() == Node::Root ||
				kid->type() == Node::Comment ||
				kid->type() == Node::Text ||
				kid->type() == Node::Menu ||
				(kid->type() == Node::Input && static_cast<InputNode *>(kid)->isAvailable()) ||
				kid->type() == Node::Choice)
			{
				QListViewItem *found = dict.take(kids->current());
				if (found)
					after = found;
				else
					after = new ConfigListItem(this, after, kids->current());
				static_cast<ConfigListItem *>(after)->initialize();
			}
			else
				after = buildTree(kids->current(), dict, after);
		}
	}
	return after;
}

bool ConfigListItem::canEdit() const
{
	if (m_node->type() == Node::Input)
		switch (static_cast<InputNode *>(m_node)->inputType())
		{
			case InputNode::Hex:
			case InputNode::Int:
			case InputNode::String:
				return true;
			default:
				break;
		}
	return false;
}

QString ConfigListItem::help() const
{
	QString symbol;
	switch (m_node->type())
	{
		case Node::Input:
			symbol = static_cast<InputNode *>(m_node)->symbol();
			break;
		case Node::Choice:
			symbol = static_cast<ChoiceNode *>(m_node)->symbols()[0];
			break;
		default:
			break;
	}
	return symbol.isEmpty() ? QString::null : Parser::self()->helpText(symbol);
}

void ConfigListItem::apply()
{
	if (m_node->type() == Node::Input)
		static_cast<InputNode *>(m_node)->setValue(text(1));
}

void ChoiceListItem::initialize()
{
	ChoiceNode *choice = static_cast<ChoiceNode *>(static_cast<ConfigListItem *>(parent())->m_node);
	setText(0, choice->labels()[m_index]);
	if (choice->index() == m_index)
		setPixmap(0, locate("data", "kcmlinuz/data/yes.png"));
	else
		setPixmap(0, QPixmap());
}

void ChoiceListItem::activate()
{
	static_cast<ChoiceNode *>(static_cast<ConfigListItem *>(parent())->m_node)->setIndex(m_index);
	static_cast<ConfigListView *>(listView())->apply();
}

ConfigListView::ConfigListView(QWidget *parent, const char *name)
	: KListView(parent, name)
{
	header()->setClickEnabled(false);
	addColumn(i18n("Option"));
	addColumn(i18n("Value"));
	setRootIsDecorated(true);
	setSorting(-1);
	setItemsRenameable(true);
	setRenameable(1, true);
	setAllColumnsShowFocus(true);
	connect(this, SIGNAL(itemRenamed(QListViewItem *)), SLOT(edited(QListViewItem *)));
}

void ConfigListView::rename(QListViewItem *item, int c)
{
	if (c == 1 && static_cast<ConfigListItem *>(item)->canEdit())
		KListView::rename(item, c);
}

void ConfigListView::slotUpdate()
{
	if (!firstChild())
		return;
	static_cast<ConfigListItem *>(firstChild())->initialize();
}

void ConfigListView::apply()
{
	Parser::self()->apply();
	QTimer::singleShot(0, this, SLOT(slotUpdate()));
	emit changed();
}

void ConfigListView::edited(QListViewItem *item)
{
	static_cast<ConfigListItem *>(item)->apply();
	apply();
}

// vim: ts=4 sw=4 noet
