tools/designer/src/lib/shared/qdesigner_tabwidget.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,569 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Designer of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdesigner_tabwidget_p.h"
+#include "qdesigner_command_p.h"
+#include "qdesigner_propertycommand_p.h"
+#include "promotiontaskmenu_p.h"
+#include "formwindowbase_p.h"
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtGui/QApplication>
+#include <QtGui/QTabBar>
+#include <QtGui/QAction>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+#include <QtGui/QLabel>
+#include <QtGui/QTabWidget>
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace qdesigner_internal {
+// Store tab widget as drag source
+class MyMimeData : public QMimeData
+{
+    Q_OBJECT
+public:
+    MyMimeData(const QTabWidget *tab) : m_tab(tab) {}
+    static bool fromMyTab(const QMimeData *mimeData, const QTabWidget *tab) {
+        if (!mimeData)
+            return false;
+        const MyMimeData *m = qobject_cast<const MyMimeData *>(mimeData);
+        return m &&  m->m_tab ==  tab;
+    }
+private:
+    const QTabWidget *m_tab;
+};
+
+} // namespace qdesigner_internal
+
+// ------------- QTabWidgetEventFilter
+
+QTabWidgetEventFilter::QTabWidgetEventFilter(QTabWidget *parent) :
+    QObject(parent),
+    m_tabWidget(parent),
+    m_dropIndicator(0),
+    m_dragPage(0),
+    m_mousePressed(false),
+    m_actionDeletePage(new QAction(tr("Delete"),  this)),
+    m_actionInsertPage(new QAction(tr("Before Current Page"), this)),
+    m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)),
+    m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this))
+{
+    tabBar()->setAcceptDrops(true);
+    tabBar()->installEventFilter(this);
+
+    connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage()));
+    connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter()));
+    connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage()));
+}
+
+QTabWidgetEventFilter::~QTabWidgetEventFilter()
+{
+}
+
+void QTabWidgetEventFilter::install(QTabWidget *tabWidget)
+{
+    new QTabWidgetEventFilter(tabWidget);
+}
+
+QTabWidgetEventFilter *QTabWidgetEventFilter::eventFilterOf(const QTabWidget *tabWidget)
+{
+    // Look for 1st order children only..otherwise, we might get filters of nested tab widgets
+    const QObjectList children = tabWidget->children();
+    const QObjectList::const_iterator cend = children.constEnd();
+    for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) {
+        QObject *o = *it;
+        if (!o->isWidgetType())
+            if (QTabWidgetEventFilter *ef = qobject_cast<QTabWidgetEventFilter*>(o))
+                return ef;
+    }
+    return 0;
+}
+
+QMenu *QTabWidgetEventFilter::addTabWidgetContextMenuActions(const QTabWidget *tabWidget, QMenu *popup)
+{
+    QTabWidgetEventFilter *filter = eventFilterOf(tabWidget);
+    if (!filter)
+        return 0;
+    return filter->addContextMenuActions(popup);
+}
+
+QTabBar *QTabWidgetEventFilter::tabBar() const
+{
+    // QTabWidget::tabBar() accessor is protected, grmbl...
+    if (!m_cachedTabBar) {
+        const QList<QTabBar *> tabBars = qFindChildren<QTabBar *>(m_tabWidget);
+        Q_ASSERT(tabBars.size() == 1);
+        m_cachedTabBar = tabBars.front();
+    }
+    return m_cachedTabBar;
+
+}
+
+static bool canMove(const QPoint &pressPoint, const QMouseEvent *e)
+{
+    const QPoint pt = pressPoint - e->pos();
+    return pt.manhattanLength() > QApplication::startDragDistance();
+}
+
+bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e)
+{
+    const QEvent::Type type = e->type();
+    // Do not try to locate tab bar and form window, etc. for uninteresting events and
+    // avoid asserts about missing tab bars when being destroyed
+    switch (type) {
+    case QEvent::MouseButtonDblClick:
+    case QEvent::MouseButtonPress:
+    case QEvent::MouseButtonRelease:
+    case QEvent::MouseMove:
+    case QEvent::DragLeave:
+    case QEvent::DragEnter:
+    case QEvent::DragMove:
+    case QEvent::Drop:
+        break;
+    default:
+        return false;
+    }
+
+    if (o != tabBar())
+        return false;
+
+    QDesignerFormWindowInterface *fw = formWindow();
+    if (!fw)
+        return false;
+
+    switch (type) {
+    case QEvent::MouseButtonDblClick:
+        break;
+    case QEvent::MouseButtonPress: {
+        QMouseEvent *mev = static_cast<QMouseEvent*>(e);
+        if (QDesignerFormWindowInterface *fw = formWindow()) {
+            fw->clearSelection();
+            fw->selectWidget(m_tabWidget, true);
+        }
+        if (mev->button() & Qt::LeftButton) {
+            m_mousePressed = true;
+            m_pressPoint = mev->pos();
+
+            QTabBar *tabbar = tabBar();
+            const int count = tabbar->count();
+            for (int i = 0; i < count; ++i) {
+                if (tabbar->tabRect(i).contains(m_pressPoint)) {
+                    if (i != tabbar->currentIndex()) {
+                        qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw);
+                        cmd->init(m_tabWidget, QLatin1String("currentIndex"), i);
+                        fw->commandHistory()->push(cmd);
+                    }
+                    break;
+                }
+            }
+        }
+    } break;
+
+    case QEvent::MouseButtonRelease:
+        m_mousePressed = false;
+        break;
+
+    case QEvent::MouseMove: {
+        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
+        if (m_mousePressed && canMove(m_pressPoint, mouseEvent)) {
+            const int index = m_tabWidget->currentIndex();
+            if (index == -1)
+                break;
+
+            m_mousePressed = false;
+            QDrag *drg = new QDrag(m_tabWidget);
+            drg->setMimeData(new qdesigner_internal::MyMimeData(m_tabWidget));
+
+            m_dragIndex = index;
+            m_dragPage  = m_tabWidget->currentWidget();
+            m_dragLabel = m_tabWidget->tabText(index);
+            m_dragIcon  = m_tabWidget->tabIcon(index);
+            if (m_dragIcon.isNull()) {
+                QLabel *label = new QLabel(m_dragLabel);
+                label->adjustSize();
+                drg->setPixmap(QPixmap::grabWidget(label));
+                label->deleteLater();
+            } else {
+                drg->setPixmap(m_dragIcon.pixmap(22, 22));
+            }
+
+            m_tabWidget->removeTab(m_dragIndex);
+
+            const Qt::DropActions dropAction = drg->start(Qt::MoveAction);
+
+            if (dropAction == Qt::IgnoreAction) {
+                // abort
+                m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel);
+                m_tabWidget->setCurrentIndex(m_dragIndex);
+            }
+
+            if (m_dropIndicator)
+                m_dropIndicator->hide();
+        }
+    } break;
+
+    case QEvent::DragLeave: {
+        if (m_dropIndicator)
+            m_dropIndicator->hide();
+    } break;
+
+    case QEvent::DragEnter:
+    case QEvent::DragMove: {
+        QDragMoveEvent *de = static_cast<QDragMoveEvent*>(e);
+        if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget))
+            return false;
+
+        if (de->proposedAction() == Qt::MoveAction)
+            de->acceptProposedAction();
+        else {
+            de->setDropAction(Qt::MoveAction);
+            de->accept();
+        }
+
+        QRect rect;
+        const int index = pageFromPosition(de->pos(), rect);
+
+        if (!m_dropIndicator) {
+            m_dropIndicator = new QWidget(m_tabWidget);
+            QPalette p = m_dropIndicator->palette();
+            p.setColor(m_tabWidget->backgroundRole(), Qt::red);
+            m_dropIndicator->setPalette(p);
+        }
+
+        QPoint pos;
+        if (index == m_tabWidget->count())
+            pos = tabBar()->mapToParent(QPoint(rect.x() + rect.width(), rect.y()));
+        else
+            pos = tabBar()->mapToParent(QPoint(rect.x(), rect.y()));
+
+        m_dropIndicator->setGeometry(pos.x(), pos.y() , 3, rect.height());
+        m_dropIndicator->show();
+    } break;
+
+    case QEvent::Drop: {
+        QDropEvent *de = static_cast<QDropEvent*>(e);
+        if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget))
+            return false;
+        de->acceptProposedAction();
+        de->accept();
+
+        QRect rect;
+        const int newIndex = pageFromPosition(de->pos(), rect);
+
+        qdesigner_internal::MoveTabPageCommand *cmd = new qdesigner_internal::MoveTabPageCommand(fw);
+        m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel);
+        cmd->init(m_tabWidget, m_dragPage, m_dragIcon, m_dragLabel, m_dragIndex, newIndex);
+        fw->commandHistory()->push(cmd);
+    } break;
+
+    default:
+        break;
+    }
+
+    return false;
+}
+
+void QTabWidgetEventFilter::removeCurrentPage()
+{
+    if (!m_tabWidget->currentWidget())
+        return;
+
+    if (QDesignerFormWindowInterface *fw = formWindow()) {
+        qdesigner_internal::DeleteTabPageCommand *cmd = new qdesigner_internal::DeleteTabPageCommand(fw);
+        cmd->init(m_tabWidget);
+        fw->commandHistory()->push(cmd);
+    }
+}
+
+void QTabWidgetEventFilter::addPage()
+{
+    if (QDesignerFormWindowInterface *fw = formWindow()) {
+        qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw);
+        cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertBefore);
+        fw->commandHistory()->push(cmd);
+    }
+}
+
+void QTabWidgetEventFilter::addPageAfter()
+{
+    if (QDesignerFormWindowInterface *fw = formWindow()) {
+        qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw);
+        cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertAfter);
+        fw->commandHistory()->push(cmd);
+    }
+}
+
+QDesignerFormWindowInterface *QTabWidgetEventFilter::formWindow() const
+{
+    return QDesignerFormWindowInterface::findFormWindow(const_cast<QTabWidget*>(m_tabWidget));
+}
+
+// Get page from mouse position. Default to new page if in right half of last page?
+int QTabWidgetEventFilter::pageFromPosition(const QPoint &pos, QRect &rect) const
+{
+    int index = 0;
+    const QTabBar *tabbar = tabBar();
+    const int count = m_tabWidget->count();
+    for (; index < count; index++) {
+        const QRect rc = tabbar->tabRect(index);
+        if (rc.contains(pos)) {
+            rect = rc;
+            break;
+        }
+    }
+
+    if (index == count -1) {
+        QRect rect2 = rect;
+        rect2.setLeft(rect2.left() + rect2.width() / 2);
+        if (rect2.contains(pos))
+            index++;
+    }
+    return index;
+}
+
+QMenu *QTabWidgetEventFilter::addContextMenuActions(QMenu *popup)
+{
+    QMenu *pageMenu = 0;
+    const int count = m_tabWidget->count();
+    m_actionDeletePage->setEnabled(count);
+    if (count) {
+        const int currentIndex = m_tabWidget->currentIndex();
+        const QString pageSubMenuLabel = tr("Page %1 of %2").arg(currentIndex + 1).arg(count);
+        pageMenu = popup->addMenu(pageSubMenuLabel);
+        pageMenu->addAction(m_actionDeletePage);
+        // Set up promotion menu for current widget.
+        if (QWidget *page =  m_tabWidget->currentWidget ()) {
+            m_pagePromotionTaskMenu->setWidget(page);
+            m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(m_tabWidget),
+                                                qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit,
+                                                pageMenu);
+        }
+        QMenu *insertPageMenu = popup->addMenu(tr("Insert Page"));
+        insertPageMenu->addAction(m_actionInsertPageAfter);
+        insertPageMenu->addAction(m_actionInsertPage);
+    } else {
+        QAction *insertPageAction = popup->addAction(tr("Insert Page"));
+        connect(insertPageAction, SIGNAL(triggered()), this, SLOT(addPage()));
+    }
+    popup->addSeparator();
+    return pageMenu;
+}
+
+// ----------- QTabWidgetPropertySheet
+
+static const char *currentTabTextKey = "currentTabText";
+static const char *currentTabNameKey = "currentTabName";
+static const char *currentTabIconKey = "currentTabIcon";
+static const char *currentTabToolTipKey = "currentTabToolTip";
+static const char *currentTabWhatsThisKey = "currentTabWhatsThis";
+
+QTabWidgetPropertySheet::QTabWidgetPropertySheet(QTabWidget *object, QObject *parent) :
+    QDesignerPropertySheet(object, parent),
+    m_tabWidget(object)
+{
+    createFakeProperty(QLatin1String(currentTabTextKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+    createFakeProperty(QLatin1String(currentTabNameKey), QString());
+    createFakeProperty(QLatin1String(currentTabIconKey), qVariantFromValue(qdesigner_internal::PropertySheetIconValue()));
+    if (formWindowBase())
+        formWindowBase()->addReloadableProperty(this, indexOf(QLatin1String(currentTabIconKey)));
+    createFakeProperty(QLatin1String(currentTabToolTipKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+    createFakeProperty(QLatin1String(currentTabWhatsThisKey), qVariantFromValue(qdesigner_internal::PropertySheetStringValue()));
+}
+
+QTabWidgetPropertySheet::TabWidgetProperty QTabWidgetPropertySheet::tabWidgetPropertyFromName(const QString &name)
+{
+    typedef QHash<QString, TabWidgetProperty> TabWidgetPropertyHash;
+    static TabWidgetPropertyHash tabWidgetPropertyHash;
+    if (tabWidgetPropertyHash.empty()) {
+        tabWidgetPropertyHash.insert(QLatin1String(currentTabTextKey),      PropertyCurrentTabText);
+        tabWidgetPropertyHash.insert(QLatin1String(currentTabNameKey),      PropertyCurrentTabName);
+        tabWidgetPropertyHash.insert(QLatin1String(currentTabIconKey),      PropertyCurrentTabIcon);
+        tabWidgetPropertyHash.insert(QLatin1String(currentTabToolTipKey),   PropertyCurrentTabToolTip);
+        tabWidgetPropertyHash.insert(QLatin1String(currentTabWhatsThisKey), PropertyCurrentTabWhatsThis);
+    }
+    return tabWidgetPropertyHash.value(name, PropertyTabWidgetNone);
+}
+
+void QTabWidgetPropertySheet::setProperty(int index, const QVariant &value)
+{
+    const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+    if (tabWidgetProperty == PropertyTabWidgetNone) {
+        QDesignerPropertySheet::setProperty(index, value);
+        return;
+    }
+
+    // index-dependent
+    const int currentIndex = m_tabWidget->currentIndex();
+    QWidget *currentWidget = m_tabWidget->currentWidget();
+    if (!currentWidget)
+        return;
+
+    switch (tabWidgetProperty) {
+    case PropertyCurrentTabText:
+        m_tabWidget->setTabText(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+        m_pageToData[currentWidget].text = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+        break;
+    case PropertyCurrentTabName:
+        currentWidget->setObjectName(value.toString());
+        break;
+    case PropertyCurrentTabIcon:
+        m_tabWidget->setTabIcon(currentIndex, qvariant_cast<QIcon>(resolvePropertyValue(index, value)));
+        m_pageToData[currentWidget].icon = qVariantValue<qdesigner_internal::PropertySheetIconValue>(value);
+        break;
+    case PropertyCurrentTabToolTip:
+        m_tabWidget->setTabToolTip(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+        m_pageToData[currentWidget].tooltip = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+        break;
+    case PropertyCurrentTabWhatsThis:
+        m_tabWidget->setTabWhatsThis(currentIndex, qvariant_cast<QString>(resolvePropertyValue(index, value)));
+        m_pageToData[currentWidget].whatsthis = qVariantValue<qdesigner_internal::PropertySheetStringValue>(value);
+        break;
+    case PropertyTabWidgetNone:
+        break;
+    }
+}
+
+bool QTabWidgetPropertySheet::isEnabled(int index) const
+{
+    if (tabWidgetPropertyFromName(propertyName(index)) == PropertyTabWidgetNone)
+        return QDesignerPropertySheet::isEnabled(index);
+    return m_tabWidget->currentIndex() != -1;
+}
+
+QVariant QTabWidgetPropertySheet::property(int index) const
+{
+    const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+    if (tabWidgetProperty == PropertyTabWidgetNone)
+        return  QDesignerPropertySheet::property(index);
+
+    // index-dependent
+    QWidget *currentWidget = m_tabWidget->currentWidget();
+    if (!currentWidget) {
+        if (tabWidgetProperty == PropertyCurrentTabIcon)
+            return qVariantFromValue(qdesigner_internal::PropertySheetIconValue());
+        if (tabWidgetProperty == PropertyCurrentTabText)
+            return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+        if (tabWidgetProperty == PropertyCurrentTabToolTip)
+            return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+        if (tabWidgetProperty == PropertyCurrentTabWhatsThis)
+            return qVariantFromValue(qdesigner_internal::PropertySheetStringValue());
+        return QVariant(QString());
+    }
+
+    // index-dependent
+    switch (tabWidgetProperty) {
+    case PropertyCurrentTabText:
+        return qVariantFromValue(m_pageToData.value(currentWidget).text);
+    case PropertyCurrentTabName:
+        return currentWidget->objectName();
+    case PropertyCurrentTabIcon:
+        return qVariantFromValue(m_pageToData.value(currentWidget).icon);
+    case PropertyCurrentTabToolTip:
+        return qVariantFromValue(m_pageToData.value(currentWidget).tooltip);
+    case PropertyCurrentTabWhatsThis:
+        return qVariantFromValue(m_pageToData.value(currentWidget).whatsthis);
+    case PropertyTabWidgetNone:
+        break;
+    }
+    return QVariant();
+}
+
+bool QTabWidgetPropertySheet::reset(int index)
+{
+    const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index));
+    if (tabWidgetProperty == PropertyTabWidgetNone)
+        return QDesignerPropertySheet::reset(index);
+
+    // index-dependent
+    QWidget *currentWidget = m_tabWidget->currentWidget();
+    if (!currentWidget)
+        return false;
+
+    // index-dependent
+    switch (tabWidgetProperty) {
+    case PropertyCurrentTabName:
+        setProperty(index, QString());
+        break;
+    case PropertyCurrentTabToolTip:
+        m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue();
+        setProperty(index, QString());
+        break;
+    case PropertyCurrentTabWhatsThis:
+        m_pageToData[currentWidget].whatsthis = qdesigner_internal::PropertySheetStringValue();
+        setProperty(index, QString());
+        break;
+    case PropertyCurrentTabText:
+        m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue();
+        setProperty(index, QString());
+        break;
+    case PropertyCurrentTabIcon:
+        m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue();
+        setProperty(index, QIcon());
+        break;
+    case PropertyTabWidgetNone:
+        break;
+    }
+    return true;
+}
+
+bool QTabWidgetPropertySheet::checkProperty(const QString &propertyName)
+{
+    switch (tabWidgetPropertyFromName(propertyName)) {
+    case PropertyCurrentTabText:
+    case PropertyCurrentTabName:
+    case PropertyCurrentTabToolTip:
+    case PropertyCurrentTabWhatsThis:
+    case PropertyCurrentTabIcon:
+        return false;
+    default:
+        break;
+    }
+    return true;
+}
+
+QT_END_NAMESPACE
+
+#include "qdesigner_tabwidget.moc" // required for MyMimeData