diff -r 000000000000 -r 1918ee327afb tools/designer/src/lib/shared/qdesigner_tabwidget.cpp --- /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 + +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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(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 tabBars = qFindChildren(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(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(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(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(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(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 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(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].text = qVariantValue(value); + break; + case PropertyCurrentTabName: + currentWidget->setObjectName(value.toString()); + break; + case PropertyCurrentTabIcon: + m_tabWidget->setTabIcon(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].icon = qVariantValue(value); + break; + case PropertyCurrentTabToolTip: + m_tabWidget->setTabToolTip(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].tooltip = qVariantValue(value); + break; + case PropertyCurrentTabWhatsThis: + m_tabWidget->setTabWhatsThis(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].whatsthis = qVariantValue(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