/***************************************************************************
                          kxe_treeviewitem.cpp  -  description
                             -------------------
    begin                : Wed Nov 21 2001
    copyright            : (C) 2001, 2002, 2003 by The KXMLEditor Team
    email                : lvanek@users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "kxe_treeviewitem.h"

#include "kxmleditorfactory.h"
#include "kxeconfiguration.h"
#include "kxetreeviewsettings.h"

#include "qdom_add.h"

#include <tqregexp.h>

#include <tdelistview.h>
#include <kdebug.h>
#include <kiconloader.h>

KXE_TreeViewItem::KXE_TreeViewItem( const TQDomNode & xmlNode, TQListViewItem * pParent )
	: TQListViewItem(pParent),
	  m_xmlNode(xmlNode),
	  m_pPrevSibling(0),
	  m_bBookmarked(false),
	  m_bChildsCreated(false),
	  m_bGrandChildsCreated(false)
{
	init();
	initChilds();
}

KXE_TreeViewItem::KXE_TreeViewItem( const TQDomNode & xmlNode, TDEListView * pParent,  TQListViewItem* pAfter)
	: TQListViewItem(pParent,pAfter),
	  m_xmlNode(xmlNode),
	  m_pPrevSibling(0),
	  m_bBookmarked(false),
	  m_bChildsCreated(false),
	  m_bGrandChildsCreated(false)
{
	init();
	initChilds();
}

KXE_TreeViewItem::KXE_TreeViewItem( const TQDomNode & xmlNode, TQListViewItem * pParent, TQListViewItem * pAfter )
	: TQListViewItem( pParent, pAfter ),
	  m_xmlNode(xmlNode),
	  m_pPrevSibling(0),
	  m_bBookmarked(false),
	  m_bChildsCreated(false),
	  m_bGrandChildsCreated(false)
{
	init();
	initChilds();
}

KXE_TreeViewItem::~KXE_TreeViewItem()
{
  // inform the next sibling (if there's any) about destroying this item (as its previous sibling)
	KXE_TreeViewItem * pNextItem = static_cast <KXE_TreeViewItem*> (nextSibling());
	if ( pNextItem )
		{ pNextItem->setPrevSibling(m_pPrevSibling);
    }
}

void KXE_TreeViewItem::init()
{
	// A tree view item can only be in-place renameable, if it represents an XML element
	// (the final check occurs in KXE_TreeViewItem::startRename).
	if ( m_xmlNode.isElement() )
		setRenameEnabled( 0, true );

	// inform the next sibling (if there's any) about this item (as its previous sibling)
	KXE_TreeViewItem * pNextItem = static_cast <KXE_TreeViewItem*> (nextSibling());
	if ( pNextItem )
		pNextItem->setPrevSibling(this);

	setPixmap(0, domTool_getIconForNodeType(m_xmlNode.nodeType(), false));

	if ( domTool_getLevel(m_xmlNode) < (unsigned int)KXMLEditorFactory::configuration()->treeview()->dfltExpLevel() )
		setOpen(true);

	setTexts();
}

void KXE_TreeViewItem::setTexts()
{
	switch ( m_xmlNode.nodeType() )
	{
		case TQDomNode::ElementNode:

			setText( 0, m_xmlNode.toElement().nodeName() );

			if ( KXMLEditorFactory::configuration()->treeview()->elemDisplMode() == KXETreeViewSettings::NoAttributes )
				setText( 1, TQString() );
			else
			{
				// parse all attributes to fill the second column
				TQString str2ndCol;
				for ( uint i=0; i < m_xmlNode.toElement().attributes().length(); i++ )
				{
					if ( i > 0 )
						str2ndCol += ", ";
					str2ndCol += m_xmlNode.toElement().attributes().item(i).toAttr().name();
					if ( KXMLEditorFactory::configuration()->treeview()->elemDisplMode() == KXETreeViewSettings::NamesAndValues )
						str2ndCol += '=' + m_xmlNode.toElement().attributes().item(i).toAttr().value();
				}
				setText( 1, str2ndCol );
			}
			break;

		case TQDomNode::TextNode:
		case TQDomNode::CDATASectionNode:
		case TQDomNode::CommentNode:
		{
			// set name
			TQString strText = m_xmlNode.toCharacterData().data();
			strText = strText.replace( TQRegExp("\n"), " " ); // replace every newline by a space
			strText = strText.replace( TQRegExp("\t"), "" ); // removes every tab
			strText = strText.replace( TQRegExp("\r"), "" ); // removes every return
			strText = strText.simplifyWhiteSpace();
			if( strText.length() > 30 ) // reduce name length, if necessary
				strText = strText.left(30) + "...";
			setText( 0, strText );

			break;
		}

		case TQDomNode::ProcessingInstructionNode:

			setText( 0, m_xmlNode.toProcessingInstruction().target() );
			break;

		default:
			kdDebug() << "KXE_TreeViewItem::init: unknown node type (" << m_xmlNode.nodeType() << ")" << endl;
	}
}

void KXE_TreeViewItem::initChilds()
{
	if ( ! KXMLEditorFactory::configuration()->treeview()->createItemsOnDemand() ||
	     ( ! m_bChildsCreated && 
	       ( ! parent() || ( parent() && parent()->isOpen() ) ) 
	     ) 
	   )
		ensureChildItemsCreated();
}

bool KXE_TreeViewItem::toggleBookmark()
{
	m_bBookmarked = ! m_bBookmarked;

	setPixmap(0, domTool_getIconForNodeType(m_xmlNode.nodeType(), m_bBookmarked));
	
	return m_bBookmarked;
}

KXE_TreeViewItem * KXE_TreeViewItem::lastChild() const
{
	// take the first child
	TQListViewItem * pTmpItem = firstChild();
	// if there are no childs return 0
	if ( ! pTmpItem )
		return 0;

  TQListViewItem * pTmpItem2;
	while ( (pTmpItem2 = pTmpItem->nextSibling()) != 0 )     // traversing all childs
		{
      pTmpItem = pTmpItem2;
    }
    
	return static_cast <KXE_TreeViewItem*> (pTmpItem);
}

KXE_TreeViewItem * KXE_TreeViewItem::prevItem()
{
  if ( m_pPrevSibling ) // if there is a prev. sibling
	{                     // return its last grand child (if there is any)
		KXE_TreeViewItem * pPrevItem = m_pPrevSibling;
		KXE_TreeViewItem * pTmpItem;
		while ( (pTmpItem=pPrevItem->lastChild()) )
			pPrevItem = pTmpItem;
		return pPrevItem;
	}
	else                                                 // if there is no prev. sibling,
		return static_cast <KXE_TreeViewItem*> (parent()); // return this' parent (if there is any)
}

KXE_TreeViewItem * KXE_TreeViewItem::nextItem()
{
  // checking for a child
	TQListViewItem * pTmp = firstChild();
	if (pTmp)
		return static_cast <KXE_TreeViewItem*> (pTmp);

	// there is no child -> checking for the next sibling
	pTmp = nextSibling();
	if (pTmp)
		return static_cast <KXE_TreeViewItem*> (pTmp);

	// there is no next sibling -> checking for parents' next sibling(s)
	TQListViewItem * pParent = parent();
	while (pParent)
	{
		pTmp = pParent->nextSibling();
		if (pTmp)
			return static_cast <KXE_TreeViewItem*> (pTmp);
		pParent = pParent->parent();
	}
	return 0;
}

void KXE_TreeViewItem::expandSubTree( int iLevel )
{
	setOpen(true); // expand this item

	if ( iLevel == 0 ) // return, if we are deep enough
		return;
	
	// expand childs (recursive)
	int iNewLevel = ( iLevel == -1 ) ? -1 : iLevel-1;
	KXE_TreeViewItem * pChild = static_cast <KXE_TreeViewItem*> ( firstChild() );
	while ( pChild )
	{
		pChild->expandSubTree(iNewLevel);
		pChild = static_cast <KXE_TreeViewItem*> ( pChild->nextSibling() );
	}
}

void KXE_TreeViewItem::collapseSubTree( int iLevel )
{
	if ( iLevel < 0 )
	{
		kdDebug() << "KXE_TreeViewItem::collapseSubTree: wrong level given (iLevel=" << iLevel << ")" << endl;
		return;
	}

	int iNewLevel;
	if (iLevel==0)     // collapse this item,
	{                  // because we are deep enough
		setOpen(false);
		iNewLevel = 0;
	}
	else
		iNewLevel = iLevel - 1;

	// collapsing in childs (recursive)
	KXE_TreeViewItem * pChild = static_cast <KXE_TreeViewItem*> ( firstChild() );
	while ( pChild )
	{
		pChild->collapseSubTree( iNewLevel );
		pChild = static_cast <KXE_TreeViewItem*> ( pChild->nextSibling() );
	}
}

/** Test, if item in parameter is my direct or indirect child item */
bool KXE_TreeViewItem::isMyChildren(const KXE_TreeViewItem *pTestItem)
{
	KXE_TreeViewItem* pChildXmlTreeItem = (KXE_TreeViewItem*) firstChild();
  while(pChildXmlTreeItem)
		{ if(pChildXmlTreeItem == pTestItem)
				return true;

			// test child item childrens	
			if(pChildXmlTreeItem->isMyChildren(pTestItem))	
				return true;
				
			pChildXmlTreeItem = (KXE_TreeViewItem*) pChildXmlTreeItem->nextSibling();
    }
	return false;
}


void KXE_TreeViewItem::ensureChildItemsCreated()
{
	if ( ! m_bChildsCreated )
	{
		TQDomNode tmpNode = m_xmlNode.lastChild();

		while ( ! tmpNode.isNull() )
		{
			new KXE_TreeViewItem( tmpNode, this );
			tmpNode = tmpNode.previousSibling();		
		}

		m_bChildsCreated = true;
	}
}


void KXE_TreeViewItem::ensureGrandChildItemsCreated()
{
	if ( ! m_bGrandChildsCreated )
	{
		// ensure, that all child items of this item are created
		if ( ! m_bChildsCreated )
			ensureChildItemsCreated();

		// Iterate over all children now and ensure their child items 
		// (this' grandchildrens) are created.
		KXE_TreeViewItem * pChild = static_cast <KXE_TreeViewItem*> ( firstChild() );
		while ( pChild )
		{
			pChild->ensureChildItemsCreated();
			pChild = static_cast <KXE_TreeViewItem*> ( pChild->nextSibling() );
		}

		m_bGrandChildsCreated = true;
	}
}

void KXE_TreeViewItem::startRename( int iCol )
{
	// If the given column is set to be in-place renameable in this item's view,
	// we can start renaming in-place.
	// Remember: This function is only reached for items representing XML elements.
	if ( (reinterpret_cast<TDEListView*> ( listView() ))->isRenameable( iCol ) )
		TQListViewItem::startRename( iCol );
}