/****************************************************************************
**
** Copyright (C) 1992-2004 Trolltech AS. All rights reserved.
**
** This file is part of the designer application of the Qt Toolkit.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
**   information about Qt Commercial License Agreements.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

#include "qdesigner_tabwidget.h"
#include "command.h"
#include "formwindow.h"

#include <QApplication>
#include <QTabBar>
#include <QAction>
#include <QMouseEvent>

#include <qdebug.h>

QDesignerTabWidget::QDesignerTabWidget(QWidget *parent)
    : QTabWidget(parent)
{
    dropIndicator = 0;
    dragPage = 0;
    mousePressed = false;

    tabBar()->setAcceptDrops(true);
    tabBar()->installEventFilter(this);

    m_actionInsertPage = new QAction(this);
    m_actionInsertPage->setText(tr("Add Page"));
    connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage()));

    m_actionDeletePage = new QAction(this);
    m_actionDeletePage->setText(tr("Delete Page"));
    connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage()));

    connect(this, SIGNAL(currentChanged(int)),
        this, SLOT(slotCurrentChanged(int)));
}

QDesignerTabWidget::~QDesignerTabWidget()
{
}

QString QDesignerTabWidget::currentTabName() const
{
    return currentWidget()
        ? currentWidget()->objectName()
        : QString::null;
}

void QDesignerTabWidget::setCurrentTabName(const QString &tabName)
{
    if (QWidget *w = currentWidget())
        w->setObjectName(tabName);
}

QString QDesignerTabWidget::currentTabText() const
{
    return tabText(currentIndex());
}

void QDesignerTabWidget::setCurrentTabText(const QString &tabText)
{
    setTabText(currentIndex(), tabText);
}

QString QDesignerTabWidget::currentTabToolTip() const
{
    return tabToolTip(currentIndex());
}

void QDesignerTabWidget::setCurrentTabToolTip(const QString &tabToolTip)
{
    setTabToolTip(currentIndex(), tabToolTip);
}

QIcon QDesignerTabWidget::currentTabIcon() const
{
    return tabIcon(currentIndex());
}

void QDesignerTabWidget::setCurrentTabIcon(const QIcon &tabIcon)
{
    setTabIcon(currentIndex(), tabIcon);
}

bool QDesignerTabWidget::eventFilter(QObject *o, QEvent *e)
{
    if (o != tabBar())
        return false;

    switch (e->type()) {
        case QEvent::MouseButtonDblClick: {
        } break;

        case QEvent::MouseButtonPress: {
            QMouseEvent *mev = static_cast<QMouseEvent*>(e);
            if (mev->button() & Qt::LeftButton) {
                mousePressed = true;
                pressPoint = mev->pos();
            }
        } break;

        case QEvent::MouseButtonRelease: {
            mousePressed = false;
        } break;

        case QEvent::MouseMove: {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
            if (mousePressed && canMove(mouseEvent)) {
                mousePressed = false;
                QDrag *drg = new QDrag(this);
                QMimeData *mimeData = new QMimeData();
                mimeData->setData("designer/tab", QByteArray::number(long(this)));
                drg->setMimeData(mimeData);

                dragIndex = currentIndex();
                dragPage = currentWidget();
                dragLabel = currentTabText();
                dragIcon = currentTabIcon();

                removeTab(dragIndex);

                QDrag::DropActions dropAction = drg->start(QDrag::MoveAction);

                if (dropAction == 0) {
                    // abort
                    insertTab(dragIndex, dragPage, dragIcon, dragLabel);
                    setCurrentIndex(dragIndex);
                }

                if (dropIndicator)
                    dropIndicator->hide();
            }
        } break;

        case QEvent::DragLeave: {
            if (dropIndicator)
                dropIndicator->hide();
        } break;

        case QEvent::DragMove: {
            QDragMoveEvent *de = static_cast<QDragMoveEvent*>(e);

            long addr = 0;
            if (const QMimeData *mimeData = de->mimeData()) {
                bool ok = false;
                addr = mimeData->data("designer/tab").toLong(&ok);
                if (!ok) addr = 0;
                de->acceptProposedAction();
                de->accept();
            }

            if (long(this) != addr)
                return false;

            de->accept();
            de->acceptProposedAction();

            int index = 0;
            QRect rect;
            for (; index < count(); index++) {
                QRect rc = tabBar()->tabRect(index);
                if (rc.contains(de->pos())) {
                    rect = rc;
                    break;
                }
            }

            if (index == count() -1) {
                QRect rect2 = rect;
                rect2.setLeft(rect2.left() + rect2.width() / 2);
                if (rect2.contains(de->pos()))
                    index++;
            }

            if (!dropIndicator) {
                dropIndicator = new QWidget(this);
                QPalette p = dropIndicator->palette();
                p.setColor(backgroundRole(), Qt::red);
                dropIndicator->setPalette(p);
            }

            QPoint pos;
            if (index == count())
                pos = tabBar()->mapToParent(QPoint(rect.x() + rect.width(), rect.y()));
            else
                pos = tabBar()->mapToParent(QPoint(rect.x(), rect.y()));

            dropIndicator->setGeometry(pos.x(), pos.y() , 3, rect.height());
            dropIndicator->show();
        } break;

        case QEvent::Drop: {
            QDropEvent *de = static_cast<QDropEvent*>(e);

            long addr = 0;
            if (const QMimeData *mimeData = de->mimeData()) {
                bool ok = false;
                addr = mimeData->data("designer/tab").toLong(&ok);
                if (!ok) addr = 0;
            }

            if (addr == long(this)) {
                de->acceptProposedAction();
                de->accept();

                int newIndex = 0;
                for (; newIndex < count(); newIndex++) {
                    QRect rc = tabBar()->tabRect(newIndex);
                    if (rc.contains(de->pos()))
                        break;
                }

                if (newIndex == count() -1) {
                    QRect rect2 = tabBar()->tabRect(newIndex);
                    rect2.setLeft(rect2.left() + rect2.width() / 2);
                    if (rect2.contains(de->pos()))
                        newIndex++;
                }

                if (FormWindow *fw = FormWindow::findFormWindow(this)) {
                    MoveTabPageCommand *cmd = new MoveTabPageCommand(fw);
                    insertTab(dragIndex, dragPage, dragIcon, dragLabel);
                    cmd->init(this, dragPage, dragIcon, dragLabel, dragIndex, newIndex);
                    fw->commandHistory()->push(cmd);
                }
            }
        } break;

        default:
            break;
    }

    return false;
}

void QDesignerTabWidget::removeCurrentPage()
{
    if (!currentWidget())
        return;

    if (FormWindow *fw = FormWindow::findFormWindow(this)) {
        DeleteTabPageCommand *cmd = new DeleteTabPageCommand(fw);
        cmd->init(this);
        fw->commandHistory()->push(cmd);
    }
}

void QDesignerTabWidget::addPage()
{
    if (FormWindow *fw = FormWindow::findFormWindow(this)) {
        AddTabPageCommand *cmd = new AddTabPageCommand(fw);
        cmd->init(this);
        fw->commandHistory()->push(cmd);
    }
}

bool QDesignerTabWidget::canMove(QMouseEvent *e) const
{
    QPoint pt = pressPoint - e->pos();
    return pt.manhattanLength() > QApplication::startDragDistance();
}

void QDesignerTabWidget::slotCurrentChanged(int)
{
#if 0 // ### enable me
    if (QWidget *page = widget(index)) {
        if (FormWindow *fw = FormWindow::findFormWindow(this)) {
            fw->clearSelection();
            fw->selectWidget(this, true);
        }
    }
#endif
}
