/* This file is part of the KDE project
   Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
   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 <tqpainter.h>
#include <tqpixmap.h>
#include <tqrect.h>
#include <tqevent.h>
#include <tqvaluevector.h>
#include <tqlayout.h>
#include <tqcursor.h>

#include <kdebug.h>
#include <klocale.h>
#include <kpopupmenu.h>

#include <cstdlib> // for abs()

#include "utils.h"
#include "container.h"
#include "widgetlibrary.h"
#include "objecttree.h"
#include "form.h"
#include "formmanager.h"
#include "commands.h"
#include "events.h"
#include "kexiflowlayout.h"

using namespace KFormDesigner;

EventEater::EventEater(TQWidget *widget, TQObject *container)
 : TQObject(container)
{
	m_widget = widget;
	m_container = container;

	installRecursiveEventFilter(TQT_TQOBJECT(m_widget), this);
}

bool
EventEater::eventFilter(TQObject *, TQEvent *ev)
{
	if(!m_container)
		return false;

	// When the user click the empty part of tab bar, only MouseReleaseEvent is sent,
	// we need to simulate the Press event
	if(ev->type() == TQEvent::MouseButtonRelease && m_widget->inherits(TQTABWIDGET_OBJECT_NAME_STRING))
	{
		TQMouseEvent *mev = TQT_TQMOUSEEVENT(ev);
		if(mev->button() == Qt::LeftButton)
		{
			TQMouseEvent *myev = new TQMouseEvent(TQEvent::MouseButtonPress, mev->pos(), mev->button(), mev->state());
			m_container->eventFilter(m_widget, myev);
			delete myev;
			//return true;
		}
	}
//	else if(ev->type() == TQEvent::ChildInserted) {
		// widget's tqchildren have changed, we need to reinstall filter
//		installRecursiveEventFilter(m_widget, this);
//	}

	return m_container->eventFilter(m_widget, ev);
}

EventEater::~EventEater()
{
	if(m_widget)
		removeRecursiveEventFilter(TQT_TQOBJECT(m_widget), TQT_TQOBJECT(this));
}

// Container itself

Container::Container(Container *toplevel, TQWidget *container, TQObject *parent, const char *name)
: TQObject(parent, name)
, m_insertBegin(-1,-1)
, m_mousePressEventReceived(false)
, m_mouseReleaseEvent(TQEvent::None, TQPoint(), 0, 0)
{
	m_container = container;
	m_toplevel = toplevel;

	m_moving = 0;
	m_tree = 0;
	m_form = toplevel ? toplevel->form() : 0;
	m_layout = 0;
	m_layType = NoLayout;
	m_state = DoingNothing;

	TQCString classname = container->className();
	if((classname == "HBox") || (classname == "Grid") || (classname == "VBox") ||
		(classname == "HFlow")  || (classname == "VFlow"))
		m_margin = 4; // those containers don't have frames, so little margin
	else
		m_margin = m_form ? m_form->defaultMargin() : 0;
	m_spacing = m_form ? m_form->defaultSpacing() : 0;

	if(toplevel)
	{
		ObjectTreeItem *it = new ObjectTreeItem(m_form->library()->displayName(classname),
			widget()->name(), widget(), this, this);
		setObjectTree(it);

		if(parent->isWidgetType())
		{
			TQString n = parent->name();
			ObjectTreeItem *parent = m_form->objectTree()->lookup(n);
			m_form->objectTree()->addItem(parent, it);
		}
		else
			m_form->objectTree()->addItem(toplevel->objectTree(), it);

		connect(toplevel, TQT_SIGNAL(destroyed()), this, TQT_SLOT(widgetDeleted()));
	}

	connect(container, TQT_SIGNAL(destroyed()), this, TQT_SLOT(widgetDeleted()));
}

Container::~Container()
{
	kdDebug() << " Container being deleted this == " << name() << endl;
}

void
Container::setForm(Form *form)
{
	m_form = form;
	m_margin = m_form ? m_form->defaultMargin() : 0;
	m_spacing = m_form ? m_form->defaultSpacing() : 0;
}

bool
Container::eventFilter(TQObject *s, TQEvent *e)
{
//	kdDebug() << e->type() << endl;
	switch(e->type())
	{
		case TQEvent::MouseButtonPress:
		{
			m_insertBegin = TQPoint(-1, -1);
			m_mousePressEventReceived = true;

			kdDebug() << "TQEvent::MouseButtonPress sender object = " << s->name()
				<< "of type " << s->className() << endl;
			kdDebug() << "TQEvent::MouseButtonPress this          = " << name() << endl;

			m_moving = TQT_TQWIDGET(s);
			TQMouseEvent *mev = TQT_TQMOUSEEVENT(e);
			m_grab = TQPoint(mev->x(), mev->y());

			// we are drawing a connection
			if(FormManager::self()->isCreatingConnection())  {
				drawConnection(mev);
				return true;
			}

			if(((mev->state() == ControlButton) || (mev->state() == ShiftButton)) 
				&& (!FormManager::self()->isInserting())) // multiple selection mode
			{
				if(m_form->selectedWidgets()->findRef(m_moving) != -1) // widget is already selected
				{
					if(m_form->selectedWidgets()->count() > 1) // we remove it from selection
						unSelectWidget(m_moving);
					else // the widget is the only selected, so it means we want to copy it
					{
						//m_copyRect = m_moving->tqgeometry();
						m_state = CopyingWidget;
						if(m_form->formWidget())
							m_form->formWidget()->initBuffer();
					}
				}
				else // the widget is not yet selected, we add it
					setSelectedWidget(m_moving, true, (mev->button() == Qt::RightButton));
			}
			else if((m_form->selectedWidgets()->count() > 1))//&& (!m_form->manager()->isInserting())) // more than one widget selected
			{
				if(m_form->selectedWidgets()->findRef(m_moving) == -1) // widget is not selected, it becomes the only selected widget
					setSelectedWidget(m_moving, false, (mev->button() == Qt::RightButton));
				// If the widget is already selected, we do nothing (to ease widget moving, etc.)
			}
			else// if(!m_form->manager()->isInserting())
				setSelectedWidget(m_moving, false, (mev->button() == Qt::RightButton));

			// we are inserting a widget or drawing a selection rect in the form
			if((/*s == m_container &&*/ FormManager::self()->isInserting()) || ((s == m_container) && !m_toplevel))
			{
				int tmpx,tmpy;
				if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (Qt::LeftButton|ControlButton|AltButton)))
				{
					tmpx = mev->x();
					tmpy = mev->y();
				}
				else
				{
					int gridX = m_form->gridSize();
					int gridY = m_form->gridSize();
					tmpx = int( (float)mev->x() / ((float)gridX) + 0.5 ); // snap to grid
					tmpx *= gridX;
					tmpy = int( (float)mev->y() / ((float)gridY) + 0.5 );
					tmpy *= gridX;
				}

				m_insertBegin = (TQT_TQWIDGET(s))->mapTo(m_container, TQPoint(tmpx, tmpy));
				if(m_form->formWidget())
					m_form->formWidget()->initBuffer();

				if(!FormManager::self()->isInserting())
					m_state = DrawingSelectionRect;
			}
			else {
				if(s->inherits(TQTABWIDGET_OBJECT_NAME_STRING)) // to allow changing page by clicking tab
					return false;
			}

			if (m_objectForMouseReleaseEvent) {
				const bool res = handleMouseReleaseEvent(m_objectForMouseReleaseEvent, &m_mouseReleaseEvent);
				m_objectForMouseReleaseEvent = 0;
				return res;
			}
			return true;
		}

		case TQEvent::MouseButtonRelease:
		{
			TQMouseEvent *mev = TQT_TQMOUSEEVENT(e);
			if (!m_mousePressEventReceived) {
				m_mouseReleaseEvent = *mev;
				m_objectForMouseReleaseEvent = s;
				return true;
			}
			m_mousePressEventReceived = false;
			m_objectForMouseReleaseEvent = 0;
			return handleMouseReleaseEvent(s, mev);
		}

		case TQEvent::MouseMove:
		{
			TQMouseEvent *mev = TQT_TQMOUSEEVENT(e);
			if(m_insertBegin!=TQPoint(-1,-1) && FormManager::self()->isInserting() && ((mev->state() == Qt::LeftButton) || (mev->state() == (Qt::LeftButton|ControlButton)) ||
			(mev->state() == (Qt::LeftButton|ControlButton|AltButton)) || (mev->state() == (Qt::LeftButton|ShiftButton)) ) )
			// draw the insert rect
			{
				drawInsertRect(mev, s);
				return true;
			}
			// Creating a connection, we highlight sender and receiver, and we draw a link between them
			else if(FormManager::self()->isCreatingConnection() && !FormManager::self()->createdConnection()->sender().isNull())
			{
				ObjectTreeItem *tree = m_form->objectTree()->lookup(FormManager::self()->createdConnection()->sender());
				if(!tree || !tree->widget())
					return true;

				if(m_form->formWidget() && (TQT_BASE_OBJECT(tree->widget()) != TQT_BASE_OBJECT(s)))
					m_form->formWidget()->highlightWidgets(tree->widget(), TQT_TQWIDGET(s));
			}
			else if(m_insertBegin!=TQPoint(-1,-1) && s == m_container && !m_toplevel && (mev->state() != ControlButton) && !FormManager::self()->isCreatingConnection()) // draw the selection rect
			{
				if((mev->state() != Qt::LeftButton) || /*m_inlineEditing*/ m_state == InlineEditing)
					return true;
				int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() :  mev->x();
				int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
				int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() :  mev->x();
				int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
				TQRect r = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));
				m_insertRect = r;

				if(m_form->formWidget())
					m_form->formWidget()->drawRect(r, 1);

				m_state = DoingNothing;
				return true;
			}
			else if(mev->state() == (Qt::LeftButton|ControlButton)) // draw the insert rect for the copied widget
			{
				if(s == m_container)// || (m_form->selectedWidgets()->count() > 1))
					return true;
				drawCopiedWidgetRect(mev);
				return true;
			}
			else if( ( (mev->state() == Qt::LeftButton) || (mev->state() == (Qt::LeftButton|ControlButton|AltButton)) )
			  && !FormManager::self()->isInserting() && (m_state != CopyingWidget)) // we are dragging the widget(s) to move it
			{
				if(!m_toplevel && m_moving == m_container) // no effect for form
					return false;
				if((!m_moving) || (!m_moving->parentWidget()))// || (m_moving->parentWidget()->inherits(TQWIDGETSTACK_OBJECT_NAME_STRING)))
						return true;

				moveSelectedWidgetsBy(mev->x() - m_grab.x(), mev->y() - m_grab.y());
				m_state = MovingWidget;
			}

			return true; // eat
		}

		case TQEvent::Paint: // Draw the dotted background
		{
			if(s != m_container)
				return false;
			int gridX = m_form->gridSize();
			int gridY = m_form->gridSize();

			TQPainter p(m_container);
			p.setPen(TQPen(white, 2));
			p.setRasterOp(XorROP);
			int cols = m_container->width() / gridX;
			int rows = m_container->height() / gridY;

			for(int rowcursor = 1; rowcursor <= rows; ++rowcursor)
			{
				for(int colcursor = 1; colcursor <= cols; ++colcursor)
				{
					p.drawPoint(-1 + colcursor *gridX, -1 + rowcursor *gridY);
				}
			}

			return false;
		}

		case TQEvent::Resize: // we are resizing a widget, so we set m_move to true -> the tqlayout will be reloaded when releasing mouse
		{
			if(m_form->interactiveMode())
				m_state = MovingWidget;
			break;
		}

		//case TQEvent::AccelOverride:
		case TQEvent::KeyPress:
		{
			TQKeyEvent *kev = TQT_TQKEYEVENT(e);

			if(kev->key() == Key_F2) // pressing F2 == double-clicking
			{
				m_state = InlineEditing;
				TQWidget *w;

				// try to find the widget which was clicked last and should be edited
				if(m_form->selectedWidgets()->count() == 1)
					w = m_form->selectedWidgets()->first();
				else if(m_form->selectedWidgets()->findRef(m_moving) != -1)
					w = m_moving;
				else
					w = m_form->selectedWidgets()->last();
				m_form->library()->startEditing(w->className(), w, this);
			}
			else if(kev->key() == Key_Escape)
			{
				if(FormManager::self()->isCreatingConnection())
					FormManager::self()->stopCreatingConnection();
				else if(FormManager::self()->isInserting())
					FormManager::self()->stopInsert();
				return true;
			}
			else if((kev->key() == Key_Control) && (m_state == MovingWidget))
			{
				if(!m_moving)
					return true;
				// we simulate a mouse move event to update screen
				TQMouseEvent *mev = new TQMouseEvent(TQEvent::MouseMove, m_moving->mapFromGlobal(TQCursor::pos()), Qt::NoButton,
				Qt::LeftButton|ControlButton );
				eventFilter(TQT_TQOBJECT(m_moving), TQT_TQEVENT(mev));
				delete mev;
			}
			else if(kev->key() == FormManager::self()->contextMenuKey())
			{
					FormManager::self()->createContextMenu(TQT_TQWIDGET(s), this, false);
					return true;
			}
			else if (kev->key() == Key_Delete)
			{
				FormManager::self()->deleteWidget();
				return true;
			}
			// directional buttons move the widget
			else if(kev->key() == Key_Left){ // move the widget of gridX to the left
				moveSelectedWidgetsBy(-form()->gridSize(), 0);
				return true;
			}
			else if(kev->key() == Key_Right){ // move the widget of gridX to the right
				moveSelectedWidgetsBy(form()->gridSize(), 0);
				return true;
			}
			else if(kev->key() == Key_Up){ // move the widget of gridY to the top
				moveSelectedWidgetsBy(0, - form()->gridSize());
				return true;
			}
			else if(kev->key() == Key_Down){ // move the widget of gridX to the bottom
				moveSelectedWidgetsBy(0, form()->gridSize());
				return true;
			}
			else if((kev->key() == Key_Tab) || (kev->key() == Key_BackTab)){
				ObjectTreeItem *item = form()->objectTree()->lookup(form()->selectedWidgets()->first()->name());
				if(!item || !item->parent())
					return true;
				ObjectTreeList *list = item->parent()->tqchildren();
				if(list->count() == 1)
					return true;
				int index = list->findRef(item);

				if(kev->key() == Key_BackTab){
					if(index == 0) // go back to the last item
						index = list->count() - 1;
					else
						index = index - 1;
				}
				else  {
					if(index == int(list->count() - 1)) // go back to the first item
						index = 0;
					else
						index = index + 1;
				}

				ObjectTreeItem *nextItem = list->at(index);
				if(nextItem && nextItem->widget())
					form()->setSelectedWidget(nextItem->widget(), false);
			}
			return true;
		}

		case TQEvent::KeyRelease:
		{
			TQKeyEvent *kev = TQT_TQKEYEVENT(e);
			if((kev->key() == Key_Control) && (m_state == CopyingWidget)) {
				// cancel copying
				//m_copyRect = TQRect();
				if(m_form->formWidget())
					m_form->formWidget()->clearForm();
			}
			return true;
		}

		case TQEvent::MouseButtonDblClick: // editing
		{
			kdDebug() << "Container: Mouse dbl click for widget " << s->name() << endl;
			TQWidget *w = TQT_TQWIDGET(s);
			if(!w)
				return false;

			//m_inlineEditing = true;
			m_state = InlineEditing;
			m_form->library()->startEditing(w->className(), w, this);
			return true;
		}

		case TQEvent::ContextMenu:
		case TQEvent::Enter:
		case TQEvent::Leave:
		case TQEvent::FocusIn:
		case TQEvent::FocusOut:
//		case TQEvent::DragEnter:
//		case TQEvent::DragMove:
//		case TQEvent::DragLeave:
			return true; // eat them

		default:
			return false; // let the widget do the rest ...
	}
	return false;
}

bool
Container::handleMouseReleaseEvent(TQObject *s, TQMouseEvent *mev)
{
	if(FormManager::self()->isInserting()) // we insert the widget at cursor pos
	{
		if(m_form->formWidget())
			m_form->formWidget()->clearForm();
		KCommand *com = new InsertWidgetCommand(this/*, mev->pos()*/);
		m_form->addCommand(com, true);
		m_insertBegin = TQPoint(-1,-1);
		m_insertRect = TQRect();
		return true;
	}
	else if(s == m_container && !m_toplevel && (mev->button() != Qt::RightButton) && m_insertRect.isValid()) // we are drawing a rect to select widgets
	{
		drawSelectionRect(mev);
		return true;
	}
	if(mev->button() == Qt::RightButton) // Right-click -> context menu
	{
		FormManager::self()->createContextMenu(TQT_TQWIDGET(s), this);
	}
	else if(mev->state() == (Qt::LeftButton|TQt::ControlButton))// && (m_copyRect.isValid()))
	{
		// copying a widget by Ctrl+dragging

		if(m_form->formWidget())
			m_form->formWidget()->clearForm();
		if(s == m_container) // should have no effect on form
			return true;

		// prevent accidental copying of widget (when moving mouse a little while selecting)
		if( ( (mev->pos().x() - m_grab.x()) < form()->gridSize() &&  (m_grab.x() - mev->pos().x()) < form()->gridSize() ) &&
			( (mev->pos().y() - m_grab.y()) < form()->gridSize() &&  (m_grab.y() - mev->pos().y()) < form()->gridSize() ) )
		{
			kdDebug() << "The widget has not been moved. No copying" << endl;
			return true;
		}

		m_form->setInteractiveMode(false);
		// We simulate copy and paste
		FormManager::self()->copyWidget();
		if(m_form->selectedWidgets()->count() > 1)
			FormManager::self()->setInsertPoint( mev->pos() );
		else
			FormManager::self()->setInsertPoint( TQT_TQWIDGET(s)->mapTo(m_container, mev->pos() - m_grab) );
		FormManager::self()->pasteWidget();
		m_form->setInteractiveMode(true);

		//m_initialPos = TQPoint();
	}
	else if(m_state == MovingWidget) // one widget has been moved, so we need to update the tqlayout
		reloadLayout();

	// cancel copying as user released Ctrl before releasing mouse button
	m_insertBegin = TQPoint(-1,-1);
	m_insertRect = TQRect();
	m_state = DoingNothing;
	return true; // eat
}

void
Container::setSelectedWidget(TQWidget *w, bool add, bool dontRaise, bool moreWillBeSelected)
{
	if (w)
		kdDebug() << "slotSelectionChanged " << w->name()<< endl;

	if(!w)
	{
		m_form->setSelectedWidget(m_container);
		return;
	}

	m_form->setSelectedWidget(w, add, dontRaise, moreWillBeSelected);
}

void
Container::unSelectWidget(TQWidget *w)
{
	if(!w)
		return;

	m_form->unSelectWidget(w);
}

Container*
Container::toplevel()
{
	if(m_toplevel)
		return m_toplevel;
	else
		return this;
}

void
Container::deleteWidget(TQWidget *w)
{
	if(!w)
		return;
//	kdDebug() << "Deleting a widget: " << w->name() << endl;
	m_form->objectTree()->removeItem(w->name());
	FormManager::self()->deleteWidgetLater( w );
	m_form->setSelectedWidget(m_container);
}

void
Container::widgetDeleted()
{
	m_container = 0;
	deleteLater();
}

/// Layout functions

void
Container::setLayout(LayoutType type)
{
	if(m_layType == type)
		return;

	delete m_layout;
	m_layout = 0;
	m_layType = type;

	switch(type)
	{
		case HBox:
		{
			m_layout = (TQLayout*) new TQHBoxLayout(m_container, m_margin, m_spacing);
			createBoxLayout(new HorWidgetList(m_form->toplevelContainer()->widget()));
			break;
		}
		case VBox:
		{
			m_layout = (TQLayout*) new TQVBoxLayout(m_container, m_margin, m_spacing);
			createBoxLayout(new VerWidgetList(m_form->toplevelContainer()->widget()));
			break;
		}
		case Grid:
		{
			createGridLayout();
			break;
		}
		case  HFlow:
		{
			KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
			flow->setOrientation(Qt::Horizontal);
			m_layout = (TQLayout*)flow;
			createFlowLayout();
			break;
		}
		case VFlow:
		{
			KexiFlowLayout *flow = new KexiFlowLayout(m_container,m_margin, m_spacing);
			flow->setOrientation(Qt::Vertical);
			m_layout = (TQLayout*)flow;
			createFlowLayout();
			break;
		}
		default:
		{
			m_layType = NoLayout;
			return;
		}
	}
	m_container->setGeometry(m_container->tqgeometry()); // just update tqlayout
	m_layout->activate();
}

void
Container::reloadLayout()
{
	LayoutType type = m_layType;
	setLayout(NoLayout);
	setLayout(type);
}

void
Container::createBoxLayout(WidgetList *list)
{
	TQBoxLayout *tqlayout = static_cast<TQBoxLayout*>(m_layout);

	for(ObjectTreeItem *tree = m_tree->tqchildren()->first(); tree; tree = m_tree->tqchildren()->next())
		list->append( tree->widget());
	list->sort();

	for(TQWidget *obj = list->first(); obj; obj = list->next())
		tqlayout->addWidget(obj);
	delete list;
}

void
Container::createFlowLayout()
{
	KexiFlowLayout *flow = dynamic_cast<KexiFlowLayout*>(m_layout);
	if(!flow || m_tree->tqchildren()->isEmpty())
		return;

	const int offset = 15;
	WidgetList *list=0, *list2=0;
	if(flow->orientation() ==Qt::Horizontal) {
		list = new VerWidgetList(m_form->toplevelContainer()->widget());
		list2 = new HorWidgetList(m_form->toplevelContainer()->widget());
	}
	else {
		list = new HorWidgetList(m_form->toplevelContainer()->widget());
		list2 = new VerWidgetList(m_form->toplevelContainer()->widget());
	}

	// fill the list
	for(ObjectTreeItem *tree = m_tree->tqchildren()->first(); tree; tree = m_tree->tqchildren()->next())
		list->append( tree->widget());
	list->sort();

	if(flow->orientation() ==Qt::Horizontal) {
		int y = list->first()->y();
		for(TQWidget *w = list->first(); w; w = list->next()) {
			if( (w->y() > y +offset)) {
				// start a new line
				list2->sort();
				for(TQWidget *obj = list2->first(); obj; obj = list2->next())
					flow->add(obj);
				list2->clear();
				y = w->y();
			}
			list2->append(w);
		}

		list2->sort(); // don't forget the last line
		for(TQWidget *obj = list2->first(); obj; obj = list2->next())
			flow->add(obj);
	}
	else {
		int x = list->first()->x();
		for(TQWidget *w = list->first(); w; w = list->next()) {
			if( (w->x() > x +offset)) {
				// start a new column
				list2->sort();
				for(TQWidget *obj = list2->first(); obj; obj = list2->next())
					flow->add(obj);
				list2->clear();
				x = w->x();
			}
			list2->append(w);
		}

		list2->sort(); // don't forget the last column
		for(TQWidget *obj = list2->first(); obj; obj = list2->next())
			flow->add(obj);
	}

	delete list;
	delete list2;
}

void
Container::createGridLayout(bool testOnly)
{
	//Those lists sort widgets by y and x
	VerWidgetList *vlist = new VerWidgetList(m_form->toplevelContainer()->widget());
	HorWidgetList *hlist = new HorWidgetList(m_form->toplevelContainer()->widget());
	// The vector are used to store the x (or y) beginning of each column (or row)
	TQValueVector<int> cols;
	TQValueVector<int> rows;
	int end=-1000;
	bool same = false;

	for(ObjectTreeItem *tree = m_tree->tqchildren()->first(); tree; tree = m_tree->tqchildren()->next())
		vlist->append( tree->widget());
	vlist->sort();

	for(ObjectTreeItem *tree = m_tree->tqchildren()->first(); tree; tree = m_tree->tqchildren()->next())
		hlist->append( tree->widget());
	hlist->sort();

	// First we need to make sure that two widgets won't be in the same row,
	// ie that no widget overlap another one
	if(!testOnly) {
		for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
		{
			TQWidget *w = it.current();
			WidgetListIterator it2 = it;

			for(; it2.current() != 0; ++it2) {
				TQWidget *nextw = it2.current();
				if((w->y() >= nextw->y()) || (nextw->y() >= w->tqgeometry().bottom()))
					break;

				if(!w->tqgeometry().intersects(nextw->tqgeometry()))
					break;
				// If the geometries of the two widgets intersect each other,
				// we move one of the widget to the rght or bottom of the other
				if((nextw->y() - w->y()) > abs(nextw->x() - w->x()))
					nextw->move(nextw->x(), w->tqgeometry().bottom()+1);
				else if(nextw->x() >= w->x())
					nextw->move(w->tqgeometry().right()+1, nextw->y());
				else
					w->move(nextw->tqgeometry().right()+1, nextw->y());
			}
		}
	}

	// Then we count the number of rows in the tqlayout, and set their beginnings
	for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
	{
		TQWidget *w = it.current();
		WidgetListIterator it2 = it;
		if(!same) { // this widget will make a new row
			end = w->tqgeometry().bottom();
			rows.append(w->y());
		}

		// If same == true, it means we are in the same row as prev widget
		// (so no need to create a new column)
		++it2;
		if(!it2.current())
			break;

		TQWidget *nextw = it2.current();
		if(nextw->y() >= end)
			same = false;
		else {
			same = !(same && (nextw->y() >= w->tqgeometry().bottom()));
			if(!same)
				end = w->tqgeometry().bottom();
		}
	}
	kdDebug() << "the new grid will have n rows: n == " << rows.size() << endl;

	end = -10000;
	same = false;
	// We do the same thing for the columns
	for(WidgetListIterator it(*hlist); it.current() != 0; ++it)
	{
		TQWidget *w = it.current();
		WidgetListIterator it2 = it;
		if(!same) {
			end = w->tqgeometry().right();
			cols.append(w->x());
		}

		++it2;
		if(!it2.current())
			break;

		TQWidget *nextw = it2.current();
		if(nextw->x() >= end)
			same = false;
		else {
			same = !(same && (nextw->x() >= w->tqgeometry().right()));
			if(!same)
				end = w->tqgeometry().right();
		}
	}
	kdDebug() << "the new grid will have n columns: n == " << cols.size() << endl;

	// We create the tqlayout ..
	TQGridLayout *tqlayout=0;
	if(!testOnly) {
		tqlayout = new TQGridLayout(m_container, rows.size(), cols.size(), m_margin, m_spacing, "grid");
		m_layout = (TQLayout*)tqlayout;
	}

	// .. and we fill it with widgets
	for(WidgetListIterator it(*vlist); it.current() != 0; ++it)
	{
		TQWidget *w = it.current();
		TQRect r = w->tqgeometry();
		uint wcol=0, wrow=0, endrow=0, endcol=0;
		uint i = 0;

		// We look for widget row(s) ..
		while(r.y() >= rows[i])
		{
			if(rows.size() <= i+1) // we are the last row
			{
				wrow = i;
				break;
			}
			if(r.y() < rows[i+1])
			{
				wrow = i; // the widget will be in this row
				uint j = i + 1;
				// Then we check if the widget needs to span multiple rows
				while(rows.size() >= j+1 && r.bottom() > rows[j])
				{
					endrow = j;
					j++;
				}

				break;
			}
			i++;
		}
		//kdDebug() << "the widget " << w->name() << " wil be in the row " << wrow <<
		   //" and will go to the row " << endrow << endl;

		// .. and column(s)
		i = 0;
		while(r.x() >= cols[i])
		{
			if(cols.size() <= i+1) // last column
			{
				wcol = i;
				break;
			}
			if(r.x() < cols[i+1])
			{
				wcol = i;
				uint j = i + 1;
				// Then we check if the widget needs to span multiple columns
				while(cols.size() >= j+1 && r.right() > cols[j])
				{
					endcol = j;
					j++;
				}

				break;
			}
			i++;
		}
		//kdDebug() << "the widget " << w->name() << " wil be in the col " << wcol <<
		 // " and will go to the col " << endcol << endl;

		ObjectTreeItem *item = m_form->objectTree()->lookup(w->name());
		if(!endrow && !endcol) {
			if(!testOnly)
				tqlayout->addWidget(w, wrow, wcol);
			item->setGridPos(wrow, wcol, 0, 0);
		}
		else {
			if(!endcol)  endcol = wcol;
			if(!endrow)  endrow = wrow;
			if(!testOnly)
				tqlayout->addMultiCellWidget(w, wrow, endrow, wcol, endcol);
			item->setGridPos(wrow, wcol, endrow-wrow+1, endcol-wcol+1);
		}
	}
}

TQString
Container::layoutTypeToString(int type)
{
	switch(type)
	{
		case HBox: return "HBox";
		case VBox: return "VBox";
		case Grid: return "Grid";
		case HFlow: return "HFlow";
		case VFlow: return "VFlow";
		default:   return "NoLayout";
	}
}

Container::LayoutType
Container::stringToLayoutType(const TQString &name)
{
	if(name == "HBox") return HBox;
	if(name == "VBox") return VBox;
	if(name == "Grid") return Grid;
	if(name == "HFlow")  return HFlow;
	if(name == "VFlow")  return VFlow;
	return NoLayout;
}

/// Drawing functions used by eventFilter
void
Container::drawConnection(TQMouseEvent *mev)
{
	if(mev->button() != Qt::LeftButton)
	{
		FormManager::self()->resetCreatedConnection();
		return;
	}
	// First click, we select the sender and display menu to choose signal
	if(FormManager::self()->createdConnection()->sender().isNull())
	{
		FormManager::self()->createdConnection()->setSender(m_moving->name());
		if(m_form->formWidget())
		{
			m_form->formWidget()->initBuffer();
			m_form->formWidget()->highlightWidgets(m_moving, 0/*, TQPoint()*/);
		}
		FormManager::self()->createSignalMenu(m_moving);
		return;
	}
	// the user clicked outside the menu, we cancel the connection
	if(FormManager::self()->createdConnection()->signal().isNull())
	{
		FormManager::self()->stopCreatingConnection();
		return;
	}
	// second click to choose the receiver
	if(FormManager::self()->createdConnection()->receiver().isNull())
	{
		FormManager::self()->createdConnection()->setReceiver(m_moving->name());
		FormManager::self()->createSlotMenu(m_moving);
		m_container->tqrepaint();
		return;
	}
	// the user clicked outside the menu, we cancel the connection
	if(FormManager::self()->createdConnection()->slot().isNull())
	{
		FormManager::self()->stopCreatingConnection();
		return;
	}
}

void
Container::drawSelectionRect(TQMouseEvent *mev)
{
	//finish drawing unclipped selection rectangle: clear the surface
	if(m_form->formWidget())
		m_form->formWidget()->clearForm();
	int topx = (m_insertBegin.x() < mev->x()) ? m_insertBegin.x() :  mev->x();
	int topy = (m_insertBegin.y() < mev->y()) ? m_insertBegin.y() : mev->y();
	int botx = (m_insertBegin.x() > mev->x()) ? m_insertBegin.x() :  mev->x();
	int boty = (m_insertBegin.y() > mev->y()) ? m_insertBegin.y() : mev->y();
	TQRect r = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));

	setSelectedWidget(m_container, false);
	TQWidget *widgetToSelect = 0;
	// We check which widgets are in the rect and select them
	for(ObjectTreeItem *item = m_tree->tqchildren()->first(); item; item = m_tree->tqchildren()->next())
	{
		TQWidget *w = item->widget();
		if(!w)
			continue;
		if(w->tqgeometry().intersects(r) && w != m_container) {
			if (widgetToSelect)
				setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, true/*moreWillBeSelected*/);
			widgetToSelect = w; //select later
		}
	}
	if (widgetToSelect) //the last one left
		setSelectedWidget(widgetToSelect, true/*add*/, false/*raise*/, false/*!moreWillBeSelected*/);

	m_insertRect = TQRect();
	m_state = DoingNothing;
	m_container->tqrepaint();
}

void
Container::drawInsertRect(TQMouseEvent *mev, TQObject *s)
{
	int tmpx, tmpy;
	TQPoint pos = TQT_TQWIDGET(s)->mapTo(m_container, mev->pos());
	int gridX = m_form->gridSize();
	int gridY = m_form->gridSize();
	if(!FormManager::self()->snapWidgetsToGrid() || (mev->state() == (Qt::LeftButton|ControlButton|AltButton)) )
	{
		tmpx = pos.x();
		tmpy = pos.y();
	}
	else
	{
		tmpx = int( (float) pos.x() / ((float)gridX) + 0.5);
		tmpx *= gridX;
		tmpy = int( (float)pos.y() / ((float)gridY) + 0.5);
		tmpy *= gridX;
	}

	int topx = (m_insertBegin.x() < tmpx) ? m_insertBegin.x() : tmpx;
	int topy = (m_insertBegin.y() < tmpy) ? m_insertBegin.y() : tmpy;
	int botx = (m_insertBegin.x() > tmpx) ? m_insertBegin.x() : tmpx;
	int boty = (m_insertBegin.y() > tmpy) ? m_insertBegin.y() : tmpy;
	m_insertRect = TQRect(TQPoint(topx, topy), TQPoint(botx, boty));

	if(m_insertRect.x() < 0)
		m_insertRect.setLeft(0);
	if(m_insertRect.y() < 0)
		m_insertRect.setTop(0);
	if(m_insertRect.right() > m_container->width())
		m_insertRect.setRight(m_container->width());
	if(m_insertRect.bottom() > m_container->height())
		m_insertRect.setBottom(m_container->height());

	if(FormManager::self()->isInserting() && m_insertRect.isValid())
	{
		if(m_form->formWidget())
		{
			TQRect drawRect = TQRect(m_container->mapTo(m_form->widget(), m_insertRect.topLeft())
				, m_insertRect.size());
			m_form->formWidget()->drawRect(drawRect, 2);
		}
	}
}

void
Container::drawCopiedWidgetRect(TQMouseEvent *mev)
{
	// We've been dragging a widget, but Ctrl was hold, so we start copy
	if(m_state == MovingWidget)  {
		//FormManager::self()->undo(); // undo last moving
		//m_moving->move(m_initialPos);
		if(m_form->formWidget())  {
			m_container->tqrepaint();
			m_form->formWidget()->initBuffer();
		}
		m_state = CopyingWidget;
	}

	//m_copyRect.moveTopLeft(m_container->mapFromGlobal( mev->globalPos()) - m_grab);

	if(m_form->formWidget())  {
		TQValueList<TQRect> rectList;
		for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next()) {
			TQRect drawRect = w->tqgeometry();
			TQPoint p = mev->pos() - m_grab;
			drawRect.moveBy(p.x(), p.y());
			p = m_container->mapTo(m_form->widget(), TQPoint(0, 0));
			//drawRect = TQRect( ((TQWidget*)s)->mapTo(m_form->widget(), drawRect.topLeft()), drawRect.size());
			drawRect.moveBy(p.x(), p.y());
			rectList.append(drawRect);
		}

		m_form->formWidget()->drawRects(rectList, 2);
	}
}

/// Other functions used by eventFilter
void
Container::moveSelectedWidgetsBy(int realdx, int realdy, TQMouseEvent *mev)
{
	if (m_form->selectedWidget() == m_form->widget())
		return; //do not move top-level widget

	const int gridX = m_form->gridSize();
	const int gridY = m_form->gridSize();
	int dx=realdx, dy=realdy;

	for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
	{
		if(!w || !w->parent() || w->parent()->inherits(TQTABWIDGET_OBJECT_NAME_STRING) || w->parent()->inherits(TQWIDGETSTACK_OBJECT_NAME_STRING))
			continue;

		if(w->parentWidget() && w->parentWidget()->isA(TQWIDGETSTACK_OBJECT_NAME_STRING))
		{
			w = w->parentWidget(); // widget is WidgetStack page
			if(w->parentWidget() && w->parentWidget()->inherits(TQTABWIDGET_OBJECT_NAME_STRING)) // widget is tabwidget page
				w = w->parentWidget();
		}

		int tmpx = w->x() + realdx;
		int tmpy = w->y() + realdy;
		if(tmpx < 0)
			dx = TQMAX(0 - w->x(), dx); // because dx is <0
		else if(tmpx > w->parentWidget()->width() - gridX)
			dx = TQMIN(w->parentWidget()->width() - gridX - w->x(), dx);

		if(tmpy < 0)
			dy = TQMAX(0 - w->y(), dy); // because dy is <0
		else if(tmpy > w->parentWidget()->height() - gridY)
			dy = TQMIN(w->parentWidget()->height() - gridY - w->y(), dy);
	}

	for(TQWidget *w = m_form->selectedWidgets()->first(); w; w = m_form->selectedWidgets()->next())
	{
		// Don't move tab widget pages (or widget stack pages)
		if(!w || !w->parent() || w->parent()->inherits(TQTABWIDGET_OBJECT_NAME_STRING) || w->parent()->inherits(TQWIDGETSTACK_OBJECT_NAME_STRING))
			continue;

		if(w->parentWidget() && w->parentWidget()->isA(TQWIDGETSTACK_OBJECT_NAME_STRING))
		{
			w = w->parentWidget(); // widget is WidgetStack page
			if(w->parentWidget() && w->parentWidget()->inherits(TQTABWIDGET_OBJECT_NAME_STRING)) // widget is tabwidget page
				w = w->parentWidget();
		}

		int tmpx, tmpy;
		if(!FormManager::self()->snapWidgetsToGrid() || (mev && mev->state() == (Qt::LeftButton|ControlButton|AltButton)) )
		{
			tmpx = w->x() + dx;
			tmpy = w->y() + dy;
		}
		else
		{
			tmpx = int( float( w->x() + dx) / float(gridX) + 0.5) * gridX;
			tmpy = int( float( w->y() + dy) / float(gridY) + 0.5) * gridY;
		}

		if((tmpx != w->x()) || (tmpy != w->y()))
			w->move(tmpx,tmpy);
	}
}

////////////

DesignTimeDynamicChildWidgetHandler::DesignTimeDynamicChildWidgetHandler()
 : m_item(0)
{
}

DesignTimeDynamicChildWidgetHandler::~DesignTimeDynamicChildWidgetHandler()
{
}

void
DesignTimeDynamicChildWidgetHandler::childWidgetAdded(TQWidget* w)
{
	if (m_item) {
		installRecursiveEventFilter(TQT_TQOBJECT(w), m_item->eventEater());
	}
}

#include "container.moc"