/****************************************************************************
**
** Copyright (C) 1992-2005 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 "qdesigner_taskmenu.h"
#include "qdesigner_command.h"
#include "qdesigner_promotedwidget.h"
#include "qtundo.h"
#include "promotetocustomwidgetdialog.h"
#include "widgetfactory.h"
#include "widgetdatabase.h"
#include "qlayout_widget.h"
#include "spacer_widget.h"

#include <abstractformeditor.h>
#include <abstractformwindow.h>
#include <abstractformwindowcursor.h>

#include <QtGui/QAction>
#include <QtGui/QWidget>
#include <QtGui/QInputDialog>
#include <QtGui/QMainWindow>
#include <QtGui/QDockWidget>
#include <QtCore/QVariant>

#include <QtCore/qdebug.h>

QDesignerTaskMenu::QDesignerTaskMenu(QWidget *widget, QObject *parent)
    : QObject(parent),
      m_widget(widget)
{
    m_changeObjectNameAction = new QAction(tr("Change Object Name"), this);
    connect(m_changeObjectNameAction, SIGNAL(triggered()), this, SLOT(changeObjectName()));

    m_createDockWidgetAction = new QAction(tr("Create Dock Window"), this);
    connect(m_createDockWidgetAction, SIGNAL(triggered()), this, SLOT(createDockWidget()));

    m_promoteToCustomWidgetAction = new QAction(tr("Promote to Custom Widget"), this);
    connect(m_promoteToCustomWidgetAction, SIGNAL(triggered()), this, SLOT(promoteToCustomWidget()));

    QString demote_string = tr("Demote from Custom Widget");
    if (const QDesignerPromotedWidget *promoted = qobject_cast<const QDesignerPromotedWidget*>(widget))
        demote_string = tr("Demote to ") + promoted->item()->extends();
    m_demoteFromCustomWidgetAction = new QAction(demote_string, this);
    connect(m_demoteFromCustomWidgetAction, SIGNAL(triggered()),
            this, SLOT(demoteFromCustomWidget()));
}

QDesignerTaskMenu::~QDesignerTaskMenu()
{
}

QWidget *QDesignerTaskMenu::widget() const
{
    return m_widget;
}

AbstractFormWindow *QDesignerTaskMenu::formWindow() const
{
    AbstractFormWindow *result = AbstractFormWindow::findFormWindow(widget());
    Q_ASSERT(result != 0);
    return result;
}

QList<QAction*> QDesignerTaskMenu::taskActions() const
{
    AbstractFormWindow *formWindow = AbstractFormWindow::findFormWindow(widget());
    Q_ASSERT(formWindow);

    QList<QAction*> actions;

    actions.append(m_changeObjectNameAction);

#if 0 // ### enable me after beta2
    if (qobject_cast<const QMainWindow*>(formWindow->mainContainer()) != 0) {
        actions.append(m_createDockWidgetAction);
    }
#endif

    if (qobject_cast<const QDesignerPromotedWidget*>(m_widget) == 0)
        actions.append(m_promoteToCustomWidgetAction);
    else
        actions.append(m_demoteFromCustomWidgetAction);

    return actions;
}

void QDesignerTaskMenu::changeObjectName()
{
    QString newObjectName = QInputDialog::getText(widget(), tr("Change Object Name"),
            tr("Object Name"), QLineEdit::Normal, widget()->objectName());

    if (!newObjectName.isEmpty()) {
        formWindow()->cursor()->setProperty("objectName", newObjectName);
    }
}

void QDesignerTaskMenu::createDockWidget()
{
    AbstractFormWindow *formWindow = AbstractFormWindow::findFormWindow(widget());
    Q_ASSERT(formWindow != 0);

    QMainWindow *mainWindow = qobject_cast<QMainWindow*>(formWindow->mainContainer());
    Q_ASSERT(mainWindow != 0);

    formWindow->beginCommand(tr("Create Dock Window"));

    AbstractWidgetFactory *widgetFactory = formWindow->core()->widgetFactory();
    QDockWidget *dockWidget = (QDockWidget *) widgetFactory->createWidget(QLatin1String("QDockWidget"), formWindow->mainContainer());
    Q_ASSERT(dockWidget);

    InsertWidgetCommand *cmd = new InsertWidgetCommand(formWindow);
    cmd->init(dockWidget);
    formWindow->commandHistory()->push(cmd);

    ReparentWidgetCommand *reparentCmd = new ReparentWidgetCommand(formWindow);
    reparentCmd->init(widget(), dockWidget);
    formWindow->commandHistory()->push(reparentCmd);

    SetDockWidgetWidgetCommand *setDockWidgetCmd = new SetDockWidgetWidgetCommand(formWindow);
    setDockWidgetCmd->init(dockWidget, m_widget);
    formWindow->commandHistory()->push(setDockWidgetCmd);

    AddDockWidgetCommand *addDockWidgetCmd = new AddDockWidgetCommand(formWindow);
    addDockWidgetCmd->init(mainWindow, dockWidget);
    formWindow->commandHistory()->push(addDockWidgetCmd);

    formWindow->endCommand();
}

QDesignerTaskMenuFactory::QDesignerTaskMenuFactory(QExtensionManager *extensionManager)
    : DefaultExtensionFactory(extensionManager)
{
}

QObject *QDesignerTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
{
    if (iid != Q_TYPEID(ITaskMenu))
        return 0;

    QWidget *widget = qobject_cast<QWidget*>(object);
    if (widget == 0)
        return 0;

    // check if is an internal widget (### generalize)
    if (qobject_cast<QLayoutWidget*>(widget) || qobject_cast<Spacer*>(widget))
        return 0;

    return new QDesignerTaskMenu(widget, parent);
}

void QDesignerTaskMenu::promoteToCustomWidget()
{
    AbstractFormWindow *fw = formWindow();
    AbstractFormEditor *core = fw->core();
    QWidget *wgt = widget();
    QWidget *parent = wgt->parentWidget();
    AbstractWidgetDataBase *db = core->widgetDataBase();
    WidgetFactory *factory = qobject_cast<WidgetFactory*>(core->widgetFactory());

    Q_ASSERT(qobject_cast<QDesignerPromotedWidget*>(wgt) == 0);

    QString base_class_name = factory->classNameOf(wgt);

    PromoteToCustomWidgetDialog dialog(db, base_class_name);
    if (!dialog.exec())
        return;

    QString custom_class_name = dialog.customClassName();
    QString include_file = dialog.includeFile();

    AbstractWidgetDataBaseItem *item = 0;
    int idx = db->indexOfClassName(custom_class_name);
    if (idx == -1) {
        item = new WidgetDataBaseItem(custom_class_name, tr("Promoted Widgets"));
        item->setCustom(true);
        item->setPromoted(true);
        item->setExtends(base_class_name);
        db->append(item);
    } else {
        item = db->item(idx);
    }
    item->setIncludeFile(include_file);

    fw->beginCommand(tr("Promote to custom widget"));

    QDesignerPromotedWidget *promoted
        = new QDesignerPromotedWidget(item, wgt, parent);
    promoted->setObjectName(QLatin1String("__qt__promoted_") + wgt->objectName());
    promoted->setGeometry(wgt->geometry());
    InsertWidgetCommand *insert_cmd = new InsertWidgetCommand(fw);
    insert_cmd->init(promoted);
    fw->commandHistory()->push(insert_cmd);

    ReparentWidgetCommand *reparent_cmd = new ReparentWidgetCommand(fw);
    reparent_cmd->init(wgt, promoted);
    fw->commandHistory()->push(reparent_cmd);

    fw->endCommand();

    fw->clearSelection();
    fw->selectWidget(promoted);
}

void QDesignerTaskMenu::demoteFromCustomWidget()
{
    AbstractFormWindow *fw = formWindow();
    QWidget *wgt = widget();
    QWidget *parent = wgt->parentWidget();

    QDesignerPromotedWidget *promoted = qobject_cast<QDesignerPromotedWidget*>(wgt);
    Q_ASSERT(promoted != 0);

    fw->beginCommand(tr("Demote to ") + promoted->item()->extends());

    ReparentWidgetCommand *reparent_cmd = new ReparentWidgetCommand(fw);
    reparent_cmd->init(promoted->child(), parent);
    fw->commandHistory()->push(reparent_cmd);

    DeleteWidgetCommand *delete_cmd = new DeleteWidgetCommand(fw);
    delete_cmd->init(promoted);
    fw->commandHistory()->push(delete_cmd);

    fw->endCommand();

    fw->clearSelection();
    fw->selectWidget(promoted);
}

