/* This file is part of the KDE project
   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <kdebug.h>

#include <tqpainter.h>

#include <kiconloader.h>
#include <tdelocale.h>

#include "objecttree.h"
#include "form.h"
#include "container.h"
#include "formmanager.h"
#include "widgetlibrary.h"

#include "objecttreeview.h"

using namespace KFormDesigner;

ObjectTreeViewItem::ObjectTreeViewItem(ObjectTreeViewItem *parent, ObjectTreeItem *item)
 : TDEListViewItem(parent, item->name(), item->className())
{
	m_item = item;
}

ObjectTreeViewItem::ObjectTreeViewItem(TDEListView *list, ObjectTreeItem *item)
 : TDEListViewItem(list, item ? item->name() : TQString(), item ? item->className() : TQString())
{
	m_item = item;
}

ObjectTreeViewItem::~ObjectTreeViewItem()
{
}

TQString
ObjectTreeViewItem::name() const
{
	if(m_item)
		return m_item->name();
    else
        return TQString();
}

void
ObjectTreeViewItem::paintCell(TQPainter *p, const TQColorGroup & cg, int column, int width, int align)
{
	int margin = listView()->itemMargin();
	if(column == 1)
	{
		if(!m_item)
			return;
		TDEListViewItem::paintCell(p, cg, column, width, align);
	}
	else
	{
		if(!m_item)
			return;

		p->fillRect(0,0,width, height(), TQBrush(backgroundColor()));

		if(isSelected())
		{
			p->fillRect(0,0,width, height(), TQBrush(cg.highlight()));
			p->setPen(cg.highlightedText());
		}

		TQFont f = listView()->font();
		p->save();
		if(isSelected())
			f.setBold(true);
		p->setFont(f);
		if(depth() == 0) // for edit tab order dialog
		{
			TQString iconName 
				= ((ObjectTreeView*)listView())->iconNameForClass(m_item->widget()->className());
			p->drawPixmap(margin, (height() - IconSize(TDEIcon::Small))/2 , SmallIcon(iconName));
			p->drawText(
				TQRect(2*margin + IconSize(TDEIcon::Small),0,width, height()-1), 
				TQt::AlignVCenter, m_item->name());
		}
		else
			p->drawText(TQRect(margin,0,width, height()-1), TQt::AlignVCenter, m_item->name());
		p->restore();

		p->setPen( TQColor(200,200,200) ); //like in t.v.
		p->drawLine(width-1, 0, width-1, height()-1);
	}

	p->setPen( TQColor(200,200,200) ); //like in t.v.
	p->drawLine(-150, height()-1, width, height()-1 );
}

void
ObjectTreeViewItem::paintBranches(TQPainter *p, const TQColorGroup &cg, int w, int y, int h)
{
	p->eraseRect(0,0,w,h);
	ObjectTreeViewItem *item = (ObjectTreeViewItem*)firstChild();
	if(!item || !item->m_item || !item->m_item->widget())
		return;

	p->save();
	p->translate(0,y);
	while(item)
	{
		p->fillRect(0,0,w, item->height(), TQBrush(item->backgroundColor()));
		p->fillRect(-150,0,150, item->height(), TQBrush(item->backgroundColor()));
		p->save();
		p->setPen( TQColor(200,200,200) ); //like in t.v.
		p->drawLine(-150, item->height()-1, w, item->height()-1 );
		p->restore();

		if(item->isSelected())
		{
			p->fillRect(0,0,w, item->height(), TQBrush(cg.highlight()));
			p->fillRect(-150,0,150, item->height(), TQBrush(cg.highlight()));
		}

		TQString iconName 
			= ((ObjectTreeView*)listView())->iconNameForClass(item->m_item->widget()->className());
		p->drawPixmap(
			(w - IconSize(TDEIcon::Small))/2, (item->height() - IconSize(TDEIcon::Small))/2 , 
			SmallIcon(iconName));

		p->translate(0, item->totalHeight());
		item = (ObjectTreeViewItem*)item->nextSibling();
	}
	p->restore();
}

void
ObjectTreeViewItem::setup()
{
	TDEListViewItem::setup();
	if(!m_item)
		setHeight(0);
}

void
ObjectTreeViewItem::setOpen( bool o )
{
	//don't allow to collapse the node, user may be tricked because we're not displaying [+] marks
	if (o)
		TDEListViewItem::setOpen(o);
}

// ObjectTreeView itself ----------------

ObjectTreeView::ObjectTreeView(TQWidget *parent, const char *name, bool tabStop)
 : TDEListView(parent, name)
 , m_form(0)
{
	addColumn(i18n("Name"), 130);
	addColumn(i18n("Widget's type", "Type"), 100);

	installEventFilter(this);

	connect((TQObject*)header(), TQT_SIGNAL(sectionHandleDoubleClicked(int)), this, TQT_SLOT(slotColumnSizeChanged(int)));
	if(!tabStop)
	{
		setSelectionModeExt(Extended);
		connect(this, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotSelectionChanged()));
		connect(this, TQT_SIGNAL(contextMenu(TDEListView *, TQListViewItem *, const TQPoint&)), this, TQT_SLOT(displayContextMenu(TDEListView*, TQListViewItem*, const TQPoint&)));
	}

	setFullWidth(true);
	setAllColumnsShowFocus(true);
	setItemMargin(3);
	setSorting(-1);
}

ObjectTreeView::~ObjectTreeView()
{
}

TQSize
ObjectTreeView::sizeHint() const
{
	return TQSize( TQFontMetrics(font()).width(columnText(0)+columnText(1)+"   "),
		TDEListView::sizeHint().height());
}

TQString
ObjectTreeView::iconNameForClass(const TQCString &classname)
{
	return m_form->library()->iconName(classname);
}

void
ObjectTreeView::slotColumnSizeChanged(int)
{
	setColumnWidth(1, viewport()->width() - columnWidth(0));
}

void
ObjectTreeView::displayContextMenu(TDEListView *list, TQListViewItem *item, const TQPoint &)
{
	if(list != this || !m_form || !item)
		return;

	TQWidget *w = ((ObjectTreeViewItem*)item)->m_item->widget();
	if(!w)
		return;

	FormManager::self()->createContextMenu(w, m_form->activeContainer());
}

ObjectTreeViewItem*
ObjectTreeView::findItem(const TQString &name)
{
	TQListViewItemIterator it(this);
        while(it.current())
	{
		ObjectTreeViewItem *item = static_cast<ObjectTreeViewItem*>(it.current());
		if(item->name() == name)
		{
			return item;
		}
		it++;
	}
	return 0;
}

void
ObjectTreeView::setSelectedWidget(TQWidget *w, bool add)
{
	blockSignals(true); // to avoid recursion

	if(!w)
	{
		clearSelection();
		blockSignals(false);
		return;
	}

	if(selectedItems().count() == 0)
		add = false;

	if(!add)
		clearSelection();


	TQListViewItem *item = (TQListViewItem*) findItem(w->name());
	if(!add)
	{
		setCurrentItem(item);
		setSelectionAnchor(item);
		setSelected(item, true);
	}
	else
		setSelected(item, true);

	blockSignals(false);
}

void
ObjectTreeView::slotSelectionChanged()
{
	const bool hadFocus = hasFocus();
	TQPtrList<TQListViewItem> list = selectedItems();
	m_form->selectFormWidget();
	for(TQListViewItem *item = list.first(); item; item = list.next())
	{
		ObjectTreeViewItem *it = static_cast<ObjectTreeViewItem*>(item);
		TQWidget *w = it->objectTree()->widget();
		if(w && (m_form->selectedWidgets()->findRef(w) == -1))
			m_form->setSelectedWidget(w, true, true);
	}
	if (hadFocus)
		setFocus(); //restore focus
}

void
ObjectTreeView::addItem(ObjectTreeItem *item)
{
	ObjectTreeViewItem *parent=0;

	parent = findItem(item->parent()->name());
	if(!parent)
		return;

	loadTree(item, parent);
}

void
ObjectTreeView::removeItem(ObjectTreeItem *item)
{
	if(!item)
		return;
	ObjectTreeViewItem *it = findItem(item->name());
	delete it;
}

void
ObjectTreeView::renameItem(const TQCString &oldname, const TQCString &newname)
{
	if(findItem(newname))
		return;
	ObjectTreeViewItem *item = findItem(oldname);
	if(!item)
		return;
	item->setText(0, newname);
}

void
ObjectTreeView::setForm(Form *form)
{
	if (m_form)
		disconnect(m_form, TQT_SIGNAL(destroying()), this, TQT_SLOT(slotBeforeFormDestroyed()));
	m_form = form;
	m_topItem = 0;
	clear();

	if(!m_form)
		return;

	connect(m_form, TQT_SIGNAL(destroying()), this, TQT_SLOT(slotBeforeFormDestroyed()));

	// Creates the hidden top Item
	m_topItem = new ObjectTreeViewItem(this);
	m_topItem->setSelectable(false);
	m_topItem->setOpen(true);

	ObjectTree *tree = m_form->objectTree();
	loadTree(tree, m_topItem);

	if(!form->selectedWidgets()->isEmpty())
		setSelectedWidget(form->selectedWidgets()->first());
	else
		setSelectedWidget(form->widget());
}

void
ObjectTreeView::slotBeforeFormDestroyed()
{
	setForm(0);
}

ObjectTreeViewItem*
ObjectTreeView::loadTree(ObjectTreeItem *item, ObjectTreeViewItem *parent)
{
	if(!item)
		return 0;
	ObjectTreeViewItem *treeItem = new ObjectTreeViewItem(parent, item);
	treeItem->setOpen(true);

	// The item is inserted by default at the beginning, but we want it to be at the end, so we move it
	TQListViewItem *last = parent->firstChild();
	while(last->nextSibling())
		last = last->nextSibling();
	treeItem->moveItem(last);

	ObjectTreeList *list = item->children();
	for(ObjectTreeItem *it = list->first(); it; it = list->next())
		loadTree(it, treeItem);

	return treeItem;
}

#include "objecttreeview.moc"
