/****************************************************************************
**
** 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 under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** 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/qpl/ for QPL licensing information.
** 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 "objectinspector.h"

// sdk
#include <container.h>
#include <qextensionmanager.h>
#include <abstractformeditor.h>
#include <abstractformwindow.h>
#include <abstractformwindowcursor.h>
#include <abstractwidgetdatabase.h>
#include <treewidget.h>

// Qt
#include <QApplication>
#include <QHeaderView>
#include <QStack>
#include <QScrollBar>
#include <QItemDelegate>
#include <QPair>
#include <QPainter>
#include <QVBoxLayout>

#include <qdebug.h>

ObjectInspector::ObjectInspector(AbstractFormEditor *core, QWidget *parent)
    : AbstractObjectInspector(parent),
      m_core(core),
      m_ignoreUpdate(false)
{
    QVBoxLayout *vbox = new QVBoxLayout(this);
    vbox->setMargin(0);

    m_treeWidget = new TreeWidget(this);
    vbox->addWidget(m_treeWidget);

    m_treeWidget->setColumnCount(2);
    m_treeWidget->headerItem()->setText(0, tr("Object"));
    m_treeWidget->headerItem()->setText(1, tr("Class"));

    m_treeWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    m_treeWidget->header()->setResizeMode(QHeaderView::Stretch, 1);

    connect(m_treeWidget, SIGNAL(doubleClicked(QTreeWidgetItem *, int, Qt::MouseButton, Qt::KeyboardModifiers)),
        this, SLOT(slotSelectionChanged()));

    connect(m_treeWidget, SIGNAL(returnPressed(QTreeWidgetItem *, int)),
        this, SLOT(slotSelectionChanged()));
}

ObjectInspector::~ObjectInspector()
{
}

AbstractFormEditor *ObjectInspector::core() const
{
    return m_core;
}

bool ObjectInspector::sortEntry(const QObject *a, const QObject *b)
{
    return a->objectName() < b->objectName();
}

void ObjectInspector::setFormWindow(AbstractFormWindow *fw)
{
    if (m_ignoreUpdate)
        return;

    m_formWindow = fw;

    int xoffset = m_treeWidget->horizontalScrollBar()->value();
    int yoffset = m_treeWidget->verticalScrollBar()->value();

    m_treeWidget->clear();

    if (!fw)
        return;

    AbstractWidgetDataBase *db = fw->core()->widgetDataBase();

    m_treeWidget->viewport()->setUpdatesEnabled(false);

    QStack< QPair<QTreeWidgetItem*, QObject*> > workingList;
    QObject *rootObject = fw->mainContainer();
    workingList.append(qMakePair(new QTreeWidgetItem(m_treeWidget), rootObject));

    while (!workingList.isEmpty()) {
        QTreeWidgetItem *item = workingList.top().first;
        QObject *object = workingList.top().second;
        workingList.pop();

        QString objectName = object->objectName();
        if (objectName.isEmpty())
            objectName = tr("<noname>");

        item->setText(0, objectName);

        QString className;
        if (AbstractWidgetDataBaseItem *widgetItem = db->item(db->indexOfObject(object, true))) {
            className = widgetItem->name();

            if (object->isWidgetType() && className == QLatin1String("QLayoutWidget")
                    && static_cast<QWidget*>(object)->layout()) {
                className = QLatin1String(static_cast<QWidget*>(object)->layout()->metaObject()->className());
            }

            item->setText(1, className);
            item->setIcon(0, widgetItem->icon());
        }

        QVariant ptr;
        qVariantSet(ptr, object, "QObject");
        item->setData(0, 1000, ptr);

        if (IContainer *c = qt_extension<IContainer*>(fw->core()->extensionManager(), object)) {
            for (int i=0; i<c->count(); ++i) {
                QObject *page = c->widget(i);

                QTreeWidgetItem *pageItem = new QTreeWidgetItem(item);
                workingList.append(qMakePair(pageItem, page));
            }
        } else {
            QList<QObject*> children = object->children();
            qSort(children.begin(), children.end(), ObjectInspector::sortEntry);
            foreach (QObject *child, children) {
                if (!child->isWidgetType() || !fw->isManaged(static_cast<QWidget*>(child)))
                    continue;

                QTreeWidgetItem *childItem = new QTreeWidgetItem(item);
                workingList.append(qMakePair(childItem, child));
            }
        }

        m_treeWidget->openItem(item);
    }

    m_treeWidget->horizontalScrollBar()->setValue(xoffset);
    m_treeWidget->verticalScrollBar()->setValue(yoffset);

    m_treeWidget->viewport()->setUpdatesEnabled(true);
    m_treeWidget->viewport()->update();
}

void ObjectInspector::slotSelectionChanged()
{
    if (!m_formWindow)
        return;

    m_formWindow->clearSelection(false);

    QList<QTreeWidgetItem*> items = m_treeWidget->selectedItems();
    foreach (QTreeWidgetItem *item, items) {
        QObject *object = 0;
        Q_ASSERT(qVariantGet(item->data(0, 1000), object, "QObject"));
        if (QWidget *widget = qt_cast<QWidget*>(object))
            m_formWindow->selectWidget(widget);
    }
}
