/*
 * Copyright 2011 Aurélien Gâteau <agateau@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#include "column-resizer.h"

#include <QDebug>
#include <QEvent>
#include <QFormLayout>
#include <QGridLayout>
#include <QTimer>
#include <QWidget>

class FormLayoutWidgetItem : public QWidgetItem
{
public:
    FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole)
    : QWidgetItem(widget)
    , m_width(-1)
    , m_formLayout(formLayout)
    , m_itemRole(itemRole)
    {}

    QSize sizeHint() const
    {
        QSize size = QWidgetItem::sizeHint();
        if (m_width != -1) {
            size.setWidth(m_width);
        }
        return size;
    }

    QSize minimumSize() const
    {
        QSize size = QWidgetItem::minimumSize();
        if (m_width != -1) {
            size.setWidth(m_width);
        }
        return size;
    }

    QSize maximumSize() const
    {
        QSize size = QWidgetItem::maximumSize();
        if (m_width != -1) {
            size.setWidth(m_width);
        }
        return size;
    }

    void setWidth(int width)
    {
        if (width != m_width) {
            m_width = width;
            invalidate();
        }
    }

    void setGeometry(const QRect& _rect)
    {
        QRect rect = _rect;
        int width = widget()->sizeHint().width();
        if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) {
            rect.setLeft(rect.right() - width);
        }
        QWidgetItem::setGeometry(rect);
    }

    QFormLayout* formLayout() const
    {
        return m_formLayout;
    }

private:
    int m_width;
    QFormLayout* m_formLayout;
    QFormLayout::ItemRole m_itemRole;
};

typedef QPair<QGridLayout*, int> GridColumnInfo;

class ColumnResizerPrivate
{
public:
    ColumnResizerPrivate(ColumnResizer* q_ptr)
    : q(q_ptr)
    , m_updateTimer(new QTimer(q))
    {
        m_updateTimer->setSingleShot(true);
        m_updateTimer->setInterval(0);
        QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth()));
    }

    void scheduleWidthUpdate()
    {
        m_updateTimer->start();
    }

    ColumnResizer* q;
    QTimer* m_updateTimer;
    QList<QWidget*> m_widgets;
    QList<FormLayoutWidgetItem*> m_wrWidgetItemList;
    QList<GridColumnInfo> m_gridColumnInfoList;
};

ColumnResizer::ColumnResizer(QObject* parent)
: QObject(parent)
, d(new ColumnResizerPrivate(this))
{}

ColumnResizer::~ColumnResizer()
{
    delete d;
}

void ColumnResizer::addWidget(QWidget* widget)
{
    d->m_widgets.append(widget);
    widget->installEventFilter(this);
    d->scheduleWidthUpdate();
}

void ColumnResizer::updateWidth()
{
    int width = 0;
    Q_FOREACH(QWidget* widget, d->m_widgets) {
        width = qMax(widget->sizeHint().width(), width);
    }
    Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) {
        item->setWidth(width);
        item->formLayout()->update();
    }
    Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) {
        info.first->setColumnMinimumWidth(info.second, width);
    }
}

bool ColumnResizer::eventFilter(QObject*, QEvent* event)
{
    if (event->type() == QEvent::Resize) {
        d->scheduleWidthUpdate();
    }
    return false;
}

void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column)
{
    Q_ASSERT(column >= 0);
    QGridLayout* gridLayout = qobject_cast<QGridLayout*>(layout);
    QFormLayout* formLayout = qobject_cast<QFormLayout*>(layout);
    if (gridLayout) {
        addWidgetsFromGridLayout(gridLayout, column);
    } else if (formLayout) {
        if (column > QFormLayout::SpanningRole) {
            qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout";
            return;
        }
        QFormLayout::ItemRole role = static_cast<QFormLayout::ItemRole>(column);
        addWidgetsFromFormLayout(formLayout, role);
    } else {
        qCritical() << "Don't know how to handle layout" << layout;
    }
}

void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column)
{
    for (int row = 0; row < layout->rowCount(); ++row) {
        QLayoutItem* item = layout->itemAtPosition(row, column);
        if (!item) {
            continue;
        }
        QWidget* widget = item->widget();
        if (!widget) {
            continue;
        }
        addWidget(widget);
    }
    d->m_gridColumnInfoList << GridColumnInfo(layout, column);
}

void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role)
{
    for (int row = 0; row < layout->rowCount(); ++row) {
        QLayoutItem* item = layout->itemAt(row, role);
        if (!item) {
            continue;
        }
        QWidget* widget = item->widget();
        if (!widget) {
            continue;
        }
        layout->removeItem(item);
        delete item;
        FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role);
        layout->setItem(row, role, newItem);
        addWidget(widget);
        d->m_wrWidgetItemList << newItem;
    }
}

#include <column-resizer.moc>
// vi: ts=4 sw=4 et
