/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "gui/common/FlowLayout.h"
#include <QApplication>
#include <QtGui>
#include <QScrollBar>
#include <QDebug>

//*** FlowLayoutItem **********************************************************

void FlowLayoutItem::mousePressEvent(QMouseEvent *event)
{
	if (event->button() == Qt::LeftButton) {
		m_startPos = event->pos();
	}//if (event->button() == Qt::LeftButton)
	QWidget::mousePressEvent(event);
}

void FlowLayoutItem::mouseMoveEvent(QMouseEvent *event)
{
	if (event->buttons() & Qt::LeftButton) {
		int distance = (event->pos() - m_startPos).manhattanLength();
		if (distance >= QApplication::startDragDistance())
			performDrag();
	}//if (event->buttons() & Qt::LeftButton)
	QWidget::mouseMoveEvent(event);
}

void FlowLayoutItem::performDrag()
{
	QMimeData *mimeData = new QMimeData;
	mimeData->setText(m_myName);

	QDrag *drag = new QDrag(this);
	drag->setMimeData(mimeData);
	QPixmap pixmap=getDragImage();

	drag->setPixmap(pixmap.scaled(50,50,Qt::KeepAspectRatio, Qt::SmoothTransformation));
	/// Warning On Windows, Drag Pixmap size cannot exceed 50*50. ///
	drag->setHotSpot(QPoint(0, 0));
	Qt::DropAction dropAction = drag->exec(Qt::CopyAction);
	qDebug()<<dropAction;
}

void FlowLayoutItem::mouseReleaseEvent(QMouseEvent *event)
{
	Q_UNUSED(event);
	QWidget::mouseReleaseEvent(event);
}

void FlowLayoutItem::dragEnterEvent(QDragEnterEvent *event)
{
	FlowLayoutItem *source =
	    qobject_cast<FlowLayoutItem *>(event->source());
	if (source && source != this) {
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
		return;
	}//if (source && source != this)
	QWidget *wid =
	    qobject_cast<QWidget *>(event->source());//QT5 return QObject
	FlowLayout *layout = 0;
	if (wid) layout =
	    qobject_cast<FlowLayout *>(wid->layout());
	if (layout) {
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
		return;
	}//if (layout)
}

void FlowLayoutItem::dragMoveEvent(QDragMoveEvent *event)
{
	FlowLayoutItem *source =
	    qobject_cast<FlowLayoutItem *>(event->source());
	if (source && source != this) {
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
		return;
	}//if (source && source != this)
	QWidget *wid =
	    qobject_cast<QWidget *>(event->source());//QT5 return QObject
	FlowLayout *layout = 0;
	if (wid) layout =
	    qobject_cast<FlowLayout *>(wid->layout());
	if (layout) {
		event->setDropAction(Qt::CopyAction);
		event->acceptProposedAction();
		return;
	}//if (layout)
}

void FlowLayoutItem::dropEvent(QDropEvent *event)
{
	QList <FlowLayoutItem*> list;
	FlowLayoutItem *source =
	    qobject_cast<FlowLayoutItem *>(event->source());
	if (source && source != this) {
		event->setDropAction(Qt::CopyAction);
		list << source;
	} else {//if (source && source != this)
		QWidget *wid =
		    qobject_cast<QWidget *>(event->source());//QT5 return QObject
		FlowLayout *layout = NULL;
		if (wid) layout =
		    qobject_cast<FlowLayout *>(wid->layout());
		if (layout) {
			QList<QLayoutItem *> listSel = layout->selectionList();
			int count = listSel.count();
			for (int curs = 0; curs < count; ++curs){
				QLayoutItem *layoutItem = listSel.at(curs);
				FlowLayoutItem *flItem = 0;
				if (layoutItem) flItem = qobject_cast<FlowLayoutItem*>(layoutItem->widget());
				if (flItem) list << flItem;
			}//for (int curs = 0; curs < count; ++curs)
		}//if (layout)
	}//else (source && source != this)
	if (!list.isEmpty()) {
		event->setDropAction(Qt::CopyAction);
		bool bAccept=true;
		emit flowLayoutItemDropped(list, bAccept);
		if (bAccept) event->acceptProposedAction();
	}//if (!list.empty())
}

//*** FlowLayoutWidget **********************************************************
FlowLayoutWidget::FlowLayoutWidget(QWidget *parent, int margin/*=-1*/, int hSpacing/*=-1*/, int vSpacing/*=-1*/)
  : QWidget(parent)
{
	FlowLayoutWidget(margin, hSpacing, vSpacing);
}

FlowLayoutWidget::FlowLayoutWidget(int margin/*=-1*/, int hSpacing/*=-1*/, int vSpacing/*=-1*/)
{
	FlowLayout *fl = new FlowLayout(this, margin, hSpacing, vSpacing);
	Q_UNUSED(fl)
	this->installEventFilter(this);
	this->setMouseTracking(true);
	this->setAcceptDrops(true);
	m_saParent = 0;
	m_sbVertical = 0;
}

FlowLayoutWidget::~FlowLayoutWidget()
{
}

bool FlowLayoutWidget::eventFilter(QObject *obj, QEvent *event)
{
	qDebug() << "FlowLayoutWidget:: obj type:" << obj->metaObject()->className() << " event type:" << event->type();
	updateParent();
	if (event->type() == QEvent::DragEnter) {
		QDragEnterEvent *dragEnterEvent = static_cast<QDragEnterEvent *>(event);
		if (dragEnterEvent){
			dragEnterEvent->setDropAction(Qt::IgnoreAction);
			dragEnterEvent->accept();
		}//if (dragEnterEvent)
	}//if (event->type() == QEvent::DragEnter)

	if (event->type() == QEvent::DragMove) {
		QDragMoveEvent *dragMoveEvent = static_cast<QDragMoveEvent *>(event);
		const int border = 20;
		if (obj==this && dragMoveEvent){
			if (m_sbVertical){
				int maxY = m_sbVertical->maximum();
				int currentY = m_sbVertical->value();
				int height = m_saParent->height();
				int topBorder = currentY + border;
				int bottomBorder = currentY + height - border;
				int dragY = dragMoveEvent->pos().y();
				qDebug() <<"Drag event:" << dragY ;
				int dY = (dragY<topBorder)?dragY - topBorder:((dragY>bottomBorder)?dragY - bottomBorder:0);
				qDebug() << "dY:" << dY << " m_lastYPos:" << m_lastYPos << "(dragY-m_lastYPos)*dY:" << (dragY-m_lastYPos)*dY;
				int newValue=currentY+dY;
				if ((abs(dY)<border) && ((dragY-m_lastYPos)*dY >= 0)){
					if (newValue>maxY) newValue=maxY;
					if (newValue<0) newValue=0;
					m_sbVertical->setValue(newValue);
				} else {
					newValue=currentY;
				}//if ((abs(dY)<border) && ((dragY-m_lastYPos)*dY >= 0))
				m_lastYPos = dragY+(newValue-currentY);
			}//if (sbVertical)
		}//if (obj==this && dragMoveEvent)
		if (obj==m_sbVertical && dragMoveEvent){
			if (m_sbVertical->isVisible()){
				int maxY = m_sbVertical->maximum();
				double height = m_sbVertical->height()*1.0;
				double scale = (maxY/height);
				int dragY = dragMoveEvent->pos().y();
				qDebug() << "Drag maxY:" << maxY << "height:" << height  << "scale:" << scale << "dragY:" << dragY;
				m_sbVertical->setValue(dragY*scale);
			}//if (sbVertical->isVisible())
		}//if (obj==this && dragMoveEvent)
	}//if (event->type() == QEvent::DragMove)

	// standard event processing
	return QObject::eventFilter(obj, event);
}

void FlowLayoutWidget::updateParent()
{
	if (parent()){
		if (!m_saParent){
			if (parent()->objectName() == "qt_scrollarea_viewport"){
				m_saParent = qobject_cast<QScrollArea*>(parent()->parent());
			} else {
				m_saParent = qobject_cast<QScrollArea*>(parent());
			}//if (parent()->objectName() == "qt_scrollarea_viewport")
			if (m_saParent){
				m_saParent->installEventFilter(this);
				m_saParent->setAcceptDrops(true);
				m_saParent->setMouseTracking(true);
			}//if (saParent)
		}//if (!saParent)
		if (m_saParent && !m_sbVertical){
			m_sbVertical= m_saParent->verticalScrollBar();
			if (m_sbVertical){
				m_sbVertical->installEventFilter(this);
				m_sbVertical->setAcceptDrops(true);
				m_sbVertical->setMouseTracking(true);
			}//if (sbVertical)
		}//if (saParent && !sbVertical)
	}//if (parent())
}

//*** FlowLayout **********************************************************

FlowLayout::FlowLayout(QWidget *parent, int margin/*=-1*/, int hSpacing/*=-1*/, int vSpacing/*=-1*/)
  : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)
{
	setContentsMargins(margin, margin, margin, margin);
	this->installEventFilter(this);
}

FlowLayout::FlowLayout(int margin/*=-1*/, int hSpacing/*=-1*/, int vSpacing/*=-1*/)
  : m_hSpace(hSpacing), m_vSpace(vSpacing)
{
	setContentsMargins(margin, margin, margin, margin);
	this->installEventFilter(this);
}

FlowLayout::~FlowLayout()
{
	QLayoutItem *item;
	while ((item = takeAt(0)))
		delete item;
}

bool FlowLayout::eventFilter(QObject *obj, QEvent *event)
{
	qDebug() << "FlowLayout::obj type:" << obj->metaObject()->className() << " event type:" << event->type();

	if (event->type() == QEvent::MouseButtonPress) {
		m_startPos = QCursor::pos();
	}//if (event->type() == QEvent::MouseButtonPress)

	if (event->type() == QEvent::MouseButtonRelease) {
		QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
		int distance = (QCursor::pos() - m_startPos).manhattanLength();
		if (distance < QApplication::startDragDistance()){
			unsetCurrent();
			m_currentIndex=indexAtGlobal(QCursor::pos());
			setCurrent();
			bool invert = (mouseEvent->modifiers() &= Qt::ControlModifier);
			if (mouseEvent->modifiers() &= Qt::ShiftModifier){
				m_selStartIndex=(m_selStartIndex<m_currentIndex)?m_selStartIndex:m_currentIndex;
				m_selStopIndex=(m_selStopIndex>m_currentIndex)?m_selStopIndex:m_currentIndex;
			} else {
				m_selStartIndex=m_selStopIndex=m_currentIndex;
				if (mouseEvent->modifiers() != Qt::ControlModifier){
					foreach (QLayoutItem *item, m_selectionList) {
						FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(item->widget());
						if (fli) fli->setIsSelected(false);
						m_selectionList.removeOne(item);
					}
				}//if (mouseEvent->modifiers() != Qt::ControlModifier)
			}//if (mouseEvent->modifiers()
			addSelection(invert);
			setCurrent();
		}//if (distance < QApplication::startDragDistance())
		doLayout(geometry(),false);
	}//if (event->type() == QEvent::MouseButtonRelease)

	if (event->type() == QEvent::MouseMove) {
		QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
		if (mouseEvent->buttons() & Qt::LeftButton) {
			int distance = (QCursor::pos() - m_startPos).manhattanLength();
			if (distance >= QApplication::startDragDistance()){
				if (!m_selectionList.isEmpty()) {
					QLayoutItem *item=itemAtGlobal(m_startPos);
					if (item) {
						if (m_selectionList.contains(item)){
							performDrag();
							return true; // eat event
						}//if (m_selectionList.contains(item))
					}//if (item)
				}//if (!m_selectionList.isEmpty())
			}//if (distance >= QApplication::startDragDistance())
		}//if (mouseEvent->buttons() & Qt::LeftButton)
	}//if (event->type() == QEvent::MouseMove)

	if (event->type() == QEvent::KeyRelease) {
		QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);

		if ((keyEvent->key()==Qt::Key_A) && (keyEvent->modifiers() &= Qt::ControlModifier)){
			int count = m_itemList.count();
			int selected = m_selectionList.count();
			if (count != selected){
				for (int curs=0; curs<count; ++curs){
					QLayoutItem *item=itemAt(curs);
					if (item) {
						if (!m_selectionList.contains(item)){
							FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(item->widget());
							if (fli) fli->setIsSelected(true);
							m_selectionList.append(item);
						}//if (!m_selectionList.contains(item))
					}//if (item)
				}//for (int curs=0; curs<count; ++curs)
			} else {
				foreach (QLayoutItem *item, m_selectionList) {
					FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(item->widget());
					if (fli) fli->setIsSelected(false);
					m_selectionList.removeOne(item);
				}
			}//if (count != selected)

			doLayout(geometry(),false);
			event->accept();
		}//if ((keyEvent->key()==Qt::Key_A) && (keyEvent->modifiers() &= Qt::ControlModifier))

		if ((keyEvent->key()==Qt::Key_Space)){
			if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier)){
				addSelection((keyEvent->modifiers() &= Qt::ControlModifier));
			}//if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier))
			doLayout(geometry(),false);
			m_selStartIndex = m_selStopIndex = m_currentIndex;
			event->accept();
		}//if ((keyEvent->key()==Qt::Key_Space))

		if ((keyEvent->key()==Qt::Key_Left)){
			unsetCurrent();
			if (m_currentIndex>0) m_currentIndex-=1;
			if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier)){
				m_selStartIndex=m_currentIndex;
				addSelection((keyEvent->modifiers() &= Qt::ControlModifier));
			}//if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier))
			doLayout(geometry(),false);
			m_selStartIndex = m_selStopIndex = m_currentIndex;
			event->accept();
			setCurrent();
		}//if ((keyEvent->key()==Qt::Key_Left))

		if ((keyEvent->key()==Qt::Key_Right)){
			unsetCurrent();
			if (m_currentIndex<(m_itemList.count()-1)) m_currentIndex+=1;
			if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier)){
				m_selStopIndex=m_currentIndex;
				addSelection((keyEvent->modifiers() &= Qt::ControlModifier));
			}//if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier))
			doLayout(geometry(),false);
			m_selStartIndex = m_selStopIndex = m_currentIndex;
			event->accept();
			setCurrent();
		}//if ((keyEvent->key()==Qt::Key_Right))

		if ((keyEvent->key()==Qt::Key_Up)){
			unsetCurrent();
			QLayoutItem* item = currentItem();
			if (item) {
				QRect loc = item->geometry();
				int vSpace = verticalSpacing();
				QPoint pos = QPoint(loc.left()+loc.width()/2, loc.top()-vSpace-2);
				int index = -1;
				while ((pos.y()>0) && (index < 0)){
					index = indexAtParent(pos);
					pos.setY(pos.y()-2);
				}//while ((pos.y()>0) && (index < 0))
				m_currentIndex = (index>0)?index:0;
				m_currentIndex = (index<=m_itemList.count())?index:m_itemList.count();
				if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier)){
					m_selStopIndex = m_currentIndex;
					addSelection((keyEvent->modifiers() &= Qt::ControlModifier));
				}//if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier))
				doLayout(geometry(),false);
				m_selStartIndex = m_selStopIndex = m_currentIndex;
				event->accept();
			}//if (wid)
			setCurrent();
		}//if ((keyEvent->key()==Qt::Key_Right))

		if ((keyEvent->key()==Qt::Key_Down)){
			unsetCurrent();
			QLayoutItem* item = currentItem();
			if (item){
				QRect loc = item->geometry();
				int vSpace = verticalSpacing();
				QPoint pos = QPoint(loc.left()+loc.width()/2, loc.bottom()+vSpace+2);
				int index = -1;
				while ((pos.y()<geometry().bottom()) && (index < 0)){
					index = indexAtParent(pos);
					pos.setY(pos.y()+2);
				}//while ((pos.y()<geometry().bottom()) && (index < 0))
				m_currentIndex = (index>0)?index:0;
				m_currentIndex = (index<=m_itemList.count())?index:m_itemList.count();
				if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier)){
					m_selStopIndex = m_currentIndex;
					addSelection((keyEvent->modifiers() &= Qt::ControlModifier));
				}//if ((keyEvent->modifiers() &= Qt::ShiftModifier) || (keyEvent->modifiers() &= Qt::ControlModifier))
				doLayout(geometry(),false);
				m_selStartIndex = m_selStopIndex = m_currentIndex;
				event->accept();
			}//if (wid)
			setCurrent();
		}//if ((keyEvent->key()==Qt::Key_Right))

	}//if (event->type() == QEvent::KeyRelease)

	// standard event processing
	return QObject::eventFilter(obj, event);
}

void FlowLayout::unsetCurrent()
{
	QLayoutItem *oldItem = currentItem();
	if (oldItem) {
		FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(oldItem->widget());
		if (fli) fli->setIsCurrent(false);
	}//if (oldItem)
}

void FlowLayout::setCurrent()
{
	QLayoutItem *newItem = currentItem();
	if (newItem) {
		FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(newItem->widget());
		if (fli) fli->setIsCurrent(true);
	}//if (newItem)
}

void FlowLayout::addItem(QLayoutItem *item)
{
	m_itemList.append(item);
	item->widget()->installEventFilter(this);
}

void FlowLayout::addItem(FlowLayoutItem *item)
{
	QWidget *widget = qobject_cast<QWidget *>(item);
	addWidget(widget);
}

int FlowLayout::horizontalSpacing() const
{
	if (m_hSpace >= 0) {
		return m_hSpace;
	} else {
		return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
	}//if (m_hSpace >= 0)
}
void FlowLayout::setHorizontalSpacing(int &h)
{
	if (h>=0) {
		m_hSpace = h;
	} else {
		m_hSpace = -1;
	}//if (h>=0)
	doLayout(geometry(), false);
}

int FlowLayout::verticalSpacing() const
{
	if (m_vSpace >= 0) {
		return m_vSpace;
	} else {
		return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
	}//if (m_vSpace >= 0)
}
void FlowLayout::setVerticalSpacing(int &v)
{
	if (v>=0) {
		m_vSpace = v;
	} else {
		m_vSpace = -1;
	}//if (v>=0)
	doLayout(geometry(), false);
}

int FlowLayout::count() const
{
	return m_itemList.size();
}

QLayoutItem *FlowLayout::itemAt(int index) const
{
	return m_itemList.value(index);
}

QLayoutItem *FlowLayout::itemAtGlobal(const QPoint &p) const
{
	return m_itemList.value(indexAtGlobal(p));
}

QLayoutItem *FlowLayout::itemAtParent(const QPoint &p) const
{
	return m_itemList.value(indexAtParent(p));
}

int FlowLayout::indexAtGlobal(const QPoint &p) const
{
	int count = m_itemList.size();
	for(int curs=0; curs<count; ++curs){
		QWidget *widget = m_itemList.value(curs)->widget();
		if(widget) {
			QPoint pos = widget->mapFromGlobal(p);
			if((pos.x()>0) && (pos.x()<widget->width()))
				if((pos.y()>0) && (pos.y()<widget->height()))
					return curs;
		}//if(widget)
	}//for(int curs=0; curs<count; ++curs)
	return -1;
}

int FlowLayout::indexAtParent(const QPoint &p) const
{
	int count = m_itemList.size();
	for(int curs=0; curs<count; ++curs){
		QWidget *widget = m_itemList.value(curs)->widget();
		if(widget) {
			QPoint pos = widget->mapFromParent(p);
			if((pos.x()>=0) && (pos.x()<=widget->width()))
				if((pos.y()>=0) && (pos.y()<=widget->height()))
					return curs;

			if (pos.y()<0) break;//In line below so don't check other item.
		}//if(widget)
	}//for(int curs=0; curs<count; ++curs)
	return -1;
}

QLayoutItem *FlowLayout::takeAt(int index)
{
	if (index >= 0 && index < m_itemList.size())
		return m_itemList.takeAt(index);
	else
		return 0;
}

Qt::Orientations FlowLayout::expandingDirections() const
{
	return Qt::Horizontal;
}

bool FlowLayout::hasHeightForWidth() const
{
	return true;
}

int FlowLayout::heightForWidth(int width) const
{
	int height = doLayout(QRect(0, 0, width, 0), true);
	return height;
}

void FlowLayout::setGeometry(const QRect &rect)
{
	QLayout::setGeometry(rect);
	doLayout(rect, false);
}

QSize FlowLayout::sizeHint() const
{
	return minimumSize();
}

QSize FlowLayout::minimumSize() const
{
	QSize size;
	QLayoutItem *item;
	foreach (item, m_itemList)
		size = size.expandedTo(item->minimumSize());

	size += QSize(2*margin(), 2*margin());
	return size;
}

void FlowLayout::addSelection(bool invert){
	for (int curs=m_selStartIndex; curs<=m_selStopIndex; ++curs){
		QLayoutItem *item=itemAt(curs);
		if (item) {
			FlowLayoutItem *fli = qobject_cast<FlowLayoutItem *>(item->widget());
			if (invert && m_selectionList.contains(item)){
				if (fli) fli->setIsSelected(false);
				m_selectionList.removeOne(item);
			} else {
				if (fli) fli->setIsSelected(true);
				m_selectionList.append(item);
			}//if (m_selectionList.contains(item))
		}//if (item)
	}//for (int curs=m_selStartIndex; curs<=m_selStopIndex; ++curs)
}

void FlowLayout::performDrag()
{
	QPixmap dragPixmap;
	bool atLeastOnePixmap = false;
	int count = m_selectionList.count();
	for (int curs=0; curs<count; ++curs){
		QLayoutItem *layoutItem =  m_selectionList.at(curs);
		if (layoutItem){
			QWidget *widget = layoutItem->widget();
			if (widget) {
				QPixmap itemPixmap;
				FlowLayoutItem *item = qobject_cast<FlowLayoutItem *>(widget);
				if (item){
					itemPixmap = item->getDragImage();
				} else {
#if QT_VERSION >= QT_VERSION_CHECK (5, 0, 0)
					itemPixmap = widget->grab();//QT5
#else
					itemPixmap = QPixmap::grabWidget(widget);
#endif
				}//if (item)

				itemPixmap = itemPixmap.scaled(50,50,Qt::KeepAspectRatio, Qt::SmoothTransformation);
				/// Warning On Windows, Drag Pixmap size cannot exceed 50*50. ///
				if (curs==0) dragPixmap = itemPixmap;
				QPixmap oldPixmap = dragPixmap;
				if (curs!=0) dragPixmap = QPixmap(oldPixmap.width() + 20 , oldPixmap.height());
				dragPixmap.fill(widget->palette().background().color());
				QPainter painter(&dragPixmap);
				painter.drawPixmap(0, 0, oldPixmap);
				if (curs!=0) painter.drawPixmap((20 * curs), 0, itemPixmap);

				atLeastOnePixmap = true;
			}//if (widget)
		}//if (layoutItem)
	}//for (int curs=0; curs<count; ++curs)
	if (atLeastOnePixmap) {
		QMimeData *mimeData = new QMimeData;
		mimeData->setText("");
		QDrag *drag = new QDrag(this->parentWidget());
		drag->setMimeData(mimeData);

		drag->setPixmap(dragPixmap);
		drag->setHotSpot(QPoint(0, 0));
		drag->exec(Qt::CopyAction);
	}//if (atLeastOnePixmap)
}

int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
	int left, top, right, bottom;
	getContentsMargins(&left, &top, &right, &bottom);
	QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
	int x = effectiveRect.x();
	int y = effectiveRect.y();
	int lineHeight = 0;

	int count = m_itemList.size();
	for (int curs=0; curs<count; ++curs) {
		QLayoutItem *item=m_itemList.value(curs);
		QWidget *wid = item->widget();
		int spaceX = horizontalSpacing();
		if (spaceX == -1)
			spaceX = wid->style()->layoutSpacing(
			      QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
		int spaceY = verticalSpacing();
		if (spaceY == -1)
			spaceY = wid->style()->layoutSpacing(
			      QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);

		int nextX = x + item->sizeHint().width() + spaceX;
		if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
			x = effectiveRect.x();
			y = y + lineHeight + spaceY;
			nextX = x + item->sizeHint().width() + spaceX;
			lineHeight = 0;
		}//if (nextX - spaceX > effectiveRect.right() && lineHeight > 0)

		if (!testOnly){
			item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
			bool selected = m_selectionList.contains(item);
			bool isCurrent = (curs==currentIndex());
			QString solid = isCurrent?"dot-dash":"inset";
			QString color = selected?"blue":isCurrent?"gray":"";
			QString border = (selected||isCurrent)?QString("border: 1px %1 %2").arg(solid).arg(color):"";
			QString widName = wid->objectName();
			QString style;
			if (widName.isEmpty()){
				style=border;
			} else {
				//For Custom QWidget, change paintEvent as FlowLayoutItem. cf:http://qt-project.org/doc/qt-4.8/stylesheet-reference.html
				style = QString("QWidget#%1\n{\n%2\n}\n").arg(wid->objectName(),border);
			}//if (widName.isEmpty())
			///Warning: Test if != to not ask a new redraw all time ///
			if (wid->styleSheet()!=style) wid->setStyleSheet(style);
		}//if (!testOnly)

		x = nextX;
		lineHeight = qMax(lineHeight, item->sizeHint().height());
	}//for (curs=0; curs<count; ++curs)

	return y + lineHeight - rect.y() + bottom;
}

int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
	QObject *parent = this->parent();
	if (!parent) {
		return -1;
	} else if (parent->isWidgetType()) {
		QWidget *pw = static_cast<QWidget *>(parent);
		return pw->style()->pixelMetric(pm, 0, pw);
	} else {
		return static_cast<QLayout *>(parent)->spacing();
	}//if (!parent)
}
