diff options
Diffstat (limited to 'src/gui')
119 files changed, 4500 insertions, 2207 deletions
diff --git a/src/gui/dialogs/qcolordialog.cpp b/src/gui/dialogs/qcolordialog.cpp index a7df999..44a82ef 100644 --- a/src/gui/dialogs/qcolordialog.cpp +++ b/src/gui/dialogs/qcolordialog.cpp @@ -62,6 +62,7 @@ #include "qmime.h" #include "qspinbox.h" #include "qdialogbuttonbox.h" +#include "private/qguiplatformplugin_p.h" #ifdef Q_WS_S60 #include "private/qt_s60_p.h" @@ -1454,6 +1455,8 @@ void QColorDialogPrivate::init(const QColor &initial) q->setSizeGripEnabled(false); q->setWindowTitle(QColorDialog::tr("Select Color")); + nativeDialogInUse = false; + nextCust = 0; QVBoxLayout *mainLay = new QVBoxLayout(q); // there's nothing in this dialog that benefits from sizing up @@ -1719,6 +1722,8 @@ void QColorDialog::setCurrentColor(const QColor &color) d->setCurrentQColor(color); d->setCocoaPanelColor(color); #endif + if (d->nativeDialogInUse) + qt_guiPlatformPlugin()->colorDialogSetCurrentColor(this, color); } QColor QColorDialog::currentColor() const @@ -1871,6 +1876,17 @@ void QColorDialog::setVisible(bool visible) setAttribute(Qt::WA_DontShowOnScreen, false); } } +#else + + if (!(d->opts & DontUseNativeDialog) && qt_guiPlatformPlugin()->colorDialogSetVisible(this, visible)) { + d->nativeDialogInUse = true; + // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below + // updates the state correctly, but skips showing the non-native version: + setAttribute(Qt::WA_DontShowOnScreen); + } else { + d->nativeDialogInUse = false; + setAttribute(Qt::WA_DontShowOnScreen, false); + } #endif QDialog::setVisible(visible); @@ -1970,8 +1986,8 @@ QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent) QColorDialog::~QColorDialog() { -#if defined(Q_WS_MAC) Q_D(QColorDialog); +#if defined(Q_WS_MAC) if (d->delegate) { d->releaseCocoaColorPanelDelegate(); QColorDialogPrivate::sharedColorPanelAvailable = true; @@ -1985,6 +2001,9 @@ QColorDialog::~QColorDialog() settings.setValue(QLatin1String("Qt/customColors/") + QString::number(i), cusrgb[i]); } #endif + if (d->nativeDialogInUse) + qt_guiPlatformPlugin()->colorDialogDelete(this); + } diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index f6b88bb..9e4fdd1 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -44,6 +44,7 @@ #include <qapplication.h> #include <qtimer.h> #include <qdialogbuttonbox.h> +#include <qabstracteventdispatcher.h> #include <private/qapplication_p.h> #include <private/qt_mac_p.h> #include <qdebug.h> @@ -319,6 +320,7 @@ QT_USE_NAMESPACE QMacCocoaAutoReleasePool pool; mDialogIsExecuting = true; [NSApp runModalForWindow:mColorPanel]; + QAbstractEventDispatcher::instance()->interrupt(); if (mResultCode == NSCancelButton) mPriv->colorDialog()->reject(); else @@ -411,7 +413,7 @@ void QColorDialogPrivate::openCocoaColorPanel(const QColor &initial, void QColorDialogPrivate::closeCocoaColorPanel() { - [[static_cast<QCocoaColorPanelDelegate *>(delegate) colorPanel] close]; + [static_cast<QCocoaColorPanelDelegate *>(delegate) onCancelClicked]; } void QColorDialogPrivate::releaseCocoaColorPanelDelegate() diff --git a/src/gui/dialogs/qcolordialog_p.h b/src/gui/dialogs/qcolordialog_p.h index c7cabfb..81df503 100644 --- a/src/gui/dialogs/qcolordialog_p.h +++ b/src/gui/dialogs/qcolordialog_p.h @@ -114,6 +114,7 @@ public: QColorDialog::ColorDialogOptions opts; QPointer<QObject> receiverToDisconnectOnClose; QByteArray memberToDisconnectOnClose; + bool nativeDialogInUse; #ifdef Q_WS_MAC void openCocoaColorPanel(const QColor &initial, diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index 7df49fa..ed2d676 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -673,28 +673,6 @@ void QDialog::keyPressEvent(QKeyEvent *e) case Qt::Key_Escape: reject(); break; - case Qt::Key_Up: - case Qt::Key_Left: - if (focusWidget() && - (focusWidget()->focusPolicy() == Qt::StrongFocus || - focusWidget()->focusPolicy() == Qt::WheelFocus)) { - e->ignore(); - break; - } - // call ours, since c++ blocks us from calling the one - // belonging to focusWidget(). - focusNextPrevChild(false); - break; - case Qt::Key_Down: - case Qt::Key_Right: - if (focusWidget() && - (focusWidget()->focusPolicy() == Qt::StrongFocus || - focusWidget()->focusPolicy() == Qt::WheelFocus)) { - e->ignore(); - break; - } - focusNextPrevChild(true); - break; default: e->ignore(); return; diff --git a/src/gui/dialogs/qerrormessage.cpp b/src/gui/dialogs/qerrormessage.cpp index 436ef94..762936a 100644 --- a/src/gui/dialogs/qerrormessage.cpp +++ b/src/gui/dialogs/qerrormessage.cpp @@ -245,12 +245,6 @@ QErrorMessage::QErrorMessage(QWidget * parent) Q_D(QErrorMessage); QGridLayout * grid = new QGridLayout(this); d->icon = new QLabel(this); -#ifdef QT_SOFTKEYS_ENABLED - d->okAction = new QAction(this); - d->okAction->setSoftKeyRole(QAction::PositiveSoftKey); - connect(d->okAction, SIGNAL(triggered()), this, SLOT(accept())); - addAction(d->okAction); -#endif #ifndef QT_NO_MESSAGEBOX d->icon->setPixmap(QMessageBox::standardIcon(QMessageBox::Information)); d->icon->setAlignment(Qt::AlignHCenter | Qt::AlignTop); @@ -262,6 +256,13 @@ QErrorMessage::QErrorMessage(QWidget * parent) d->again->setChecked(true); grid->addWidget(d->again, 1, 1, Qt::AlignTop); d->ok = new QPushButton(this); +#ifdef QT_SOFTKEYS_ENABLED + d->okAction = new QAction(d->ok); + d->okAction->setSoftKeyRole(QAction::PositiveSoftKey); + connect(d->okAction, SIGNAL(triggered()), this, SLOT(accept())); + addAction(d->okAction); +#endif + #if defined(Q_WS_WINCE) || defined(Q_WS_S60) d->ok->setFixedSize(0,0); diff --git a/src/gui/dialogs/qfiledialog_mac.mm b/src/gui/dialogs/qfiledialog_mac.mm index 3a4ecce..8e4c461 100644 --- a/src/gui/dialogs/qfiledialog_mac.mm +++ b/src/gui/dialogs/qfiledialog_mac.mm @@ -62,6 +62,7 @@ #include <qvarlengtharray.h> #include <qdesktopwidget.h> #include <stdlib.h> +#include <qabstracteventdispatcher.h> #include "ui_qfiledialog.h" QT_BEGIN_NAMESPACE @@ -245,6 +246,8 @@ QT_USE_NAMESPACE mReturnCode = [mSavePanel runModalForDirectory:mCurrentDir file:selectable ? filename : @"untitled"]; + + QAbstractEventDispatcher::instance()->interrupt(); return (mReturnCode == NSOKButton); } diff --git a/src/gui/dialogs/qfiledialog_p.h b/src/gui/dialogs/qfiledialog_p.h index 54fc0e0..32cd397 100644 --- a/src/gui/dialogs/qfiledialog_p.h +++ b/src/gui/dialogs/qfiledialog_p.h @@ -76,6 +76,8 @@ #include <qdebug.h> #include "qsidebar_p.h" #include "qfscompleter_p.h" +#include "private/qguiplatformplugin_p.h" + #if defined (Q_OS_UNIX) #include <unistd.h> @@ -405,17 +407,17 @@ inline QString QFileDialogPrivate::rootPath() const { #ifndef Q_WS_MAC // Dummies for platforms that don't use native dialogs: - inline void QFileDialogPrivate::deleteNativeDialog_sys() {} - inline bool QFileDialogPrivate::setVisible_sys(bool) { return false; } - inline QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys(){ return QDialog::Rejected; } - inline void QFileDialogPrivate::setDirectory_sys(const QString &) {} - inline QString QFileDialogPrivate::directory_sys() const { return QString(); } - inline void QFileDialogPrivate::selectFile_sys(const QString &) {} - inline QStringList QFileDialogPrivate::selectedFiles_sys() const { return QStringList(); } - inline void QFileDialogPrivate::setFilter_sys() {} - inline void QFileDialogPrivate::setNameFilters_sys(const QStringList &) {} - inline void QFileDialogPrivate::selectNameFilter_sys(const QString &) {} - inline QString QFileDialogPrivate::selectedNameFilter_sys() const { return QString(); } + inline void QFileDialogPrivate::deleteNativeDialog_sys() { qt_guiPlatformPlugin()->fileDialogDelete(q_func()); } + inline bool QFileDialogPrivate::setVisible_sys(bool visible) { return qt_guiPlatformPlugin()->fileDialogSetVisible(q_func(), visible); } + inline QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys(){ return qt_guiPlatformPlugin()->fileDialogResultCode(q_func()); } + inline void QFileDialogPrivate::setDirectory_sys(const QString &directory) { qt_guiPlatformPlugin()->fileDialogSetDirectory(q_func(), directory); } + inline QString QFileDialogPrivate::directory_sys() const { return qt_guiPlatformPlugin()->fileDialogDirectory(q_func()); } + inline void QFileDialogPrivate::selectFile_sys(const QString &filename) { qt_guiPlatformPlugin()->fileDialogSelectFile(q_func(), filename); } + inline QStringList QFileDialogPrivate::selectedFiles_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedFiles(q_func()); } + inline void QFileDialogPrivate::setFilter_sys() { qt_guiPlatformPlugin()->fileDialogSetFilter(q_func()); } + inline void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters) { qt_guiPlatformPlugin()->fileDialogSetNameFilters(q_func(), filters); } + inline void QFileDialogPrivate::selectNameFilter_sys(const QString &filter) { qt_guiPlatformPlugin()->fileDialogSelectNameFilter(q_func(), filter); } + inline QString QFileDialogPrivate::selectedNameFilter_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedNameFilter(q_func()); } #endif QT_END_NAMESPACE diff --git a/src/gui/dialogs/qprintdialog_mac.mm b/src/gui/dialogs/qprintdialog_mac.mm index a7587b1..56a065a 100644 --- a/src/gui/dialogs/qprintdialog_mac.mm +++ b/src/gui/dialogs/qprintdialog_mac.mm @@ -122,6 +122,8 @@ QT_END_NAMESPACE QT_USE_NAMESPACE +#ifdef QT_MAC_USE_COCOA + @class QCocoaPrintPanelDelegate; @interface QCocoaPrintPanelDelegate : NSObject { @@ -166,6 +168,12 @@ QT_USE_NAMESPACE } // Keep us in sync with file output PMDestinationType dest; + + // If the user selected print to file, the session has been + // changed behind our back and our d->ep->session object is a + // dangling pointer. Update it based on the "current" session + d->ep->session = static_cast<PMPrintSession>([d->ep->printInfo PMPrintSession]); + PMSessionGetDestinationType(d->ep->session, d->ep->settings, &dest); if (dest == kPMDestinationFile) { QCFType<CFURLRef> file; @@ -191,6 +199,8 @@ QT_USE_NAMESPACE } @end +#endif + QT_BEGIN_NAMESPACE extern void macStartInterceptWindowTitle(QWidget *window); diff --git a/src/gui/dialogs/qprintdialog_win.cpp b/src/gui/dialogs/qprintdialog_win.cpp index f66c27f..843c4e2 100644 --- a/src/gui/dialogs/qprintdialog_win.cpp +++ b/src/gui/dialogs/qprintdialog_win.cpp @@ -52,6 +52,13 @@ #include <private/qprintengine_win_p.h> #include <private/qprinter_p.h> +#if defined(Q_CC_MINGW) && !defined(PD_NOCURRENTPAGE) +#define PD_NOCURRENTPAGE 0x00800000 +#define PD_RESULT_PRINT 1 +#define PD_RESULT_APPLY 2 +#define START_PAGE_GENERAL 0XFFFFFFFF +#endif + QT_BEGIN_NAMESPACE extern void qt_win_eatMouseMove(); diff --git a/src/gui/dialogs/qprogressdialog.cpp b/src/gui/dialogs/qprogressdialog.cpp index 5fb10bf..f5024bb 100644 --- a/src/gui/dialogs/qprogressdialog.cpp +++ b/src/gui/dialogs/qprogressdialog.cpp @@ -453,7 +453,7 @@ void QProgressDialog::setCancelButton(QPushButton *cancelButton) cancelButton->show(); #else { - d->cancelAction = new QAction(cancelButton->text(), this); + d->cancelAction = new QAction(cancelButton->text(), cancelButton); d->cancelAction->setSoftKeyRole(QAction::NegativeSoftKey); connect(d->cancelAction, SIGNAL(triggered()), this, SIGNAL(canceled())); addAction(d->cancelAction); diff --git a/src/gui/dialogs/qwizard.cpp b/src/gui/dialogs/qwizard.cpp index 0f6d353..0102e25 100644 --- a/src/gui/dialogs/qwizard.cpp +++ b/src/gui/dialogs/qwizard.cpp @@ -1340,7 +1340,7 @@ bool QWizardPrivate::ensureButton(QWizard::WizardButton which) const pushButton->setText(buttonDefaultText(wizStyle, which, this)); #ifdef QT_SOFTKEYS_ENABLED - QAction *softKey = new QAction(pushButton->text(), antiFlickerWidget); + QAction *softKey = new QAction(pushButton->text(), pushButton); QAction::SoftKeyRole softKeyRole; switch(which) { case QWizard::NextButton: diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index e971fd8..ee01fdc 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -566,7 +566,7 @@ QGraphicsColorizeEffect::~QGraphicsColorizeEffect() \brief the color of the effect. By default, the color is light blue (QColor(0, 0, 192)). -*/; +*/ QColor QGraphicsColorizeEffect::color() const { Q_D(const QGraphicsColorizeEffect); diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp index 590b666..df1179a 100644 --- a/src/gui/egl/qegl_qws.cpp +++ b/src/gui/egl/qegl_qws.cpp @@ -83,7 +83,8 @@ static QScreen *screenForDevice(QPaintDevice *device) screenNumber = 0; screen = screen->subScreens()[screenNumber]; } - while (screen->classId() == QScreen::ProxyClass) { + while (screen->classId() == QScreen::ProxyClass || + screen->classId() == QScreen::TransformedClass) { screen = static_cast<QProxyScreen *>(screen)->screen(); } return screen; diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp index 02ae729..c61e1d3 100644 --- a/src/gui/egl/qeglproperties.cpp +++ b/src/gui/egl/qeglproperties.cpp @@ -313,7 +313,7 @@ QString QEglProperties::toString() const int alpha = value(EGL_ALPHA_SIZE); int bufferSize = value(EGL_BUFFER_SIZE); if (bufferSize == (red + green + blue + alpha)) - bufferSize = EGL_DONT_CARE; + bufferSize = 0; str += QLatin1String(" rgba="); str += QString::number(red); str += QLatin1Char(','); @@ -322,7 +322,7 @@ QString QEglProperties::toString() const str += QString::number(blue); str += QLatin1Char(','); str += QString::number(alpha); - if (bufferSize != EGL_DONT_CARE) { + if (bufferSize != 0) { // Only report buffer size if different than r+g+b+a. str += QLatin1String(" buffer-size="); str += QString::number(bufferSize); diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri index fa4dd68..84253b5 100644 --- a/src/gui/embedded/directfb.pri +++ b/src/gui/embedded/directfb.pri @@ -1,7 +1,7 @@ # These defines might be necessary if your DirectFB driver doesn't # support all of the DirectFB API. # -#DEFINES += QT_NO_DIRECTFB_SUBSURFACE +#DEFINES += QT_DIRECTFB_SUBSURFACE #DEFINES += QT_DIRECTFB_WINDOW_AS_CURSOR #DEFINES += QT_NO_DIRECTFB_IMAGEPROVIDER #DEFINES += QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index f75118b..f9b5c8c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -92,87 +92,118 @@ qreal QGraphicsAnchorPrivate::spacing() const } +static void sizeHintsFromItem(QGraphicsLayoutItem *item, + const QGraphicsAnchorLayoutPrivate::Orientation orient, + qreal *minSize, qreal *prefSize, + qreal *expSize, qreal *maxSize) +{ + QSizePolicy::Policy policy; + qreal minSizeHint; + qreal prefSizeHint; + qreal maxSizeHint; + + if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) { + policy = item->sizePolicy().horizontalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); + } else { + policy = item->sizePolicy().verticalPolicy(); + minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); + prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); + maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); + } + + // minSize, prefSize and maxSize are initialized + // with item's preferred Size: this is QSizePolicy::Fixed. + // + // Then we check each flag to find the resultant QSizePolicy, + // according to the following table: + // + // constant value + // QSizePolicy::Fixed 0 + // QSizePolicy::Minimum GrowFlag + // QSizePolicy::Maximum ShrinkFlag + // QSizePolicy::Preferred GrowFlag | ShrinkFlag + // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag + + if (policy & QSizePolicy::ShrinkFlag) + *minSize = minSizeHint; + else + *minSize = prefSizeHint; + + if (policy & QSizePolicy::GrowFlag) + *maxSize = maxSizeHint; + else + *maxSize = prefSizeHint; + + // Note that these two initializations are affected by the previous flags + if (policy & QSizePolicy::IgnoreFlag) + *prefSize = *maxSize; + else + *prefSize = prefSizeHint; + + if (policy & QSizePolicy::ExpandFlag) + *expSize = *maxSize; + else + *expSize = *prefSize; +} + void AnchorData::refreshSizeHints(qreal effectiveSpacing) { - if (!isLayoutAnchor && from->m_item == to->m_item) { - QGraphicsLayoutItem *item = from->m_item; + const bool isInternalAnchor = from->m_item == to->m_item; - const QGraphicsAnchorLayoutPrivate::Orientation orient = QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); - const Qt::AnchorPoint centerEdge = QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient); + if (isInternalAnchor) { + const QGraphicsAnchorLayoutPrivate::Orientation orient = + QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge); - QSizePolicy::Policy policy; - qreal minSizeHint, prefSizeHint, maxSizeHint; - if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) { - policy = item->sizePolicy().horizontalPolicy(); - minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width(); - prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width(); - maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width(); + if (isLayoutAnchor) { + minSize = 0; + prefSize = 0; + expSize = 0; + maxSize = QWIDGETSIZE_MAX; } else { - policy = item->sizePolicy().verticalPolicy(); - minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height(); - prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height(); - maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height(); + QGraphicsLayoutItem *item = from->m_item; + sizeHintsFromItem(item, orient, &minSize, &prefSize, &expSize, &maxSize); } - // minSize, prefSize and maxSize are initialized - // with item's preferred Size: this is QSizePolicy::Fixed. - // - // Then we check each flag to find the resultant QSizePolicy, - // according to the following table: - // - // constant value - // QSizePolicy::Fixed 0 - // QSizePolicy::Minimum GrowFlag - // QSizePolicy::Maximum ShrinkFlag - // QSizePolicy::Preferred GrowFlag | ShrinkFlag - // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag - prefSize = prefSizeHint; - minSize = prefSize; - maxSize = prefSize; - - if (policy & QSizePolicy::GrowFlag) - maxSize = maxSizeHint; - - if (policy & QSizePolicy::ShrinkFlag) - minSize = minSizeHint; - - if (policy & QSizePolicy::IgnoreFlag) - prefSize = minSize; + const Qt::AnchorPoint centerEdge = + QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient); bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge); if (hasCenter) { minSize /= 2; prefSize /= 2; + expSize /= 2; maxSize /= 2; } - // Set the anchor effective sizes to preferred. - // - // Note: The idea here is that all items should remain at their - // preferred size unless where that's impossible. In cases where - // the item is subject to restrictions (anchored to the layout - // edges, for instance), the simplex solver will be run to - // recalculate and override the values we set here. - sizeAtMinimum = prefSize; - sizeAtPreferred = prefSize; - sizeAtMaximum = prefSize; - } else if (!hasSize) { // Anchor has no size defined, use given default information minSize = effectiveSpacing; prefSize = effectiveSpacing; + expSize = effectiveSpacing; maxSize = effectiveSpacing; - - sizeAtMinimum = prefSize; - sizeAtPreferred = prefSize; - sizeAtMaximum = prefSize; } + + // Set the anchor effective sizes to preferred. + // + // Note: The idea here is that all items should remain at their + // preferred size unless where that's impossible. In cases where + // the item is subject to restrictions (anchored to the layout + // edges, for instance), the simplex solver will be run to + // recalculate and override the values we set here. + sizeAtMinimum = prefSize; + sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; + sizeAtMaximum = prefSize; } void ParallelAnchorData::updateChildrenSizes() { firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum; firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred; + firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtExpanding; firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum; firstEdge->updateChildrenSizes(); @@ -181,9 +212,16 @@ void ParallelAnchorData::updateChildrenSizes() void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing) { - // First refresh children information - firstEdge->refreshSizeHints(effectiveSpacing); - secondEdge->refreshSizeHints(effectiveSpacing); + refreshSizeHints_helper(effectiveSpacing); +} + +void ParallelAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, + bool refreshChildren) +{ + if (refreshChildren) { + firstEdge->refreshSizeHints(effectiveSpacing); + secondEdge->refreshSizeHints(effectiveSpacing); + } // ### should we warn if the parallel connection is invalid? // e.g. 1-2-3 with 10-20-30, the minimum of the latter is @@ -192,12 +230,16 @@ void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing) minSize = qMax(firstEdge->minSize, secondEdge->minSize); maxSize = qMin(firstEdge->maxSize, secondEdge->maxSize); + expSize = qMax(firstEdge->expSize, secondEdge->expSize); + expSize = qMin(expSize, maxSize); + prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize); - prefSize = qMin(prefSize, maxSize); + prefSize = qMin(prefSize, expSize); // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } @@ -233,6 +275,21 @@ static qreal getFactor(qreal value, qreal min, qreal pref, qreal max) } } +static qreal getExpandingFactor(const qreal &expSize, const qreal &sizeAtPreferred, + const qreal &sizeAtExpanding, const qreal &sizeAtMaximum) +{ + const qreal lower = qMin(sizeAtPreferred, sizeAtMaximum); + const qreal upper = qMax(sizeAtPreferred, sizeAtMaximum); + const qreal boundedExpSize = qBound(lower, expSize, upper); + + const qreal bandSize = sizeAtMaximum - boundedExpSize; + if (bandSize == 0) { + return 0; + } else { + return (sizeAtExpanding - boundedExpSize) / bandSize; + } +} + void SequentialAnchorData::updateChildrenSizes() { // ### REMOVE ME @@ -242,15 +299,18 @@ void SequentialAnchorData::updateChildrenSizes() Q_ASSERT(sizeAtMinimum < maxSize || qFuzzyCompare(sizeAtMinimum, maxSize)); Q_ASSERT(sizeAtPreferred > minSize || qFuzzyCompare(sizeAtPreferred, minSize)); Q_ASSERT(sizeAtPreferred < maxSize || qFuzzyCompare(sizeAtPreferred, maxSize)); + Q_ASSERT(sizeAtExpanding > minSize || qFuzzyCompare(sizeAtExpanding, minSize)); + Q_ASSERT(sizeAtExpanding < maxSize || qFuzzyCompare(sizeAtExpanding, maxSize)); Q_ASSERT(sizeAtMaximum > minSize || qFuzzyCompare(sizeAtMaximum, minSize)); Q_ASSERT(sizeAtMaximum < maxSize || qFuzzyCompare(sizeAtMaximum, maxSize)); // Band here refers if the value is in the Minimum To Preferred // band (the lower band) or the Preferred To Maximum (the upper band). - qreal minFactor = getFactor(sizeAtMinimum, minSize, prefSize, maxSize); - qreal prefFactor = getFactor(sizeAtPreferred, minSize, prefSize, maxSize); - qreal maxFactor = getFactor(sizeAtMaximum, minSize, prefSize, maxSize); + const qreal minFactor = getFactor(sizeAtMinimum, minSize, prefSize, maxSize); + const qreal prefFactor = getFactor(sizeAtPreferred, minSize, prefSize, maxSize); + const qreal maxFactor = getFactor(sizeAtMaximum, minSize, prefSize, maxSize); + const qreal expFactor = getExpandingFactor(expSize, sizeAtPreferred, sizeAtExpanding, sizeAtMaximum); for (int i = 0; i < m_edges.count(); ++i) { AnchorData *e = m_edges.at(i); @@ -264,30 +324,45 @@ void SequentialAnchorData::updateChildrenSizes() bandSize = maxFactor > 0 ? e->maxSize - e->prefSize : e->prefSize - e->minSize; e->sizeAtMaximum = e->prefSize + bandSize * maxFactor; + const qreal lower = qMin(e->sizeAtPreferred, e->sizeAtMaximum); + const qreal upper = qMax(e->sizeAtPreferred, e->sizeAtMaximum); + const qreal edgeBoundedExpSize = qBound(lower, e->expSize, upper); + e->sizeAtExpanding = edgeBoundedExpSize + expFactor * (e->sizeAtMaximum - edgeBoundedExpSize); + e->updateChildrenSizes(); } } void SequentialAnchorData::refreshSizeHints(qreal effectiveSpacing) { + refreshSizeHints_helper(effectiveSpacing); +} + +void SequentialAnchorData::refreshSizeHints_helper(qreal effectiveSpacing, + bool refreshChildren) +{ minSize = 0; prefSize = 0; + expSize = 0; maxSize = 0; for (int i = 0; i < m_edges.count(); ++i) { AnchorData *edge = m_edges.at(i); - // First refresh children information - edge->refreshSizeHints(effectiveSpacing); + // If it's the case refresh children information first + if (refreshChildren) + edge->refreshSizeHints(effectiveSpacing); minSize += edge->minSize; prefSize += edge->prefSize; + expSize += edge->expSize; maxSize += edge->maxSize; } // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; + sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; } @@ -357,6 +432,12 @@ QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate() : calculateGraphCacheDirty(1) { for (int i = 0; i < NOrientations; ++i) { + for (int j = 0; j < 3; ++j) { + sizeHints[i][j] = -1; + } + sizeAtExpanding[i] = -1; + interpolationProgress[i] = -1; + spacings[i] = -1; graphSimplified[i] = false; graphHasConflicts[i] = false; @@ -422,39 +503,21 @@ static bool simplifySequentialChunk(Graph<AnchorVertex, AnchorData> *graph, qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString())); #endif - qreal min = 0; - qreal pref = 0; - qreal max = 0; - SequentialAnchorData *sequence = new SequentialAnchorData; AnchorVertex *prev = before; AnchorData *data; for (i = 0; i <= vertices.count(); ++i) { AnchorVertex *next = (i < vertices.count()) ? vertices.at(i) : after; data = graph->takeEdge(prev, next); - min += data->minSize; - pref += data->prefSize; - max = checkAdd(max, data->maxSize); sequence->m_edges.append(data); prev = next; } - - // insert new - sequence->minSize = min; - sequence->prefSize = pref; - sequence->maxSize = max; - - // Unless these values are overhidden by the simplex solver later-on, - // anchors will keep their own preferred size. - sequence->sizeAtMinimum = pref; - sequence->sizeAtPreferred = pref; - sequence->sizeAtMaximum = pref; - sequence->setVertices(vertices); - sequence->from = before; sequence->to = after; + sequence->refreshSizeHints_helper(0, false); + // data here is the last edge in the sequence // ### this seems to be here for supporting reverse order sequences, // but doesnt seem to be used right now @@ -469,25 +532,11 @@ static bool simplifySequentialChunk(Graph<AnchorVertex, AnchorData> *graph, AnchorData *newAnchor = sequence; if (AnchorData *oldAnchor = graph->takeEdge(before, after)) { - newAnchor = new ParallelAnchorData(oldAnchor, sequence); - - newAnchor->isLayoutAnchor = (oldAnchor->isLayoutAnchor + ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, sequence); + parallel->isLayoutAnchor = (oldAnchor->isLayoutAnchor || sequence->isLayoutAnchor); - - min = qMax(oldAnchor->minSize, sequence->minSize); - max = qMin(oldAnchor->maxSize, sequence->maxSize); - - pref = qMax(oldAnchor->prefSize, sequence->prefSize); - pref = qMin(pref, max); - - newAnchor->minSize = min; - newAnchor->prefSize = pref; - newAnchor->maxSize = max; - - // Same as above, by default, keep preferred size. - newAnchor->sizeAtMinimum = pref; - newAnchor->sizeAtPreferred = pref; - newAnchor->sizeAtMaximum = pref; + parallel->refreshSizeHints_helper(0, false); + newAnchor = parallel; } graph->createEdge(before, after, newAnchor); @@ -817,9 +866,10 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() QGraphicsLayoutItem *layout = q; // Horizontal - AnchorData *data = new AnchorData(0, 0, QWIDGETSIZE_MAX); + AnchorData *data = new AnchorData; addAnchor_helper(layout, Qt::AnchorLeft, layout, - Qt::AnchorRight, data); + Qt::AnchorRight, data); + data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; // Set the Layout Left edge as the root of the horizontal graph. @@ -827,9 +877,10 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() graph[Horizontal].setRootVertex(v); // Vertical - data = new AnchorData(0, 0, QWIDGETSIZE_MAX); + data = new AnchorData; addAnchor_helper(layout, Qt::AnchorTop, layout, - Qt::AnchorBottom, data); + Qt::AnchorBottom, data); + data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; // Set the Layout Top edge as the root of the vertical graph. @@ -856,19 +907,15 @@ void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) items.append(item); - QSizeF minSize = item->effectiveSizeHint(Qt::MinimumSize); - QSizeF prefSize = item->effectiveSizeHint(Qt::PreferredSize); - QSizeF maxSize = item->effectiveSizeHint(Qt::MaximumSize); - - // Horizontal - AnchorData *data = new AnchorData(minSize.width(), prefSize.width(), maxSize.width()); - addAnchor_helper(item, Qt::AnchorLeft, item, - Qt::AnchorRight, data); + // Create horizontal and vertical internal anchors for the item and + // refresh its size hint / policy values. + AnchorData *data = new AnchorData; + addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data); + data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used - // Vertical - data = new AnchorData(minSize.height(), prefSize.height(), maxSize.height()); - addAnchor_helper(item, Qt::AnchorTop, item, - Qt::AnchorBottom, data); + data = new AnchorData; + addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data); + data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used } /*! @@ -921,20 +968,17 @@ void QGraphicsAnchorLayoutPrivate::createCenterAnchors( Q_ASSERT(first && last); // Create new anchors - AnchorData *oldData = graph[orientation].edgeData(first, last); - - qreal minimumSize = oldData->minSize / 2; - qreal preferredSize = oldData->prefSize / 2; - qreal maximumSize = oldData->maxSize / 2; - QSimplexConstraint *c = new QSimplexConstraint; - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); + + AnchorData *data = new AnchorData; c->variables.insert(data, 1.0); addAnchor_helper(item, firstEdge, item, centerEdge, data); + data->refreshSizeHints(0); - data = new AnchorData(minimumSize, preferredSize, maximumSize); + data = new AnchorData; c->variables.insert(data, -1.0); addAnchor_helper(item, centerEdge, item, lastEdge, data); + data->refreshSizeHints(0); itemCenterConstraints[orientation].append(c); @@ -995,14 +1039,9 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( if (substitute) { // Create the new anchor that should substitute the left-center-right anchors. - AnchorData *oldData = g.edgeData(first, center); - - qreal minimumSize = oldData->minSize * 2; - qreal preferredSize = oldData->prefSize * 2; - qreal maximumSize = oldData->maxSize * 2; - - AnchorData *data = new AnchorData(minimumSize, preferredSize, maximumSize); + AnchorData *data = new AnchorData; addAnchor_helper(item, firstEdge, item, lastEdge, data); + data->refreshSizeHints(0); // Remove old anchors removeAnchor_helper(first, center); @@ -1120,7 +1159,7 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi // Use heuristics to find out what the user meant with this anchor. correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge); - AnchorData *data; + AnchorData *data = new AnchorData; if (!spacing) { // If firstItem or secondItem is the layout itself, the spacing will default to 0. // Otherwise, the following matrix is used (questionmark means that the spacing @@ -1130,22 +1169,25 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi // Left 0 0 ? // HCenter 0 0 0 // Right ? 0 0 - if (firstItem != q - && secondItem != q - && pickEdge(firstEdge, Horizontal) != Qt::AnchorHorizontalCenter - && oppositeEdge(firstEdge) == secondEdge) { - data = new AnchorData; // ask the style later + if (firstItem == q + || secondItem == q + || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter + || oppositeEdge(firstEdge) != secondEdge) { + data->setFixedSize(0); } else { - data = new AnchorData(0); // spacing should be 0 + data->unsetSize(); } addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); + } else if (*spacing >= 0) { - data = new AnchorData(*spacing); + data->setFixedSize(*spacing); addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data); + } else { - data = new AnchorData(-*spacing); + data->setFixedSize(-*spacing); addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data); } + return acquireGraphicsAnchor(data); } @@ -1622,11 +1664,18 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( qreal min, max; feasible = solveMinMax(trunkConstraints, trunkPath, &min, &max); - // Solve for preferred. The objective function is calculated from the constraints - // and variables internally. - feasible &= solvePreferred(trunkConstraints); - if (feasible) { + // Solve for preferred. The objective function is calculated from the constraints + // and variables internally. + solvePreferred(trunkConstraints); + + // remove sizeHintConstraints from trunkConstraints + trunkConstraints = parts[0]; + + // Solve for expanding. The objective function and the constraints from items + // are calculated internally. + solveExpanding(trunkConstraints); + // Propagate the new sizes down the simplified graph, ie. tell the // group anchors to set their children anchors sizes. @@ -1636,19 +1685,23 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( for (int i = 0; i < trunkVariables.count(); ++i) trunkVariables.at(i)->updateChildrenSizes(); - // Calculate and set the preferred size for the layout from the edge sizes that - // were calculated above. + // Calculate and set the preferred and expanding sizes for the layout, + // from the edge sizes that were calculated above. qreal pref(0.0); + qreal expanding(0.0); foreach (const AnchorData *ad, trunkPath.positives) { pref += ad->sizeAtPreferred; + expanding += ad->sizeAtExpanding; } foreach (const AnchorData *ad, trunkPath.negatives) { pref -= ad->sizeAtPreferred; + expanding -= ad->sizeAtExpanding; } + sizeHints[orientation][Qt::MinimumSize] = min; sizeHints[orientation][Qt::PreferredSize] = pref; sizeHints[orientation][Qt::MaximumSize] = max; - + sizeAtExpanding[orientation] = expanding; } } else { #if 0 @@ -1664,6 +1717,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorData *ad = trunkPath.positives.toList()[0]; ad->sizeAtMinimum = ad->minSize; ad->sizeAtPreferred = ad->prefSize; + ad->sizeAtExpanding = ad->expSize; ad->sizeAtMaximum = ad->maxSize; // Propagate @@ -1672,6 +1726,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum; sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred; sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum; + sizeAtExpanding[orientation] = ad->sizeAtExpanding; } // Delete the constraints, we won't use them anymore. @@ -1701,6 +1756,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( AnchorData *ad = partVariables[j]; Q_ASSERT(ad); ad->sizeAtMinimum = ad->sizeAtPreferred; + ad->sizeAtExpanding = ad->sizeAtPreferred; ad->sizeAtMaximum = ad->sizeAtPreferred; ad->updateChildrenSizes(); } @@ -1785,6 +1841,11 @@ void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation) queue.enqueue(qMakePair(pair.second, v)); } } + + // We will walk through every reachable items (non-float) store them in a temporary set. + // We them create a set of all items and subtract the non-floating items from the set in + // order to get the floating items. The floating items is then stored in m_floatItems + identifyFloatItems(visited, orientation); } /*! @@ -1943,6 +2004,52 @@ QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) } /*! + \internal + + Use all visited Anchors on findPaths() so we can identify non-float Items. +*/ +void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation) +{ + QSet<QGraphicsLayoutItem *> nonFloating; + + foreach (const AnchorData *ad, visited) + identifyNonFloatItems_helper(ad, &nonFloating); + + QSet<QGraphicsLayoutItem *> allItems; + foreach (QGraphicsLayoutItem *item, items) + allItems.insert(item); + m_floatItems[orientation] = allItems - nonFloating; +} + + +/*! + \internal + + Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float. + If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach + internal anchors (items). +*/ +void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar) +{ + Q_Q(QGraphicsAnchorLayout); + + switch(ad->type) { + case AnchorData::Normal: + if (ad->from->m_item == ad->to->m_item && ad->to->m_item != q) + nonFloatingItemsIdentifiedSoFar->insert(ad->to->m_item); + break; + case AnchorData::Sequential: + foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges) + identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar); + break; + case AnchorData::Parallel: + identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar); + identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar); + break; + } +} + +/*! \internal Use the current vertices distance to calculate and set the geometry of @@ -1967,22 +2074,35 @@ void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) right = geom.right() - right; foreach (QGraphicsLayoutItem *item, items) { - firstH = internalVertex(item, Qt::AnchorLeft); - secondH = internalVertex(item, Qt::AnchorRight); - firstV = internalVertex(item, Qt::AnchorTop); - secondV = internalVertex(item, Qt::AnchorBottom); - QRectF newGeom; - newGeom.setTop(top + firstV->distance); - newGeom.setBottom(top + secondV->distance); + QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize); + if (m_floatItems[Horizontal].contains(item)) { + newGeom.setLeft(0); + newGeom.setRight(itemPreferredSize.width()); + } else { + firstH = internalVertex(item, Qt::AnchorLeft); + secondH = internalVertex(item, Qt::AnchorRight); + + if (visualDir == Qt::LeftToRight) { + newGeom.setLeft(left + firstH->distance); + newGeom.setRight(left + secondH->distance); + } else { + newGeom.setLeft(right - secondH->distance); + newGeom.setRight(right - firstH->distance); + } + } - if (visualDir == Qt::LeftToRight) { - newGeom.setLeft(left + firstH->distance); - newGeom.setRight(left + secondH->distance); + if (m_floatItems[Vertical].contains(item)) { + newGeom.setTop(0); + newGeom.setBottom(itemPreferredSize.height()); } else { - newGeom.setLeft(right - secondH->distance); - newGeom.setRight(right - firstH->distance); + firstV = internalVertex(item, Qt::AnchorTop); + secondV = internalVertex(item, Qt::AnchorBottom); + + newGeom.setTop(top + firstV->distance); + newGeom.setBottom(top + secondV->distance); } + item->setGeometry(newGeom); } } @@ -2058,9 +2178,13 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( interpolationInterval[orientation] = MinToPreferred; lower = sizeHints[orientation][Qt::MinimumSize]; upper = sizeHints[orientation][Qt::PreferredSize]; - } else { - interpolationInterval[orientation] = PreferredToMax; + } else if (current < sizeAtExpanding[orientation]) { + interpolationInterval[orientation] = PreferredToExpanding; lower = sizeHints[orientation][Qt::PreferredSize]; + upper = sizeAtExpanding[orientation]; + } else { + interpolationInterval[orientation] = ExpandingToMax; + lower = sizeAtExpanding[orientation]; upper = sizeHints[orientation][Qt::MaximumSize]; } @@ -2075,11 +2199,12 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( \internal Calculate the current Edge size based on the current Layout size and the - size the edge is supposed to have when: + size the edge is supposed to have when the layout is at its: - - the layout is at its minimum size. - - the layout is at its preferred size. - - the layout is at its maximum size. + - minimum size, + - preferred size, + - size when all expanding anchors are expanded, + - maximum size. These three key values are calculated in advance using linear programming (more expensive) or the simplification algorithm, then @@ -2099,8 +2224,11 @@ void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, if (interpolationInterval[orientation] == MinToPreferred) { lower = edge->sizeAtMinimum; upper = edge->sizeAtPreferred; - } else { + } else if (interpolationInterval[orientation] == PreferredToExpanding) { lower = edge->sizeAtPreferred; + upper = edge->sizeAtExpanding; + } else { + lower = edge->sizeAtExpanding; upper = edge->sizeAtMaximum; } @@ -2289,6 +2417,139 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(QList<QSimplexConstraint *> co /*! \internal + Calculate the "expanding" keyframe + + This new keyframe sits between the already existing sizeAtPreferred and + sizeAtMaximum keyframes. Its goal is to modify the interpolation between + the latter as to respect the "expanding" size policy of some anchors. + + Previously all items would be subject to a linear interpolation between + sizeAtPreferred and sizeAtMaximum values. This will change now, the + expanding anchors will change their size before the others. To calculate + this keyframe we use the following logic: + + 1) Ask each anchor for their desired expanding size (ad->expSize), this + value depends on the anchor expanding property in the following way: + + - Expanding normal anchors want to grow towards their maximum size + - Non-expanding normal anchors want to remain at their preferred size. + - Sequential anchors wants to grow towards a size that is calculated by: + summarizing it's child anchors, where it will use preferred size for non-expanding anchors + and maximum size for expanding anchors. + - Parallel anchors want to grow towards the smallest maximum size of all the expanding anchors. + + 2) Clamp their desired values to the value they assume in the neighbour + keyframes (sizeAtPreferred and sizeAtExpanding) + + 3) Run simplex with a setup that ensures the following: + + a. Anchors will change their value from their sizeAtPreferred towards + their sizeAtMaximum as much as required to ensure that ALL anchors + reach their respective "desired" expanding sizes. + + b. No anchors will change their value beyond what is NEEDED to satisfy + the requirement above. + + The final result is that, at the "expanding" keyframe expanding anchors + will grow and take with them all anchors that are parallel to them. + However, non-expanding anchors will remain at their preferred size unless + they are forced to grow by a parallel expanding anchor. + + Note: For anchors where the sizeAtPreferred is bigger than sizeAtMaximum, + the visual effect when the layout grows from its preferred size is + the following: Expanding anchors will keep their size while non + expanding ones will shrink. Only after non-expanding anchors have + shrinked all the way, the expanding anchors will start to shrink too. +*/ +void QGraphicsAnchorLayoutPrivate::solveExpanding(QList<QSimplexConstraint *> constraints) +{ + QList<AnchorData *> variables = getVariables(constraints); + QList<QSimplexConstraint *> itemConstraints; + QSimplexConstraint *objective = new QSimplexConstraint; + bool hasExpanding = false; + + // Construct the simplex constraints and objective + for (int i = 0; i < variables.size(); ++i) { + // For each anchor + AnchorData *ad = variables[i]; + + // Clamp the desired expanding size + qreal upperBoundary = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum); + qreal lowerBoundary = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum); + qreal boundedExpSize = qBound(lowerBoundary, ad->expSize, upperBoundary); + + // Expanding anchors are those that want to move from their preferred size + if (boundedExpSize != ad->sizeAtPreferred) + hasExpanding = true; + + // Lock anchor between boundedExpSize and sizeAtMaximum (ensure 3.a) + if (boundedExpSize == ad->sizeAtMaximum) { + // The interval has only one possible value, we can use an "Equal" + // constraint and don't need to add this variable to the objective. + QSimplexConstraint *itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::Equal; + itemC->variables.insert(ad, 1.0); + itemC->constant = boundedExpSize; + itemConstraints << itemC; + } else { + // Add MoreOrEqual and LessOrEqual constraints. + QSimplexConstraint *itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::MoreOrEqual; + itemC->variables.insert(ad, 1.0); + itemC->constant = qMin(boundedExpSize, ad->sizeAtMaximum); + itemConstraints << itemC; + + itemC = new QSimplexConstraint; + itemC->ratio = QSimplexConstraint::LessOrEqual; + itemC->variables.insert(ad, 1.0); + itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum); + itemConstraints << itemC; + + // Create objective to avoid the anchors from moving away from + // the preferred size more than the needed amount. (ensure 3.b) + // The objective function is the distance between sizeAtPreferred + // and sizeAtExpanding, it will be minimized. + if (ad->sizeAtExpanding < ad->sizeAtMaximum) { + // Try to shrink this variable towards its sizeAtPreferred value + objective->variables.insert(ad, 1.0); + } else { + // Try to grow this variable towards its sizeAtPreferred value + objective->variables.insert(ad, -1.0); + } + } + } + + // Solve + if (hasExpanding == false) { + // If no anchors are expanding, we don't need to run the simplex + // Set all variables to their preferred size + for (int i = 0; i < variables.size(); ++i) { + variables[i]->sizeAtExpanding = variables[i]->sizeAtPreferred; + } + } else { + // Run simplex + QSimplex simplex; + + // Satisfy expanding (3.a) + bool feasible = simplex.setConstraints(constraints + itemConstraints); + Q_ASSERT(feasible); + + // Reduce damage (3.b) + simplex.setObjective(objective); + simplex.solveMin(); + + // Collect results + for (int i = 0; i < variables.size(); ++i) { + variables[i]->sizeAtExpanding = variables[i]->result; + } + } + + delete objective; + qDeleteAll(itemConstraints); +} + +/*! + \internal Returns true if there are no arrangement that satisfies all constraints. Otherwise returns false. @@ -2298,7 +2559,10 @@ bool QGraphicsAnchorLayoutPrivate::hasConflicts() const { QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this); that->calculateGraphs(); - return graphHasConflicts[0] || graphHasConflicts[1]; + + bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty(); + + return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict; } #ifdef QT_DEBUG diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index c86bfa3..9ac0e19 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -149,30 +149,14 @@ struct AnchorData : public QSimplexVariable { Sequential, Parallel }; - AnchorData(qreal minimumSize, qreal preferredSize, qreal maximumSize) - : QSimplexVariable(), from(0), to(0), - minSize(minimumSize), prefSize(preferredSize), - maxSize(maximumSize), sizeAtMinimum(preferredSize), - sizeAtPreferred(preferredSize), sizeAtMaximum(preferredSize), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(true), - isLayoutAnchor(false) {} - - AnchorData(qreal size) - : QSimplexVariable(), from(0), to(0), - minSize(size), prefSize(size), maxSize(size), - sizeAtMinimum(size), sizeAtPreferred(size), sizeAtMaximum(size), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(true), - isLayoutAnchor(false) {} AnchorData() : QSimplexVariable(), from(0), to(0), - minSize(0), prefSize(0), maxSize(0), - sizeAtMinimum(0), sizeAtPreferred(0), sizeAtMaximum(0), - graphicsAnchor(0), - skipInPreferred(0), type(Normal), hasSize(false), - isLayoutAnchor(false) {} + minSize(0), prefSize(0), expSize(0), maxSize(0), + sizeAtMinimum(0), sizeAtPreferred(0), + sizeAtExpanding(0), sizeAtMaximum(0), + graphicsAnchor(0), skipInPreferred(0), + type(Normal), hasSize(true), isLayoutAnchor(false) {} virtual void updateChildrenSizes() {} virtual void refreshSizeHints(qreal effectiveSpacing); @@ -189,9 +173,11 @@ struct AnchorData : public QSimplexVariable { { minSize = size; prefSize = size; + expSize = size; maxSize = size; sizeAtMinimum = size; sizeAtPreferred = size; + sizeAtExpanding = size; sizeAtMaximum = size; hasSize = true; } @@ -211,6 +197,7 @@ struct AnchorData : public QSimplexVariable { // size. qreal minSize; qreal prefSize; + qreal expSize; qreal maxSize; // These attributes define which sizes should that anchor be in when the @@ -218,6 +205,7 @@ struct AnchorData : public QSimplexVariable { // calculated by the Simplex solver based on the current layout setup. qreal sizeAtMinimum; qreal sizeAtPreferred; + qreal sizeAtExpanding; qreal sizeAtMaximum; QGraphicsAnchor *graphicsAnchor; @@ -225,15 +213,6 @@ struct AnchorData : public QSimplexVariable { uint type : 2; // either Normal, Sequential or Parallel uint hasSize : 1; // if false, get size from style. uint isLayoutAnchor : 1; // if this anchor is connected to a layout 'edge' -protected: - AnchorData(Type type, qreal size = 0) - : QSimplexVariable(), from(0), to(0), - minSize(size), prefSize(size), - maxSize(size), sizeAtMinimum(size), - sizeAtPreferred(size), sizeAtMaximum(size), - graphicsAnchor(0), - skipInPreferred(0), type(type), hasSize(true), - isLayoutAnchor(false) {} }; #ifdef QT_DEBUG @@ -245,8 +224,9 @@ inline QString AnchorData::toString() const struct SequentialAnchorData : public AnchorData { - SequentialAnchorData() : AnchorData(AnchorData::Sequential) + SequentialAnchorData() : AnchorData() { + type = AnchorData::Sequential; #ifdef QT_DEBUG name = QLatin1String("SequentialAnchorData"); #endif @@ -255,6 +235,8 @@ struct SequentialAnchorData : public AnchorData virtual void updateChildrenSizes(); virtual void refreshSizeHints(qreal effectiveSpacing); + void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true); + void setVertices(const QVector<AnchorVertex*> &vertices) { m_children = vertices; @@ -270,9 +252,10 @@ struct SequentialAnchorData : public AnchorData struct ParallelAnchorData : public AnchorData { ParallelAnchorData(AnchorData *first, AnchorData *second) - : AnchorData(AnchorData::Parallel), - firstEdge(first), secondEdge(second) + : AnchorData(), firstEdge(first), secondEdge(second) { + type = AnchorData::Parallel; + // ### Those asserts force that both child anchors have the same direction, // but can't we simplify a pair of anchors in opposite directions? Q_ASSERT(first->from == second->from); @@ -287,6 +270,8 @@ struct ParallelAnchorData : public AnchorData virtual void updateChildrenSizes(); virtual void refreshSizeHints(qreal effectiveSpacing); + void refreshSizeHints_helper(qreal effectiveSpacing, bool refreshChildren = true); + AnchorData* firstEdge; AnchorData* secondEdge; }; @@ -355,7 +340,8 @@ public: // Interval represents which interpolation interval are we operating in. enum Interval { MinToPreferred = 0, - PreferredToMax + PreferredToExpanding, + ExpandingToMax }; // Several structures internal to the layout are duplicated to handle @@ -457,6 +443,8 @@ public: void constraintsFromPaths(Orientation orientation); QList<QSimplexConstraint *> constraintsFromSizeHints(const QList<AnchorData *> &anchors); QList<QList<QSimplexConstraint *> > getGraphParts(Orientation orientation); + void identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation); + void identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar); inline AnchorVertex *internalVertex(const QPair<QGraphicsLayoutItem*, Qt::AnchorPoint> &itemEdge) const { @@ -486,6 +474,7 @@ public: bool solveMinMax(QList<QSimplexConstraint *> constraints, GraphPath path, qreal *min, qreal *max); bool solvePreferred(QList<QSimplexConstraint *> constraints); + void solveExpanding(QList<QSimplexConstraint *> constraints); bool hasConflicts() const; #ifdef QT_DEBUG @@ -496,6 +485,7 @@ public: qreal spacings[NOrientations]; // Size hints from simplex engine qreal sizeHints[2][3]; + qreal sizeAtExpanding[2]; // Items QVector<QGraphicsLayoutItem *> items; @@ -521,6 +511,7 @@ public: // ### bool graphSimplified[2]; bool graphHasConflicts[2]; + QSet<QGraphicsLayoutItem *> m_floatItems[2]; uint calculateGraphCacheDirty : 1; }; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index d766acc..c914402 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -663,6 +663,8 @@ #include <private/qpixmap_x11_p.h> #endif +#include <private/qgesturemanager_p.h> + #include <math.h> QT_BEGIN_NAMESPACE @@ -7296,6 +7298,19 @@ QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent } /*! + Subscribes the graphics object to the given \a gesture for the specified \a context. + + \sa QGestureEvent +*/ + +void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureContext context) +{ + QGraphicsItemPrivate * const d = QGraphicsItem::d_func(); + d->gestureContext.insert(gesture, context); + (void)QGestureManager::instance(); // create a gesture manager +} + +/*! \property QGraphicsObject::parent \brief the parent of the item diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index e6e324a..2665235 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -464,6 +464,7 @@ private: friend class QGraphicsSceneBspTree; friend class QGraphicsView; friend class QGraphicsViewPrivate; + friend class QGraphicsObject; friend class QGraphicsWidget; friend class QGraphicsWidgetPrivate; friend class QGraphicsProxyWidgetPrivate; @@ -473,6 +474,7 @@ private: friend class QGraphicsSceneBspTreeIndexPrivate; friend class QGraphicsItemEffectSourcePrivate; friend class QGraphicsTransformPrivate; + friend class QGestureManager; friend class ::tst_QGraphicsItem; friend bool qt_closestLeaf(const QGraphicsItem *, const QGraphicsItem *); friend bool qt_closestItemFirst(const QGraphicsItem *, const QGraphicsItem *); @@ -553,6 +555,8 @@ public: using QObject::children; #endif + void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture); + Q_SIGNALS: void parentChanged(); void opacityChanged(); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 51bfea1..6550362 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -450,6 +450,7 @@ public: QGraphicsItem *focusScopeItem; Qt::InputMethodHints imHints; QGraphicsItem::PanelModality panelModality; + QMap<Qt::GestureType, Qt::GestureContext> gestureContext; // Packed 32 bits quint32 acceptedMouseButtons : 5; diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp index 15b9ff3..b7a3962 100644 --- a/src/gui/graphicsview/qgraphicsproxywidget.cpp +++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp @@ -973,7 +973,7 @@ void QGraphicsProxyWidget::hideEvent(QHideEvent *event) void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { Q_D(QGraphicsProxyWidget); - if (!event || !d->widget || !d->widget->isVisible()) + if (!event || !d->widget || !d->widget->isVisible() || !hasFocus()) return; // Find widget position and receiver. diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 961f44f..a624b10 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -420,8 +420,12 @@ void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item) */ void QGraphicsScenePrivate::_q_polishItems() { + QSet<QGraphicsItem *>::Iterator it; const QVariant booleanTrueVariant(true); - foreach (QGraphicsItem *item, unpolishedItems) { + while (!unpolishedItems.isEmpty()) { + it = unpolishedItems.begin(); + QGraphicsItem *item = *it; + unpolishedItems.erase(it); if (!item->d_ptr->explicitlyHidden) { item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); @@ -431,7 +435,6 @@ void QGraphicsScenePrivate::_q_polishItems() QApplication::sendEvent((QGraphicsWidget *)item, &event); } } - unpolishedItems.clear(); } void QGraphicsScenePrivate::_q_processDirtyItems() @@ -549,7 +552,7 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) selectedItems.remove(item); hoverItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); - unpolishedItems.removeAll(item); + unpolishedItems.remove(item); resetDirtyItem(item); //We remove all references of item from the sceneEventFilter arrays @@ -2484,7 +2487,7 @@ void QGraphicsScene::addItem(QGraphicsItem *item) if (!item->d_ptr->explicitlyHidden) { if (d->unpolishedItems.isEmpty()) QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); - d->unpolishedItems << item; + d->unpolishedItems.insert(item); } // Reenable selectionChanged() for individual items @@ -5294,7 +5297,7 @@ void QGraphicsScene::setActivePanel(QGraphicsItem *item) /*! \since 4.4 - Returns the current active window, or 0 if there is no window is currently + Returns the current active window, or 0 if no window is currently active. \sa QGraphicsScene::setActiveWindow() @@ -5475,11 +5478,11 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) } if (itemsNeedingEvents.isEmpty()) { - sceneTouchEvent->ignore(); + sceneTouchEvent->accept(); return; } - bool acceptSceneTouchEvent = false; + bool ignoreSceneTouchEvent = true; QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin(); const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd(); for (; it != end; ++it) { @@ -5522,19 +5525,20 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) item->d_ptr->acceptedTouchBeginEvent = true; bool res = sendTouchBeginEvent(item, &touchEvent) && touchEvent.isAccepted(); - acceptSceneTouchEvent = acceptSceneTouchEvent || res; + if (!res) + ignoreSceneTouchEvent = false; break; } default: if (item->d_ptr->acceptedTouchBeginEvent) { updateTouchPointsForItem(item, &touchEvent); (void) sendEvent(item, &touchEvent); - acceptSceneTouchEvent = true; + ignoreSceneTouchEvent = false; } break; } } - sceneTouchEvent->setAccepted(acceptSceneTouchEvent); + sceneTouchEvent->setAccepted(ignoreSceneTouchEvent); } bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent) diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index ba47530..d6d48d7 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -311,6 +311,7 @@ private: friend class QGraphicsSceneBspTreeIndex; friend class QGraphicsSceneBspTreeIndexPrivate; friend class QGraphicsItemEffectSourcePrivate; + friend class QGesture; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsScene::SceneLayers) diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 5000860..8073695 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -108,7 +108,7 @@ public: QPainterPath selectionArea; int selectionChanging; QSet<QGraphicsItem *> selectedItems; - QList<QGraphicsItem *> unpolishedItems; + QSet<QGraphicsItem *> unpolishedItems; QList<QGraphicsItem *> topLevelItems; bool needSortTopLevelItems; bool holesInTopLevelSiblingIndex; diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index 00fc204..b8f8fb4 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -285,24 +285,6 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) // anymore. clearColumns(firstArtificial, columns - 2); - #ifdef QT_DEBUG - // Ensure that at the end of the simplex each row should either: - // - Have a positive value on the column associated to its variable, or - // - Have zero values in all columns. - // - // This avoids a regression where restrictions would be lost - // due to randomness in the pivotRowForColumn method. - for (int i = 1; i < rows; ++i) { - int variableIndex = valueAt(i, 0); - if (valueAt(i, variableIndex) > 0) - continue; - - for (int j = 1; j < columns; ++j) { - Q_ASSERT(valueAt(i, j) == 0); - } - } - #endif - return true; } @@ -537,6 +519,12 @@ qreal QSimplex::solver(solverFactor factor) solveMaxHelper(); collectResults(); +#ifdef QT_DEBUG + for (int i = 0; i < constraints.size(); ++i) { + Q_ASSERT(constraints[i]->isSatisfied()); + } +#endif + return factor * valueAt(0, columns - 1); } diff --git a/src/gui/graphicsview/qsimplex_p.h b/src/gui/graphicsview/qsimplex_p.h index 54b080d..51991a9 100644 --- a/src/gui/graphicsview/qsimplex_p.h +++ b/src/gui/graphicsview/qsimplex_p.h @@ -94,8 +94,32 @@ struct QSimplexConstraint QPair<QSimplexVariable *, qreal> helper; QSimplexVariable * artificial; -}; +#ifdef QT_DEBUG + bool isSatisfied() { + qreal leftHandSide(0); + + QHash<QSimplexVariable *, qreal>::const_iterator iter; + for (iter = variables.constBegin(); iter != variables.constEnd(); ++iter) { + leftHandSide += iter.value() * iter.key()->result; + } + + Q_ASSERT(constant > 0 || qFuzzyCompare(1, 1 + constant)); + + if (qFuzzyCompare(1000 + leftHandSide, 1000 + constant)) + return true; + + switch (ratio) { + case LessOrEqual: + return leftHandSide < constant; + case MoreOrEqual: + return leftHandSide > constant; + default: + return false; + } + } +#endif +}; class QSimplex { diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index fce4508..e0779a0 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -54,6 +54,7 @@ #include "qvariant.h" #include "qcache.h" #include "qdebug.h" +#include "private/qguiplatformplugin_p.h" #ifdef Q_WS_MAC #include <private/qt_mac_p.h> @@ -961,19 +962,10 @@ QString QIcon::themeName() */ QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback) { - static QCache <QString, QIcon> iconCache; QIcon icon; -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_KDE) { - icon = QKde::kdeIcon(name); - if (!icon.isNull()) - return icon; - } -#endif - if (iconCache.contains(name)) { icon = *iconCache.object(name); } else { diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index adc2967..46c5431 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -43,7 +43,7 @@ #include <private/qapplication_p.h> #include <private/qicon_p.h> -#include <private/qkde_p.h> +#include <private/qguiplatformplugin_p.h> #include <QtGui/QIconEnginePlugin> #include <QtGui/QPixmapCache> @@ -68,47 +68,29 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance) +/* Theme to use in last resort, if the theme does not have the icon, neither the parents */ static QString fallbackTheme() { - QString defaultTheme; -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_GNOME) - defaultTheme = QLatin1String("gnome"); - else if (X11->desktopEnvironment == DE_KDE) - defaultTheme = X11->desktopVersion >= 4 ? - QString::fromLatin1("oxygen") : - QString::fromLatin1("crystalsvg"); -#endif - return defaultTheme; -} - -static QString systemThemeName() -{ - QString result = fallbackTheme(); #ifdef Q_WS_X11 if (X11->desktopEnvironment == DE_GNOME) { -#ifndef QT_NO_STYLE_GTK - result = QGtk::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), - result); -#endif + return QLatin1String("gnome"); } else if (X11->desktopEnvironment == DE_KDE) { - QSettings settings(QKde::kdeHome() + - QLatin1String("/share/config/kdeglobals"), - QSettings::IniFormat); - - settings.beginGroup(QLatin1String("Icons")); - - result = settings.value(QLatin1String("Theme"), result).toString(); + return X11->desktopVersion >= 4 + ? QString::fromLatin1("oxygen") + : QString::fromLatin1("crystalsvg"); + } else { + return QLatin1String("hicolor"); } #endif - return result; + return QString(); } - QIconLoader::QIconLoader() : m_themeKey(1), m_supportsSvg(false) { - m_systemTheme = systemThemeName(); + m_systemTheme = qt_guiPlatformPlugin()->systemIconThemeName(); + if (m_systemTheme.isEmpty()) + m_systemTheme = fallbackTheme(); QFactoryLoader iconFactoryLoader(QIconEngineFactoryInterfaceV2_iid, QLatin1String("/iconengines"), @@ -128,7 +110,9 @@ void QIconLoader::updateSystemTheme() { // Only change if this is not explicitly set by the user if (m_userTheme.isEmpty()) { - QString theme = systemThemeName(); + QString theme = qt_guiPlatformPlugin()->systemIconThemeName(); + if (theme.isEmpty()) + theme = fallbackTheme(); if (theme != m_systemTheme) { m_systemTheme = theme; invalidateKey(); @@ -152,51 +136,7 @@ void QIconLoader::setThemeSearchPath(const QStringList &searchPaths) QStringList QIconLoader::themeSearchPaths() const { if (m_iconDirs.isEmpty()) { - -#if defined(Q_WS_X11) - - QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); - if (xdgDirString.isEmpty()) - xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); - - QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); - - for (int i = 0 ; i < xdgDirs.size() ; ++i) { - QDir dir(xdgDirs[i]); - if (dir.exists()) - m_iconDirs.append(dir.path() + - QLatin1String("/icons")); - } - - if (X11->desktopEnvironment == DE_KDE) { - - m_iconDirs << QLatin1Char(':') + - QKde::kdeHome() + - QLatin1String("/share/icons"); - QStringList kdeDirs = - QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); - - for (int i = 0 ; i< kdeDirs.count() ; ++i) { - QDir dir(QLatin1Char(':') + kdeDirs.at(i) + - QLatin1String("/share/icons")); - if (dir.exists()) - m_iconDirs.append(dir.path()); - } - } - - // Add home directory first in search path - QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); - if (homeDir.exists()) - m_iconDirs.prepend(homeDir.path()); -#endif - -#if defined(Q_WS_WIN) - m_iconDirs.append(qApp->applicationDirPath() + - QLatin1String("/icons")); -#elif defined(Q_WS_MAC) - m_iconDirs.append(qApp->applicationDirPath() + - QLatin1String("/../Resources/icons")); -#endif + m_iconDirs = qt_guiPlatformPlugin()->iconThemeSearchPaths(); // Allways add resource directory as search path m_iconDirs.append(QLatin1String(":/icons")); } @@ -291,7 +231,7 @@ QThemeIconEntries QIconLoader::findIconHelper(const QString &themeName, if (!theme.isValid()) { theme = QIconTheme(themeName); if (!theme.isValid()) - theme = fallbackTheme(); + theme = QIconTheme(fallbackTheme()); themeList.insert(themeName, theme); } diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 37b6438..9ae8d72 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -229,24 +229,15 @@ static CFbsBitmap* uncompress(CFbsBitmap* bitmap) lock.relock(); - CBitmapContext *bitmapContext = 0; CFbsBitmapDevice* bitmapDevice = 0; + CFbsBitGc *bitmapGc = 0; QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed)); - TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); - if (err != KErrNone) { - delete bitmap; - delete bitmapDevice; - bitmap = 0; - bitmapDevice = 0; - - lock.relock(); - - return bitmap; - } + QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); + bitmapGc->Activate(bitmapDevice); - bitmapContext->DrawBitmap(TPoint(), bitmap); + bitmapGc->DrawBitmap(TPoint(), bitmap); - delete bitmapContext; + delete bitmapGc; delete bitmapDevice; return uncompressed; @@ -355,7 +346,7 @@ QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), symbianBitmapDataAccess(new QSymbianBitmapDataAccess), cfbsBitmap(0), bitmapDevice(0), - bitmapContext(0), + bitmapGc(0), pengine(0), bytes(0) { @@ -365,6 +356,7 @@ QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), QS60PixmapData::~QS60PixmapData() { release(); + delete symbianBitmapDataAccess; } void QS60PixmapData::resize(int width, int height) @@ -391,6 +383,8 @@ void QS60PixmapData::resize(int width, int height) if(cfbsBitmap->SizeInPixels() != newSize) { cfbsBitmap->Resize(TSize(width, height)); + bitmapDevice->Resize(TSize(width, height)); + bitmapGc->Resized(); if(pengine) { delete pengine; pengine = 0; @@ -404,12 +398,9 @@ void QS60PixmapData::resize(int width, int height) bool QS60PixmapData::initSymbianBitmapContext() { QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap)); - TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); - if (err != KErrNone) { - delete bitmapDevice; - bitmapDevice = 0; - return false; - } + QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); + bitmapGc->Activate(bitmapDevice); + return true; } @@ -417,7 +408,7 @@ void QS60PixmapData::release() { if (cfbsBitmap) { QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); - delete bitmapContext; + delete bitmapGc; delete bitmapDevice; delete cfbsBitmap; lock.relock(); @@ -426,7 +417,7 @@ void QS60PixmapData::release() delete pengine; image = QImage(); cfbsBitmap = 0; - bitmapContext = 0; + bitmapGc = 0; bitmapDevice = 0; pengine = 0; bytes = 0; @@ -559,13 +550,15 @@ void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect) resize(rect.width(), rect.height()); cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode()); - bitmapContext->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect)); + bitmapGc->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect)); } bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) { - bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); - return true; + beginDataAccess(); + bool res = QRasterPixmapData::scroll(dx, dy, rect); + endDataAccess(); + return res; } int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const @@ -723,6 +716,8 @@ void QS60PixmapData::beginDataAccess() void QS60PixmapData::endDataAccess(bool readOnly) const { + Q_UNUSED(readOnly); + if(!cfbsBitmap) return; diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h index 4498c05..b23961a 100644 --- a/src/gui/image/qpixmap_s60_p.h +++ b/src/gui/image/qpixmap_s60_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE class CFbsBitmap; class CFbsBitmapDevice; -class CBitmapContext; +class CFbsBitGc; class QSymbianBitmapDataAccess; @@ -114,7 +114,7 @@ private: CFbsBitmap *cfbsBitmap; CFbsBitmapDevice *bitmapDevice; - CBitmapContext *bitmapContext; + CFbsBitGc *bitmapGc; QPaintEngine *pengine; uchar* bytes; diff --git a/src/gui/inputmethod/qwininputcontext_p.h b/src/gui/inputmethod/qwininputcontext_p.h index 39d50fd..dd0490d 100644 --- a/src/gui/inputmethod/qwininputcontext_p.h +++ b/src/gui/inputmethod/qwininputcontext_p.h @@ -56,6 +56,19 @@ #include "QtGui/qinputcontext.h" #include "QtCore/qt_windows.h" +#if defined(Q_CC_MINGW) && !defined(IMR_RECONVERTSTRING) +typedef struct tagRECONVERTSTRING { + DWORD dwSize; + DWORD dwVersion; + DWORD dwStrLen; + DWORD dwStrOffset; + DWORD dwCompStrLen; + DWORD dwCompStrOffset; + DWORD dwTargetStrLen; + DWORD dwTargetStrOffset; +} RECONVERTSTRING, *PRECONVERTSTRING; +#endif + QT_BEGIN_NAMESPACE class QWinInputContext : public QInputContext diff --git a/src/gui/inputmethod/qwininputcontext_win.cpp b/src/gui/inputmethod/qwininputcontext_win.cpp index 4a160d7..e9ab870 100644 --- a/src/gui/inputmethod/qwininputcontext_win.cpp +++ b/src/gui/inputmethod/qwininputcontext_win.cpp @@ -701,7 +701,7 @@ void QWinInputContext::updateImeStatus(QWidget *w, bool hasFocus) if (!focusProxyWidget) focusProxyWidget = w; bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled() - && !(focusProxyWidget->inputMethodHints() & Qt::ImhExclusiveInputMask); + && !(focusProxyWidget->inputMethodHints() & (Qt::ImhExclusiveInputMask | Qt::ImhHiddenText)); bool hasIme = e && hasFocus; #ifdef Q_IME_DEBUG qDebug("%s HasFocus = %d hasIme = %d e = %d ", w->className(), hasFocus, hasIme, e); diff --git a/src/gui/inputmethod/qximinputcontext_x11.cpp b/src/gui/inputmethod/qximinputcontext_x11.cpp index bee3ce8..b46b162 100644 --- a/src/gui/inputmethod/qximinputcontext_x11.cpp +++ b/src/gui/inputmethod/qximinputcontext_x11.cpp @@ -612,7 +612,7 @@ void QXIMInputContext::setFocusWidget(QWidget *w) QInputContext::setFocusWidget(w); - if (!w || w->inputMethodHints() & Qt::ImhExclusiveInputMask) + if (!w || w->inputMethodHints() & (Qt::ImhExclusiveInputMask | Qt::ImhHiddenText)) return; ICData *data = ximData.value(w->effectiveWinId()); diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 27528de..d91cedd 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -761,7 +761,7 @@ void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate) } } d->itemDelegate = delegate; - update(); + viewport()->update(); } /*! @@ -826,7 +826,7 @@ void QAbstractItemView::setItemDelegateForRow(int row, QAbstractItemDelegate *de } d->rowDelegates.insert(row, delegate); } - update(); + viewport()->update(); } /*! @@ -883,7 +883,7 @@ void QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelega } d->columnDelegates.insert(column, delegate); } - update(); + viewport()->update(); } /*! @@ -1697,7 +1697,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) if ((event->buttons() & Qt::LeftButton) && d->selectionAllowed(index) && d->selectionModel) { setState(DragSelectingState); QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); - if (command.testFlag(QItemSelectionModel::Toggle)) { + if (d->ctrlDragSelectionFlag != QItemSelectionModel::NoUpdate && command.testFlag(QItemSelectionModel::Toggle)) { command &= ~QItemSelectionModel::Toggle; command |= d->ctrlDragSelectionFlag; } @@ -2185,6 +2185,9 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) } else { d->selectionModel->setCurrentIndex(newCurrent, command); d->pressedPosition = visualRect(newCurrent).center() + d->offset(); + // We copy the same behaviour as for mousePressEvent(). + QRect rect(d->pressedPosition - d->offset(), QSize(1, 1)); + setSelection(rect, command); } return; } @@ -3026,7 +3029,7 @@ void QAbstractItemView::update(const QModelIndex &index) //this test is important for peformance reason //For example in dataChanged we simply update all the cells without checking //it can be a major bottleneck to update rects that aren't even part of the viewport - if (d->viewport->geometry().intersects(rect)) + if (d->viewport->rect().intersects(rect)) d->viewport->update(rect); } } diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index c78a49b..e3d17ad 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -61,6 +61,7 @@ #endif #include <private/qfunctions_p.h> +#include <private/qguiplatformplugin_p.h> #ifndef SHGFI_ADDOVERLAYS #define SHGFI_ADDOVERLAYS 0x000000020 @@ -385,6 +386,10 @@ QIcon QFileIconProvider::icon(const QFileInfo &info) const { Q_D(const QFileIconProvider); + QIcon platformIcon = qt_guiPlatformPlugin()->fileSystemIcon(info); + if (!platformIcon.isNull()) + return platformIcon; + #if defined(Q_WS_X11) && !defined(QT_NO_STYLE_GTK) if (X11->desktopEnvironment == DE_GNOME) { QIcon gtkIcon = QGtk::getFilesystemIcon(info); diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 15bd445..a610b73 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -779,8 +779,6 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, foreach (QSpanCollection::Span *span, visibleSpans) { int row = span->top(); int col = span->left(); - if (isHidden(row, col)) - continue; QModelIndex index = model->index(row, col, root); if (!index.isValid()) continue; @@ -1119,6 +1117,9 @@ void QTableView::setHorizontalHeader(QHeaderView *header) connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries())); + + //update the sorting enabled states on the new header + setSortingEnabled(d->sortingEnabled); } /*! @@ -1480,12 +1481,30 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi ++column; while (isRowHidden(d->logicalRow(row)) && row < bottom) ++row; + d->visualCursor = QPoint(column, row); return d->model->index(d->logicalRow(row), d->logicalColumn(column), d->root); } - int visualRow = d->visualRow(current.row()); + // Update visual cursor if current index has changed. + QPoint visualCurrent(d->visualColumn(current.column()), d->visualRow(current.row())); + if (visualCurrent != d->visualCursor) { + if (d->hasSpans()) { + QSpanCollection::Span span = d->span(current.row(), current.column()); + if (span.top() > d->visualCursor.y() || d->visualCursor.y() > span.bottom() + || span.left() > d->visualCursor.x() || d->visualCursor.x() > span.right()) + d->visualCursor = visualCurrent; + } else { + d->visualCursor = visualCurrent; + } + } + + int visualRow = d->visualCursor.y(); + if (visualRow > bottom) + visualRow = bottom; Q_ASSERT(visualRow != -1); - int visualColumn = d->visualColumn(current.column()); + int visualColumn = d->visualCursor.x(); + if (visualColumn > right) + visualColumn = right; Q_ASSERT(visualColumn != -1); if (isRightToLeft()) { @@ -1496,22 +1515,33 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi } switch (cursorAction) { - case MoveUp: + case MoveUp: { + int originalRow = visualRow; #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled() && visualRow == 0) visualRow = d->visualRow(model()->rowCount() - 1) + 1; + // FIXME? visualRow = bottom + 1; #endif - --visualRow; - while (visualRow > 0 && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn)) + int r = d->logicalRow(visualRow); + int c = d->logicalColumn(visualColumn); + if (r != -1 && d->hasSpans()) { + QSpanCollection::Span span = d->span(r, c); + if (span.width() > 1 || span.height() > 1) + visualRow = d->visualRow(span.top()); + } + while (visualRow >= 0) { --visualRow; - if (d->hasSpans()) { - int row = d->logicalRow(visualRow); - QSpanCollection::Span span = d->span(row, current.column()); - visualRow = d->visualRow(span.top()); - visualColumn = d->visualColumn(span.left()); + r = d->logicalRow(visualRow); + c = d->logicalColumn(visualColumn); + if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c))) + break; } + if (visualRow < 0) + visualRow = originalRow; break; - case MoveDown: + } + case MoveDown: { + int originalRow = visualRow; if (d->hasSpans()) { QSpanCollection::Span span = d->span(current.row(), current.column()); visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height())); @@ -1520,71 +1550,106 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi if (QApplication::keypadNavigationEnabled() && visualRow >= bottom) visualRow = -1; #endif - ++visualRow; - while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn)) + int r = d->logicalRow(visualRow); + int c = d->logicalColumn(visualColumn); + if (r != -1 && d->hasSpans()) { + QSpanCollection::Span span = d->span(r, c); + if (span.width() > 1 || span.height() > 1) + visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height())); + } + while (visualRow <= bottom) { ++visualRow; - if (d->hasSpans()) { - int row = d->logicalRow(visualRow); - QSpanCollection::Span span = d->span(row, current.column()); - visualColumn = d->visualColumn(span.left()); + r = d->logicalRow(visualRow); + c = d->logicalColumn(visualColumn); + if (r == -1 || (!isRowHidden(r) && d->isCellEnabled(r, c))) + break; } + if (visualRow > bottom) + visualRow = originalRow; break; - case MovePrevious: { - int left = 0; - while (d->isVisualColumnHiddenOrDisabled(visualRow, left) && left < right) - ++left; - if (visualColumn == left) { - visualColumn = right; - int top = 0; - while (top < bottom && d->isVisualRowHiddenOrDisabled(top, visualColumn)) - ++top; - if (visualRow == top) + } + case MovePrevious: + case MoveLeft: { + int originalRow = visualRow; + int originalColumn = visualColumn; + bool firstTime = true; + bool looped = false; + bool wrapped = false; + do { + int r = d->logicalRow(visualRow); + int c = d->logicalColumn(visualColumn); + if (firstTime && c != -1 && d->hasSpans()) { + firstTime = false; + QSpanCollection::Span span = d->span(r, c); + if (span.width() > 1 || span.height() > 1) + visualColumn = d->visualColumn(span.left()); + } + while (visualColumn >= 0) { + --visualColumn; + r = d->logicalRow(visualRow); + c = d->logicalColumn(visualColumn); + if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c))) + break; + if (wrapped && (originalRow < visualRow || (originalRow == visualRow && originalColumn <= visualColumn))) { + looped = true; + break; + } + } + if (cursorAction == MoveLeft || visualColumn >= 0) + break; + visualColumn = right + 1; + if (visualRow == 0) { + wrapped == true; visualRow = bottom; - else - --visualRow; - while (visualRow > 0 && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn)) + } else { --visualRow; - break; - } // else MoveLeft - } - case MoveLeft: - --visualColumn; - while (visualColumn > 0 && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn)) - --visualColumn; - if (d->hasSpans()) { - int column = d->logicalColumn(visualColumn); - QSpanCollection::Span span = d->span(current.row(), column); - visualRow = d->visualRow(span.top()); - visualColumn = d->visualColumn(span.left()); - } + } + } while (!looped); + if (visualColumn < 0) + visualColumn = originalColumn; break; + } case MoveNext: - if (visualColumn == right) { - visualColumn = 0; - while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn)) + case MoveRight: { + int originalRow = visualRow; + int originalColumn = visualColumn; + bool firstTime = true; + bool looped = false; + bool wrapped = false; + do { + int r = d->logicalRow(visualRow); + int c = d->logicalColumn(visualColumn); + if (firstTime && c != -1 && d->hasSpans()) { + firstTime = false; + QSpanCollection::Span span = d->span(r, c); + if (span.width() > 1 || span.height() > 1) + visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width())); + } + while (visualColumn <= right) { ++visualColumn; - if (visualRow == bottom) + r = d->logicalRow(visualRow); + c = d->logicalColumn(visualColumn); + if (r == -1 || c == -1 || (!isRowHidden(r) && !isColumnHidden(c) && d->isCellEnabled(r, c))) + break; + if (wrapped && (originalRow > visualRow || (originalRow == visualRow && originalColumn >= visualColumn))) { + looped = true; + break; + } + } + if (cursorAction == MoveRight || visualColumn <= right) + break; + visualColumn = -1; + if (visualRow == bottom) { + wrapped = true; visualRow = 0; - else - ++visualRow; - while (visualRow < bottom && d->isVisualRowHiddenOrDisabled(visualRow, visualColumn)) + } else { ++visualRow; - break; - } // else MoveRight - case MoveRight: - if (d->hasSpans()) { - QSpanCollection::Span span = d->span(current.row(), current.column()); - visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width())); - } - ++visualColumn; - while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn)) - ++visualColumn; - if (d->hasSpans()) { - int column = d->logicalColumn(visualColumn); - QSpanCollection::Span span = d->span(current.row(), column); - visualRow = d->visualRow(span.top()); - } + } + } while (!looped); + if (visualColumn > right) + visualColumn = originalColumn; break; + } case MoveHome: visualColumn = 0; while (visualColumn < right && d->isVisualColumnHiddenOrDisabled(visualRow, visualColumn)) @@ -1613,14 +1678,15 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi return d->model->index(newRow, current.column(), d->root); }} + d->visualCursor = QPoint(visualColumn, visualRow); int logicalRow = d->logicalRow(visualRow); int logicalColumn = d->logicalColumn(visualColumn); if (!d->model->hasIndex(logicalRow, logicalColumn, d->root)) return QModelIndex(); QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root); - if (!isIndexHidden(result) && d->isIndexEnabled(result)) - return d->model->index(logicalRow, logicalColumn, d->root); + if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result)) + return result; return QModelIndex(); } @@ -2375,7 +2441,8 @@ bool QTableView::isCornerButtonEnabled() const QRect QTableView::visualRect(const QModelIndex &index) const { Q_D(const QTableView); - if (!d->isIndexValid(index) || index.parent() != d->root || isIndexHidden(index) ) + if (!d->isIndexValid(index) || index.parent() != d->root + || (!d->hasSpans() && isIndexHidden(index))) return QRect(); d->executePostedLayout(); diff --git a/src/gui/itemviews/qtableview_p.h b/src/gui/itemviews/qtableview_p.h index c785bd7..9fa14c2 100644 --- a/src/gui/itemviews/qtableview_p.h +++ b/src/gui/itemviews/qtableview_p.h @@ -135,7 +135,8 @@ public: rowSectionAnchor(-1), columnSectionAnchor(-1), columnResizeTimerID(0), rowResizeTimerID(0), horizontalHeader(0), verticalHeader(0), - sortingEnabled(false), geometryRecursionBlock(false) + sortingEnabled(false), geometryRecursionBlock(false), + visualCursor(QPoint()) { wrapItemText = true; #ifndef QT_NO_DRAGANDDROP @@ -183,6 +184,7 @@ public: QWidget *cornerWidget; bool sortingEnabled; bool geometryRecursionBlock; + QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation. QSpanCollection spans; diff --git a/src/gui/itemviews/qtablewidget.cpp b/src/gui/itemviews/qtablewidget.cpp index a086498..21c4e0a 100644 --- a/src/gui/itemviews/qtablewidget.cpp +++ b/src/gui/itemviews/qtablewidget.cpp @@ -571,6 +571,8 @@ void QTableModel::ensureSorted(int column, Qt::SortOrder order, colItems.remove(oldRow); vit = sortedInsertionIterator(vit, colItems.end(), order, item); int newRow = qMax((int)(vit - colItems.begin()), 0); + if ((newRow < oldRow) && !(*item < *colItems.at(oldRow - 1)) && !(*colItems.at(oldRow - 1) < *item)) + newRow = oldRow; vit = colItems.insert(vit, item); if (newRow != oldRow) { changed = true; diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 06342d8..040c498 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -623,7 +623,7 @@ void QTreeModel::ensureSorted(int column, Qt::SortOrder order, lit = sortedInsertionIterator(lit, lst.end(), order, item); int newRow = qMax(lit - lst.begin(), 0); - if ((newRow < oldRow) && !(*item < *lst.at(oldRow - 1))) + if ((newRow < oldRow) && !(*item < *lst.at(oldRow - 1)) && !(*lst.at(oldRow - 1) < *item )) newRow = oldRow; lit = lst.insert(lit, item); diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 7cde384..53c2611 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -45,9 +45,11 @@ HEADERS += \ kernel/qkeymapper_p.h \ kernel/qgesture.h \ kernel/qgesture_p.h \ - kernel/qstandardgestures.h \ - kernel/qstandardgestures_p.h \ - kernel/qsoftkeymanager_p.h + kernel/qstandardgestures_p.h \ + kernel/qgesturerecognizer.h \ + kernel/qgesturemanager_p.h \ + kernel/qsoftkeymanager_p.h \ + kernel/qguiplatformplugin_p.h SOURCES += \ kernel/qaction.cpp \ @@ -78,12 +80,18 @@ SOURCES += \ kernel/qwidgetaction.cpp \ kernel/qkeymapper.cpp \ kernel/qgesture.cpp \ - kernel/qstandardgestures.cpp \ - kernel/qsoftkeymanager.cpp + kernel/qstandardgestures.cpp \ + kernel/qgesturerecognizer.cpp \ + kernel/qgesturemanager.cpp \ + kernel/qsoftkeymanager.cpp \ + kernel/qguiplatformplugin.cpp win32 { DEFINES += QT_NO_DIRECTDRAW + HEADERS += \ + kernel/qwinnativepangesturerecognizer_win_p.h + SOURCES += \ kernel/qapplication_win.cpp \ kernel/qclipboard_win.cpp \ @@ -94,7 +102,8 @@ win32 { kernel/qsound_win.cpp \ kernel/qwidget_win.cpp \ kernel/qole_win.cpp \ - kernel/qkeymapper_win.cpp + kernel/qkeymapper_win.cpp \ + kernel/qwinnativepangesturerecognizer_win.cpp !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib } @@ -196,6 +205,7 @@ embedded { qcocoaview_mac_p.h \ qcocoaapplication_mac_p.h \ qcocoaapplicationdelegate_mac_p.h \ + qmacgesturerecognizer_mac_p.h \ qmultitouch_mac_p.h OBJECTIVE_SOURCES += \ @@ -215,7 +225,8 @@ embedded { kernel/qdesktopwidget_mac.mm \ kernel/qeventdispatcher_mac.mm \ kernel/qcocoawindowcustomthemeframe_mac.mm \ - kernel/qmultitouch_mac.mm \ + kernel/qmacgesturerecognizer_mac.mm \ + kernel/qmultitouch_mac.mm HEADERS += \ kernel/qt_cocoa_helpers_mac_p.h \ diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 044fedd..6f6d706 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -84,6 +84,8 @@ #include "qinputcontextfactory.h" #endif +#include "qguiplatformplugin_p.h" + #include <qthread.h> #include <private/qthread_p.h> @@ -97,6 +99,9 @@ #include "qapplication.h" +#include "qgesture.h" +#include "private/qgesturemanager_p.h" + #ifndef QT_NO_LIBRARY #include "qlibrary.h" #endif @@ -152,6 +157,14 @@ bool QApplicationPrivate::autoSipEnabled = false; bool QApplicationPrivate::autoSipEnabled = true; #endif +QGestureManager* QGestureManager::instance() +{ + QApplicationPrivate *d = qApp->d_func(); + if (!d->gestureManager) + d->gestureManager = new QGestureManager(qApp); + return d->gestureManager; +} + QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) : QCoreApplicationPrivate(argc, argv) { @@ -175,6 +188,8 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T directPainters = 0; #endif + gestureManager = 0; + if (!self) self = this; } @@ -788,6 +803,9 @@ void QApplicationPrivate::construct( qCritical("Library qttestability load failed!"); } } + + //make sure the plugin is loaded + qt_guiPlatformPlugin(); #endif } @@ -925,7 +943,7 @@ void QApplicationPrivate::initialize() graphics_system = QGraphicsSystemFactory::create(graphics_system_name); #endif #ifndef QT_NO_WHEELEVENT -#ifdef Q_OS_MAC +#ifdef Q_OS_MAC QApplicationPrivate::wheel_scroll_lines = 1; #else QApplicationPrivate::wheel_scroll_lines = 3; @@ -1016,11 +1034,11 @@ QApplication::~QApplication() d->eventDispatcher->closingDown(); d->eventDispatcher = 0; + QApplicationPrivate::is_app_closing = true; + QApplicationPrivate::is_app_running = false; delete qt_desktopWidget; qt_desktopWidget = 0; - QApplicationPrivate::is_app_closing = true; - QApplicationPrivate::is_app_running = false; #ifndef QT_NO_CLIPBOARD delete qt_clipboard; @@ -1955,38 +1973,7 @@ void QApplicationPrivate::setSystemFont(const QFont &font) */ QString QApplicationPrivate::desktopStyleKey() { -QString desktopstyle; -#if defined(Q_WS_WIN) && defined(Q_WS_WINCE) - if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) - desktopstyle = QLatin1String("WindowsMobile"); - else - desktopstyle = QLatin1String("WindowsCE"); - -#elif defined(Q_WS_WIN) - if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - desktopstyle = QLatin1String("WindowsVista"); - else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - desktopstyle = QLatin1String("WindowsXP"); - else - desktopstyle = QLatin1String("Windows"); // default styles for Windows -#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) - desktopstyle = QLatin1String("CDE"); // default style for X11 on Solaris -#elif defined(Q_WS_S60) - desktopstyle = QLatin1String("S60"); // default style for Symbian with S60 -#elif defined(Q_OS_SYMBIAN) - desktopstyle = QLatin1String("Windows"); // default style for Symbian without S60 -#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) - desktopstyle = QLatin1String("SGI"); // default style for X11 on IRIX -#elif defined(Q_WS_QWS) - desktopstyle = QLatin1String("Plastique"); // default style for X11 and small devices -#elif defined(Q_WS_X11) - desktopstyle = QApplicationPrivate::x11_desktop_style(); // default runtime dependant style for X11 -#elif defined(Q_WS_MAC) - desktopstyle = QLatin1String("Macintosh"); // default style for all Mac's -#endif - return desktopstyle; + return qt_guiPlatformPlugin()->styleName(); } /*! @@ -3658,6 +3645,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT } + // walk through parents and check for gestures + if (d->gestureManager) { + if (d->gestureManager->filterEvent(receiver, e)) + return true; + } + + // User input and window activation makes tooltips sleep switch (e->type()) { case QEvent::Wheel: @@ -4159,6 +4153,65 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(e); + QList<QGesture *> allGestures = gestureEvent->allGestures(); + + bool eventAccepted = gestureEvent->isAccepted(); + bool wasAccepted = eventAccepted; + while (w) { + // send only gestures the widget expects + QList<QGesture *> gestures; + QWidgetPrivate *wd = w->d_func(); + for (int i = 0; i < allGestures.size();) { + QGesture *g = allGestures.at(i); + Qt::GestureType type = g->gestureType(); + if (wd->gestureContext.contains(type)) { + allGestures.removeAt(i); + gestures.append(g); + gestureEvent->setAccepted(g, false); + } else { + ++i; + } + } + if (!gestures.isEmpty()) { + QGestureEvent ge(gestures); + ge.t = gestureEvent->t; + ge.spont = gestureEvent->spont; + ge.m_accept = wasAccepted; + res = d->notify_helper(w, &ge); + gestureEvent->spont = false; + eventAccepted = ge.isAccepted(); + if (res && eventAccepted) + break; + if (!eventAccepted) { + // ### two ways to ignore the event/gesture + + // if the whole event wasn't accepted, put back those + // gestures that were not accepted. + for (int i = 0; i < gestures.size(); ++i) { + QGesture *g = gestures.at(i); + if (!ge.isAccepted(g)) + allGestures.append(g); + } + } + } + if (allGestures.isEmpty()) + break; + if (w->isWindow()) + break; + w = w->parentWidget(); + } + gestureEvent->m_accept = eventAccepted; + } else { + res = d->notify_helper(receiver, e); + } + break; + } default: res = d->notify_helper(receiver, e); break; @@ -5566,6 +5619,37 @@ Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); } +/*! + \since 4.6 + + Registers the given \a recognizer in the gesture framework and returns a gesture ID + for it. + + The application takes ownership of the \a recognizer and returns the gesture type + ID associated with it. For gesture recognizers which handle custom QGesture + objects (i.e., those which return Qt::CustomGesture in a QGesture::gestureType() + function) the return value is a gesture ID between Qt::CustomGesture and + Qt::LastGestureType, inclusive. + + \sa unregisterGestureRecognizer(), QGestureRecognizer::createGesture(), QGesture +*/ +Qt::GestureType QApplication::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + return QGestureManager::instance()->registerGestureRecognizer(recognizer); +} + +/*! + \since 4.6 + + Unregisters all gesture recognizers of the specified \a type. + + \sa registerGestureRecognizer() +*/ +void QApplication::unregisterGestureRecognizer(Qt::GestureType type) +{ + QGestureManager::instance()->unregisterGestureRecognizer(type); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 5f21a56..12b398d 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -86,6 +86,7 @@ class QDecoration; class QApplication; class QApplicationPrivate; +class QGestureRecognizer; #if defined(qApp) #undef qApp #endif @@ -289,6 +290,9 @@ public: static Qt::NavigationMode navigationMode(); #endif + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + Q_SIGNALS: void lastWindowClosed(); void focusChanged(QWidget *old, QWidget *now); @@ -400,6 +404,7 @@ private: friend class QDirectPainter; friend class QDirectPainterPrivate; #endif + friend class QGestureManager; #if defined(Q_WS_MAC) || defined(Q_WS_X11) Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut()) diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index a95ae9d..f9c8aa3 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -1708,12 +1708,30 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event sizeof(axis), 0, &axis); // The 'new' event has acceleration applied by the OS, while the old (on - // Carbon only), has not. So we introduce acceleration here to be consistent: - int scrollFactor = 120 * qMin(5, qAbs(mdelt)); + // Carbon only), has not. So we introduce acceleration here to be consistent. + // The acceleration is trying to respect both pixel based and line scrolling, + // which turns out to be rather difficult. + int linesToScroll = mdelt > 0 ? 1 : -1; + static QTime t; + int elapsed = t.elapsed(); + t.restart(); + if (elapsed < 20) + linesToScroll *= 120; + else if (elapsed < 30) + linesToScroll *= 60; + else if (elapsed < 50) + linesToScroll *= 30; + else if (elapsed < 100) + linesToScroll *= 6; + else if (elapsed < 200) + linesToScroll *= 3; + else if (elapsed < 300) + linesToScroll *= 2; + if (axis == kEventMouseWheelAxisX) - wheel_deltaX = mdelt * scrollFactor; + wheel_deltaX = linesToScroll * 120; else - wheel_deltaY = mdelt * scrollFactor; + wheel_deltaY = linesToScroll * 120; } } diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 6036196..2d3d18c 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -83,8 +83,8 @@ class QGraphicsSystem; class QInputContext; class QObject; class QWidget; -class QGestureManager; class QSocketNotifier; +class QGestureManager; extern bool qt_is_gui_used; #ifndef QT_NO_CLIPBOARD @@ -265,20 +265,6 @@ typedef struct tagGESTURECONFIG #endif // Q_WS_WIN -class QPanGesture; -class QPinchGesture; -class QSwipeGesture; - -struct QStandardGestures -{ - QPanGesture *pan; - QPinchGesture *pinch; - QSwipeGesture *swipe; - - QStandardGestures() : pan(0), pinch(0), swipe(0) { } -}; - - class QScopedLoopLevelCounter { QThreadData *threadData; @@ -305,7 +291,6 @@ public: #if defined(Q_WS_X11) #ifndef QT_NO_SETTINGS - static QString x11_desktop_style(); static bool x11_apply_settings(); #endif static void reset_instance_pointer(); @@ -523,6 +508,8 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif + QGestureManager *gestureManager; + QMap<int, QWidget *> widgetForTouchPointId; QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); @@ -537,9 +524,6 @@ public: QTouchEvent::DeviceType deviceType, const QList<QTouchEvent::TouchPoint> &touchPoints); - typedef QMap<QWidget*, QStandardGestures> WidgetStandardGesturesMap; - WidgetStandardGesturesMap widgetGestures; - #if defined(Q_WS_WIN) static PtrRegisterTouchWindow RegisterTouchWindow; static PtrGetTouchInputInfo GetTouchInputInfo; @@ -556,7 +540,6 @@ public: PtrBeginPanningFeedback BeginPanningFeedback; PtrUpdatePanningFeedback UpdatePanningFeedback; PtrEndPanningFeedback EndPanningFeedback; - QWidget *gestureWidget; #endif #ifdef QT_RX71_MULTITOUCH diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index acd1041..cb9dda4 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -352,7 +352,8 @@ QSymbianControl::~QSymbianControl() { if (S60->curWin == this) S60->curWin = 0; - setFocusSafely(false); + if (!QApplicationPrivate::is_app_closing) + setFocusSafely(false); S60->appUi()->RemoveFromStack(this); delete m_longTapDetector; } @@ -463,12 +464,47 @@ void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } +typedef QPair<QWidget*,QMouseEvent> Event; + +/* + * Helper function called by HandlePointerEvent - separated to keep that function readable + */ +static void generateEnterLeaveEvents(QList<Event> &events, QWidget *widgetUnderPointer, + QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) +{ + //moved to another widget, create enter and leave events + if (S60->lastPointerEventTarget) { + QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal( + S60->lastCursorPos), S60->lastCursorPos, button, QApplicationPrivate::mouse_buttons, + modifiers); + events.append(Event(S60->lastPointerEventTarget, mEventLeave)); + } + if (widgetUnderPointer) { + QMouseEvent mEventEnter(QEvent::Enter, widgetUnderPointer->mapFromGlobal(globalPos), + globalPos, button, QApplicationPrivate::mouse_buttons, modifiers); + + events.append(Event(widgetUnderPointer, mEventEnter)); +#ifndef QT_NO_CURSOR + S60->curWin = widgetUnderPointer->effectiveWinId(); + if (!QApplication::overrideCursor()) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_set_pointer_sprite(widgetUnderPointer->cursor()); + else +#endif + qt_symbian_setWindowCursor(widgetUnderPointer->cursor(), S60->curWin); + } +#endif + } +} + + void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) { - //### refactor me, getting too complex QMouseEvent::Type type; Qt::MouseButton button; mapS60MouseEventTypeToQt(&type, &button, &pEvent); + Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); if (m_previousEventLongTap) if (type == QEvent::MouseButtonRelease){ @@ -480,79 +516,76 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) return; // store events for later sending/saving - QWidget *alienWidget; - typedef QPair<QWidget*,QMouseEvent> Event; QList<Event > events; QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; - if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) - { - // get the widget where the event happened - alienWidget = qwidget->childAt(widgetPos); - if (!alienWidget) - alienWidget = qwidget; - S60->mousePressTarget = alienWidget; + // widgets interested in the event + QWidget *widgetUnderPointer = qwidget->childAt(widgetPos); + if (!widgetUnderPointer) + widgetUnderPointer = qwidget; //i.e. this container widget + + QWidget *widgetWithMouseGrab = QWidget::mouseGrabber(); + + // handle auto grab of pointer when pressing / releasing + if (!widgetWithMouseGrab && type == QEvent::MouseButtonPress) { + //if previously auto-grabbed, generate a fake mouse release (platform bug: mouse release event was lost) + if (S60->mousePressTarget) { + QMouseEvent mEvent(QEvent::MouseButtonRelease, S60->mousePressTarget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(S60->mousePressTarget,mEvent)); + } + //auto grab the mouse + widgetWithMouseGrab = S60->mousePressTarget = widgetUnderPointer; + widgetWithMouseGrab->grabMouse(); + } + if (widgetWithMouseGrab && widgetWithMouseGrab == S60->mousePressTarget && type == QEvent::MouseButtonRelease) { + //release the auto grab - note this release event still goes to the autograb widget + S60->mousePressTarget = 0; + widgetWithMouseGrab->releaseMouse(); } - alienWidget = S60->mousePressTarget; + QWidget *widgetToReceiveMouseEvent; + if (widgetWithMouseGrab) + widgetToReceiveMouseEvent = widgetWithMouseGrab; + else + widgetToReceiveMouseEvent = widgetUnderPointer; - if (alienWidget != S60->lastPointerEventTarget) - if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) - { - //moved to another widget, create enter and leave events - if (S60->lastPointerEventTarget) - { - QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, - button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); - events.append(Event(S60->lastPointerEventTarget,mEventLeave)); - } - if (alienWidget) { - QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), - globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers( - pEvent.iModifiers)); + //queue QEvent::Enter and QEvent::Leave, if the pointer has moved + if (widgetUnderPointer != S60->lastPointerEventTarget && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)) + generateEnterLeaveEvents(events, widgetUnderPointer, globalPos, button, modifiers); - events.append(Event(alienWidget, mEventEnter)); -#ifndef QT_NO_CURSOR - S60->curWin = alienWidget->effectiveWinId(); - if (!QApplication::overrideCursor()) { -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS - if (S60->brokenPointerCursors) - qt_symbian_set_pointer_sprite(alienWidget->cursor()); - else -#endif - qt_symbian_setWindowCursor(alienWidget->cursor(), S60->curWin); - } -#endif - } - } + //save global state S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = widgetUnderPointer; + #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS) if (S60->brokenPointerCursors) qt_symbian_move_cursor_sprite(); #endif - S60->lastPointerEventPos = widgetPos; - S60->lastPointerEventTarget = alienWidget; - if (alienWidget) - { - QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, - button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); - events.append(Event(alienWidget,mEvent)); - QEventDispatcherS60 *dispatcher; - // It is theoretically possible for someone to install a different event dispatcher. - if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->d_func()->threadData->eventDispatcher)) != 0) { - if (dispatcher->excludeUserInputEvents()) { - for (int i=0;i < events.count();++i) - { - Event next = events[i]; - dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); - } - return; + + //queue this event. + Q_ASSERT(widgetToReceiveMouseEvent); + QMouseEvent mEvent(type, widgetToReceiveMouseEvent->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(widgetToReceiveMouseEvent,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widgetToReceiveMouseEvent->d_func()->threadData->eventDispatcher)) != 0) { + if (dispatcher->excludeUserInputEvents()) { + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); } + return; } } + + //send events in the queue for (int i=0;i < events.count();++i) { Event next = events[i]; @@ -688,7 +721,7 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), - false, 1, keyEvent.iScanCode, s60Keysym, mods); + false, 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers); // WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child(); // if (!wid) // Could happen if window isn't shown yet. @@ -948,7 +981,8 @@ void QSymbianControl::setFocusSafely(bool focus) S60->appUi()->RemoveFromStack(this); QT_TRAP_THROWING(S60->appUi()->AddToStackL(this, ECoeStackPriorityDefault, ECoeStackFlagStandard)); - lastFocusedControl = 0; + if(this == lastFocusedControl) + lastFocusedControl = 0; this->SetFocus(false); } } @@ -1121,6 +1155,11 @@ void qt_init(QApplicationPrivate * /* priv */, int) ; } */ + + // Register WId with the metatype system. This is to enable + // QWidgetPrivate::create_sys to used delayed slot invokation in order + // to destroy WId objects during reparenting. + qRegisterMetaType<WId>("WId"); } /***************************************************************************** diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 44f82b6..5bb25fa 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -92,8 +92,6 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include <private/qkeymapper_p.h> #include <private/qlocale_p.h> #include "qevent_p.h" -#include "qstandardgestures.h" -#include "qstandardgestures_p.h" //#define ALIEN_DEBUG @@ -171,10 +169,13 @@ typedef struct tagTOUCHINPUT #include <mywinsock.h> #endif +#ifndef IMR_RECONVERTSTRING +#define IMR_RECONVERTSTRING 4 +#endif + #ifndef IMR_CONFIRMRECONVERTSTRING #define IMR_CONFIRMRECONVERTSTRING 0x0005 #endif - QT_BEGIN_NAMESPACE #ifdef Q_WS_WINCE @@ -818,13 +819,16 @@ void qt_init(QApplicationPrivate *priv, int) priv->GetGestureInfo = 0; priv->GetGestureExtraArgs = 0; + priv->CloseGestureInfoHandle = 0; + priv->SetGestureConfig = 0; + priv->GetGestureConfig = 0; + priv->BeginPanningFeedback = 0; + priv->UpdatePanningFeedback = 0; + priv->EndPanningFeedback = 0; #if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo; priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments; - priv->CloseGestureInfoHandle = (PtrCloseGestureInfoHandle) 0; - priv->SetGestureConfig = (PtrSetGestureConfig) 0; - priv->GetGestureConfig = (PtrGetGestureConfig) 0; #elif !defined(Q_WS_WINCE) priv->GetGestureInfo = (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), @@ -851,7 +855,6 @@ void qt_init(QApplicationPrivate *priv, int) (PtrEndPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), "EndPanningFeedback"); #endif - priv->gestureWidget = 0; } /***************************************************************************** @@ -2496,24 +2499,24 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam if (qAppPriv->GetGestureInfo) bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); if (bResult) { - if (gi.dwID == GID_BEGIN) { - // find the alien widget for the gesture position. - // This might not be accurate as the position is the center - // point of two fingers for multi-finger gestures. - QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y); - QWidget *w = widget->childAt(widget->mapFromGlobal(pt)); - qAppPriv->gestureWidget = w ? w : widget; - } - if (qAppPriv->gestureWidget) - static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi); - if (qAppPriv->CloseGestureInfoHandle) - qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); - if (gi.dwID == GID_END) - qAppPriv->gestureWidget = 0; - } else { - DWORD dwErr = GetLastError(); - if (dwErr > 0) - qWarning() << "translateGestureEvent: error = " << dwErr; +// if (gi.dwID == GID_BEGIN) { +// // find the alien widget for the gesture position. +// // This might not be accurate as the position is the center +// // point of two fingers for multi-finger gestures. +// QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y); +// QWidget *w = widget->childAt(widget->mapFromGlobal(pt)); +// qAppPriv->gestureWidget = w ? w : widget; +// } +// if (qAppPriv->gestureWidget) +// static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi); +// if (qAppPriv->CloseGestureInfoHandle) +// qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); +// if (gi.dwID == GID_END) +// qAppPriv->gestureWidget = 0; +// } else { +// DWORD dwErr = GetLastError(); +// if (dwErr > 0) +// qWarning() << "translateGestureEvent: error = " << dwErr; } result = true; break; diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index e46a370..bf95684 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -85,6 +85,7 @@ #include "qtimer.h" #include "qlibrary.h" #include <private/qgraphicssystemfactory_p.h> +#include "qguiplatformplugin_p.h" #include "qkde_p.h" #if !defined (QT_NO_TABLET) @@ -919,7 +920,7 @@ bool QApplicationPrivate::x11_apply_settings() QString stylename = settings.value(QLatin1String("style")).toString(); if (stylename.isEmpty() && QApplicationPrivate::styleOverride.isNull() && X11->use_xrender) { - stylename = x11_desktop_style(); + stylename = qt_guiPlatformPlugin()->styleName(); } static QString currentStyleName = stylename; @@ -1313,8 +1314,7 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, pal.setColor(QPalette::Disabled, QPalette::Highlight, Qt::darkBlue); } - if (kdeColors) - pal = QKde::kdePalette().resolve(pal); + pal = qt_guiPlatformPlugin()->palette().resolve(pal); QApplicationPrivate::setSystemPalette(pal); QColor::setAllowX11ColorNames(allowX11ColorNames); } @@ -2560,42 +2560,6 @@ void qt_init(QApplicationPrivate *priv, int, #endif } - - // run-time search for default style -/*! - \internal -*/ -QString QApplicationPrivate::x11_desktop_style() -{ - QString stylename; - switch(X11->desktopEnvironment) { - case DE_KDE: - stylename = QKde::kdeStyle(); - break; - case DE_GNOME: { - QStringList availableStyles = QStyleFactory::keys(); - // Set QGtkStyle for GNOME if available - QString gtkStyleKey = QString::fromLatin1("GTK+"); - if (availableStyles.contains(gtkStyleKey)) { - stylename = gtkStyleKey; - break; - } - if (X11->use_xrender) - stylename = QLatin1String("cleanlooks"); - else - stylename = QLatin1String("windows"); - break; - } - case DE_CDE: - stylename = QLatin1String("cde"); - break; - default: - // Don't do anything - break; - } - return stylename; -} - void QApplicationPrivate::initializeWidgetPaletteHash() { } diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index b1c5fc5..4c2a14a 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -1066,7 +1066,10 @@ extern "C" { sendToPopup = true; } - if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)) { + if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled) + && !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) { [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]]; } if (sendKeyEvents && !composing) { @@ -1420,29 +1423,29 @@ Qt::DropAction QDragManager::drag(QDrag *o) // convert the image to NSImage. NSImage *image = (NSImage *)qt_mac_create_nsimage(pix); [image retain]; - DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; + DnDParams dndParams = *[QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; // save supported actions - [dndParams->view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)]; - NSPoint imageLoc = {dndParams->localPoint.x - hotspot.x(), - dndParams->localPoint.y + pix.height() - hotspot.y()}; + [dndParams.view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)]; + NSPoint imageLoc = {dndParams.localPoint.x - hotspot.x(), + dndParams.localPoint.y + pix.height() - hotspot.y()}; NSSize mouseOffset = {0.0, 0.0}; NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - NSPoint windowPoint = [dndParams->theEvent locationInWindow]; + NSPoint windowPoint = [dndParams.theEvent locationInWindow]; dragPrivate()->executed_action = Qt::ActionMask; // do the drag - [dndParams->view retain]; - [dndParams->view dragImage:image + [dndParams.view retain]; + [dndParams.view dragImage:image at:imageLoc offset:mouseOffset - event:dndParams->theEvent + event:dndParams.theEvent pasteboard:pboard - source:dndParams->view + source:dndParams.view slideBack:YES]; - [dndParams->view release]; + [dndParams.view release]; [image release]; dragPrivate()->executed_action = Qt::IgnoreAction; object = 0; - Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction)); + Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams.performedAction)); // do post drag processing, if required. if(performedAction != Qt::IgnoreAction) { // check if the receiver points us to a file location. diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp index 0d8283d..7f5c32a 100644 --- a/src/gui/kernel/qcursor_s60.cpp +++ b/src/gui/kernel/qcursor_s60.cpp @@ -110,7 +110,7 @@ void qt_symbian_set_cursor_visible(bool visible) { else cursorSpriteVisible--; Q_ASSERT(cursorSpriteVisible >=0); - + if (cursorSpriteVisible && !S60->mouseInteractionEnabled) { #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS if (S60->brokenPointerCursors) @@ -119,7 +119,7 @@ void qt_symbian_set_cursor_visible(bool visible) { #endif S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); } else if (!cursorSpriteVisible && S60->mouseInteractionEnabled) { -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS if (S60->brokenPointerCursors) qt_symbian_hide_pointer_sprite(); else @@ -188,7 +188,7 @@ Qt::HANDLE QCursor::handle() const return reinterpret_cast<Qt::HANDLE> (&(d->pcurs)); #ifdef Q_SYMBIAN_HAS_SYSTEM_CURSORS - // don't construct shape cursors, QApplication_s60 will use the system cursor instead + // don't construct shape cursors, QApplication_s60 will use the system cursor instead if (!(d->bm)) return 0; #endif @@ -228,12 +228,12 @@ void QCursorData::loadShapeFromResource(RWsSpriteBase& target, QString resource, /* * Constructs the native cursor from resources compiled into QtGui * This is needed only when the platform doesn't have system cursors. - * + * * System cursors are higher performance, since they are constructed once * and shared by all applications by specifying the shape number. * Due to symbian platform security considerations, and the fact most * existing phones have a broken RWsPointerCursor, system cursors are not - * being used. + * being used. */ void QCursorData::constructShapeSprite(RWsSpriteBase& target) { @@ -346,7 +346,7 @@ void QCursorData::constructCursorSprite(RWsSpriteBase& target) member->iMaskBitmap = pixmap.mask().toSymbianCFbsBitmap(); } else { - member->iMaskBitmap = pixmap.createHeuristicMask().toSymbianCFbsBitmap(); + member->iMaskBitmap = 0; //opaque rectangle cursor (due to EDrawModePEN) } } @@ -371,11 +371,11 @@ void qt_symbian_show_pointer_sprite() } else { cursorSprite = QCursor(Qt::ArrowCursor); } - + cursorSprite.d->scurs = RWsSprite(S60->wsSession()); QPoint pos = QCursor::pos(); cursorSprite.d->scurs.Construct(S60->windowGroup(), TPoint(pos.x(), pos.y()), ESpriteNoChildClip | ESpriteNoShadows); - + cursorSprite.d->constructCursorSprite(cursorSprite.d->scurs); cursorSprite.d->scurs.Activate(); } @@ -409,7 +409,7 @@ void qt_symbian_set_pointer_sprite(const QCursor& cursor) * RWsPointerCursor, this function is called in response to pointer events * and when QCursor::setPos() is called. * Performance is worse than a real pointer cursor, due to extra context - * switches vs. the window server moving the cursor by itself. + * switches vs. the window server moving the cursor by itself. */ void qt_symbian_move_cursor_sprite() { @@ -421,7 +421,7 @@ void qt_symbian_move_cursor_sprite() /* * Translate from Qt::CursorShape to OS system pointer cursor list index. * Currently we control the implementation of the system pointer cursor list, - * so this function is trivial. That may not always be the case. + * so this function is trivial. That may not always be the case. */ TInt qt_symbian_translate_cursor_shape(Qt::CursorShape shape) { @@ -462,7 +462,7 @@ void qt_symbian_set_cursor(QWidget *w, bool force) /* * Makes the specified cursor appear above a specific native window group * Called from QSymbianControl and QApplication::restoreOverrideCursor - * + * * Window server is needed for this, so there is no equivalent when using * the sprite workaround. */ @@ -486,7 +486,7 @@ void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &nod /* * Makes the specified cursor appear above a specific native window * Called from QSymbianControl and QApplication::restoreOverrideCursor - * + * * Window server is needed for this, so there is no equivalent when using * the sprite workaround. */ diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp index 3d6ecd2..a8d3ac5 100644 --- a/src/gui/kernel/qdnd_s60.cpp +++ b/src/gui/kernel/qdnd_s60.cpp @@ -277,7 +277,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) qApp->installEventFilter(this); - global_accepted_action = Qt::MoveAction; + global_accepted_action = defaultAction(dragPrivate()->possible_actions, Qt::NoModifier); qt_symbian_dnd_dragging = true; eventLoop = new QEventLoop; @@ -288,7 +288,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) #ifndef QT_NO_CURSOR qt_symbian_set_cursor_visible(false); - + overrideCursor = QCursor(); //deref the cursor data qt_symbian_dnd_dragging = false; #endif diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 7b9cc9a..2ff6d65 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -49,6 +49,8 @@ #include "qmime.h" #include "qdnd_p.h" #include "qevent_p.h" +#include "qgesture.h" +#include "qgesture_p.h" QT_BEGIN_NAMESPACE @@ -3357,6 +3359,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) { case QEvent::ChildRemoved: n = n ? n : "ChildRemoved"; dbg.nospace() << "QChildEvent(" << n << ", " << (static_cast<const QChildEvent*>(e))->child(); return dbg.space(); + case QEvent::Gesture: + n = "Gesture"; + break; default: dbg.nospace() << "QEvent(" << (const void *)e << ", type = " << e->type() << ')'; return dbg.space(); @@ -3558,6 +3563,7 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) \brief The QTouchEvent class contains parameters that describe a touch event. \since 4.6 \ingroup events + \ingroup multitouch \section1 Enabling Touch Events @@ -4186,4 +4192,170 @@ QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::T return *this; } +/*! + \class QGestureEvent + \since 4.6 + \ingroup events + \ingroup gestures + + \brief The QGestureEvent class provides the description of triggered gestures. + + The QGestureEvent class contains a list of gestures, which can be obtained using the + allGestures() function. + + The gestures are either active or canceled. A list of those that are currently being + executed can be obtained using the activeGestures() function. A list of those which + were previously active and have been canceled can be accessed using the + canceledGestures() function. A gesture might be canceled if the current window loses + focus, for example, or because of a timeout, or for other reasons. + + If the event handler does not accept the event by calling the generic + QEvent::accept() function, all individual QGesture object that were not accepted + will be propagated up the parent widget chain until a widget accepts them + individually, by calling QGestureEvent::accept() for each of them, or an event + filter consumes the event. + + \sa QGesture, QGestureRecognizer, + QWidget::grabGesture(), QGraphicsObject::grabGesture() +*/ + +/*! + Creates new QGestureEvent containing a list of \a gestures. +*/ +QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures) + : QEvent(QEvent::Gesture), gestures_(gestures) +{ +} + +/*! + Returns all gestures that are delivered in the event. +*/ +QList<QGesture *> QGestureEvent::allGestures() const +{ + return gestures_; +} + +/*! + Returns a gesture object by \a type. +*/ +QGesture *QGestureEvent::gesture(Qt::GestureType type) const +{ + for(int i = 0; i < gestures_.size(); ++i) + if (gestures_.at(i)->gestureType() == type) + return gestures_.at(i); + return 0; +} + +/*! + Returns a list of active (not canceled) gestures. +*/ +QList<QGesture *> QGestureEvent::activeGestures() const +{ + return gestures_; +} + +/*! + Returns a list of canceled gestures. +*/ +QList<QGesture *> QGestureEvent::canceledGestures() const +{ + return gestures_; +} + +/*! + Sets the accept flag of the given \a gesture object to the specified \a value. + + Setting the accept flag indicates that the event receiver wants the \a gesture. + Unwanted gestures may be propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gesture)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gesture)}. +*/ +void QGestureEvent::setAccepted(QGesture *gesture, bool value) +{ + setAccepted(false); + if (gesture) + gesture->d_func()->accept = value; +} + +/*! + Sets the accept flag of the given \a gesture object, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gesture, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(QGesture *gesture) +{ + setAccepted(gesture, true); +} + +/*! + Clears the accept flag parameter of the given \a gesture object, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propgated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(QGesture *gesture) +{ + setAccepted(gesture, false); +} + +/*! + Returns true if the \a gesture is accepted; otherwise returns false. +*/ +bool QGestureEvent::isAccepted(QGesture *gesture) const +{ + return gesture ? gesture->d_func()->accept : false; +} + +#ifdef Q_NO_USING_KEYWORD +/*! + \fn void QGestureEvent::setAccepted(bool accepted) + + Sets or clears the event's internal flag that determines whether it should + be delivered to other objects. + + Calling this function with a value of true for \a accepted indicates that the + caller has accepted the event and that it should not be propagated further. + Calling this function with a value of false indicates that the caller has + ignored the event and that it should be delivered to other objects. + + For convenience, the accept flag can also be set with accept(), and cleared + with ignore(). + + \sa QEvent::accepted +*/ +/*! + \fn bool QGestureEvent::isAccepted() const + + Returns true is the event has been accepted; otherwise returns false. + + \sa QEvent::accepted +*/ +/*! + \fn void QGestureEvent::accept() + + Accepts the event, the equivalent of calling setAccepted(true). + + \sa QEvent::accept() +*/ +/*! + \fn void QGestureEvent::ignore() + + Ignores the event, the equivalent of calling setAccepted(false). + + \sa QEvent::ignore() +*/ +#endif + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 4396766..3516222 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -819,6 +819,40 @@ protected: friend class QApplicationPrivate; }; +class QGesture; +class Q_GUI_EXPORT QGestureEvent : public QEvent +{ +public: + QGestureEvent(const QList<QGesture *> &gestures); + + QList<QGesture *> allGestures() const; + QGesture *gesture(Qt::GestureType type) const; + + QList<QGesture *> activeGestures() const; + QList<QGesture *> canceledGestures() const; + +#ifdef Q_NO_USING_KEYWORD + inline void setAccepted(bool accepted) { QEvent::setAccepted(accepted); } + inline bool isAccepted() const { return QEvent::isAccepted(); } + + inline void accept() { QEvent::accept(); } + inline void ignore() { QEvent::ignore(); } +#else + using QEvent::setAccepted; + using QEvent::isAccepted; + using QEvent::accept; + using QEvent::ignore; +#endif + + void setAccepted(QGesture *, bool); + void accept(QGesture *); + void ignore(QGesture *); + bool isAccepted(QGesture *) const; + +private: + QList<QGesture *> gestures_; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index 7152705..c9dd949 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -136,14 +136,19 @@ void QEventDispatcherMacPrivate::activateTimer(CFRunLoopTimerRef, void *info) if (tmr == 0 || tmr->pending == true) return; // Can't send another timer event if it's pending. - tmr->pending = true; - QTimerEvent e(tmr->id); - qt_sendSpontaneousEvent(tmr->obj, &e); - // Get the value again in case the timer gets unregistered during the sendEvent. - tmr = macTimerHash.value(timerID); - if (tmr != 0) - tmr->pending = false; + if (blockSendPostedEvents) { + QCoreApplication::postEvent(tmr->obj, new QTimerEvent(tmr->id)); + } else { + tmr->pending = true; + QTimerEvent e(tmr->id); + qt_sendSpontaneousEvent(tmr->obj, &e); + // Get the value again in case the timer gets unregistered during the sendEvent. + tmr = macTimerHash.value(timerID); + if (tmr != 0) + tmr->pending = false; + } + } void QEventDispatcherMac::registerTimer(int timerId, int interval, QObject *obj) @@ -767,7 +772,7 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession() // Sadly, we need to introduce this little event flush // to stop dialogs from blinking/poping in front if a // modal session restart was needed: - while (NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + while (NSEvent *event = [NSApp nextEventMatchingMask:0 untilDate:nil inMode:NSDefaultRunLoopMode dequeue: YES]) { @@ -942,7 +947,7 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) { - if (blockSendPostedEvents) { + if (blockSendPostedEvents || d->interrupt) { CFRunLoopSourceSignal(d->postedEventsSource); } else { if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 237ce46..fc8df49 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -40,274 +40,585 @@ ****************************************************************************/ #include "qgesture.h" -#include <private/qgesture_p.h> -#include "qgraphicsitem.h" +#include "private/qgesture_p.h" QT_BEGIN_NAMESPACE - -class QEventFilterProxyGraphicsItem : public QGraphicsItem -{ -public: - QEventFilterProxyGraphicsItem(QGesture *g) - : gesture(g) - { - } - bool sceneEventFilter(QGraphicsItem *, QEvent *event) - { - return gesture ? gesture->filterEvent(event) : false; - } - QRectF boundingRect() const { return QRectF(); } - void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { } - -private: - QGesture *gesture; -}; - -/*! + /*! \class QGesture \since 4.6 - \preliminary + \ingroup gestures + + \brief The QGesture class represents a gesture, containing properties that + describe the corresponding user input. - \brief The QGesture class is the base class for implementing custom - gestures. + Gesture objects are not constructed directly by developers. They are created by + the QGestureRecognizer object that is registered with the application; see + QApplication::registerGestureRecognizer(). - This class represents both an object that recognizes a gesture out of a set - of input events (a gesture recognizer), and a gesture object itself that - can be used to get extended information about the triggered gesture. + \section1 Gesture Properties The class has a list of properties that can be queried by the user to get - some gesture-specific parameters (for example, an offset of a Pan gesture). + some gesture-specific arguments. For example, the pinch gesture has a scale + factor that is exposed as a property. + + Developers of custom gesture recognizers can add additional properties in + order to provide additional information about a gesture. This can be done + by adding new dynamic properties to a QGesture object, or by subclassing + the QGesture class (or one of its subclasses). + + \section1 Lifecycle of a Gesture Object - Usually gesture recognizer implements a state machine, storing its state - internally in the recognizer object. The recognizer receives input events - through the \l{QGesture::}{filterEvent()} virtual function and decides - whether the event should change the state of the recognizer by emitting an - appropriate signal. + A QGesture instance is created when the application calls QWidget::grabGesture() + or QGraphicsObject::grabGesture() to configure a widget or graphics object (the + target object) for gesture input. One gesture object is created for each target + object. - Input events should be either fed to the recognizer one by one with a - filterEvent() function, or the gesture recognizer should be attached to an - object it filters events for by specifying it as a parent object. The - QGesture object installs itself as an event filter to the parent object - automatically, the unsetObject() function should be used to remove an event - filter from the parent object. To make a - gesture that operates on a QGraphicsItem, both the appropriate QGraphicsView - should be passed as a parent object and setGraphicsItem() functions should - be used to attach a gesture to a graphics item. + The registered gesture recognizer monitors the input events for the target + object via its \l{QGestureRecognizer::}{filterEvent()} function, updating the + properties of the gesture object as required. - This is a base class, to create a custom gesture type, you should subclass - it and implement its pure virtual functions. + The gesture object may be delivered to the target object in a QGestureEvent if + the corresponding gesture is active or has just been canceled. Each event that + is delivered contains a list of gesture objects, since support for more than + one gesture may be enabled for the target object. Due to the way events are + handled in Qt, gesture events may be filtered by other objects. - \sa QPanGesture + \sa QGestureEvent, QGestureRecognizer */ -/*! \fn bool QGesture::filterEvent(QEvent *event) +/*! + Constructs a new gesture object with the given \a parent. + + QGesture objects are created by gesture recognizers in the + QGestureRecognizer::createGesture() function. +*/ +QGesture::QGesture(QObject *parent) + : QObject(*new QGesturePrivate, parent) +{ + d_func()->gestureType = Qt::CustomGesture; +} + +/*! + \internal +*/ +QGesture::QGesture(QGesturePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} - Parses input \a event and emits a signal when detects a gesture. +/*! + Destroys the gesture object. +*/ +QGesture::~QGesture() +{ +} - In your reimplementation of this function, if you want to filter the \a - event out, i.e. stop it being handled further, return true; otherwise - return false; +/*! + \property QGesture::state + \brief the current state of the gesture +*/ - This is a pure virtual function that needs to be implemented in subclasses. +/*! + \property QGesture::gestureType + \brief the type of the gesture */ -/*! \fn void QGesture::started() +/*! + \property QGesture::hotSpot + + \brief The point that is used to find the receiver for the gesture event. + + If the hot-spot is not set, the targetObject is used as the receiver of the + gesture event. +*/ - The signal is emitted when the gesture is started. Extended information - about the gesture is contained in the signal sender object. +/*! + \property QGesture::hasHotSpot + \brief whether the gesture has a hot-spot +*/ - In addition to started(), a triggered() signal should also be emitted. +/*! + \property QGesture::targetObject + \brief the target object which will receive the gesture event if the hotSpot is + not set */ -/*! \fn void QGesture::triggered() +Qt::GestureType QGesture::gestureType() const +{ + return d_func()->gestureType; +} + +Qt::GestureState QGesture::state() const +{ + return d_func()->state; +} + +QObject *QGesture::targetObject() const +{ + return d_func()->targetObject; +} + +void QGesture::setTargetObject(QObject *value) +{ + d_func()->targetObject = value; +} + +QPointF QGesture::hotSpot() const +{ + return d_func()->hotSpot; +} + +void QGesture::setHotSpot(const QPointF &value) +{ + Q_D(QGesture); + d->hotSpot = value; + d->isHotSpotSet = true; +} + +bool QGesture::hasHotSpot() const +{ + return d_func()->isHotSpotSet; +} + +void QGesture::unsetHotSpot() +{ + d_func()->isHotSpotSet = false; +} + +/*! + \class QPanGesture + \since 4.6 + \brief The QPanGesture class describes a panning gesture made by the user. + \ingroup gestures - The signal is emitted when the gesture is detected. Extended information - about the gesture is contained in the signal sender object. + \image pangesture.png + + \sa {Gestures Programming}, QPinchGesture, QSwipeGesture */ -/*! \fn void QGesture::finished() +/*! + \property QPanGesture::totalOffset + \brief the total offset from the first input position to the current input + position - The signal is emitted when the gesture is finished. Extended information - about the gesture is contained in the signal sender object. + The total offset measures the total change in position of the user's input + covered by the gesture on the input device. */ -/*! \fn void QGesture::canceled() +/*! + \property QPanGesture::lastOffset + \brief the last offset recorded for this gesture + + The last offset contains the change in position of the user's input as + reported in the \l offset property when a previous gesture event was + delivered for this gesture. - The signal is emitted when the gesture is canceled, for example the - reset() function is called while the gesture was in the process of - emitting a triggered() signal. Extended information about the - gesture is contained in the sender object. + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains a zero size. */ /*! - Creates a new gesture handler object and marks it as a child of \a - parent. \a gestureTarget is the object that the gesture will watch - for events. + \property QPanGesture::offset + \brief the offset from the previous input position to the current input + position - The \a parent object is also the default event source for the - gesture, meaning that the gesture installs itself as an event filter - for the \a parent. + The offset measures the change in position of the user's input on the + input device. +*/ - \sa setGraphicsItem() +/*! + \property QPanGesture::acceleration */ -QGesture::QGesture(QObject *gestureTarget, QObject *parent) - : QObject(*new QGesturePrivate, parent) + +/*! + \internal +*/ +QPanGesture::QPanGesture(QObject *parent) + : QGesture(*new QPanGesturePrivate, parent) { - setGestureTarget(gestureTarget); + d_func()->gestureType = Qt::PanGesture; } -/*! \internal - */ -QGesture::QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent) - : QObject(dd, parent) +QSizeF QPanGesture::totalOffset() const { - setGestureTarget(gestureTarget); + return d_func()->totalOffset; } -/*! - Destroys the gesture object. -*/ -QGesture::~QGesture() +QSizeF QPanGesture::lastOffset() const { + return d_func()->lastOffset; } -/*! - \property QGesture::gestureTarget +QSizeF QPanGesture::offset() const +{ + return d_func()->offset; +} - Gesture target is the object that the gesture will watch for events. - Typically this means that the gesture installs an event filter on the - target object. -*/ -void QGesture::setGestureTarget(QObject *object) +qreal QPanGesture::acceleration() const { - d_func()->setupGestureTarget(object); + return d_func()->acceleration; } -QObject* QGesture::gestureTarget() const + +void QPanGesture::setTotalOffset(const QSizeF &value) { - return d_func()->gestureTarget; + d_func()->totalOffset = value; } -void QGesturePrivate::setupGestureTarget(QObject *object) +void QPanGesture::setLastOffset(const QSizeF &value) { - Q_Q(QGesture); - if (gestureTarget) - gestureTarget->removeEventFilter(q); - if (object) - object->installEventFilter(q); - gestureTarget = object; + d_func()->lastOffset = value; } -/*! \internal - */ -bool QGesture::eventFilter(QObject *receiver, QEvent *event) +void QPanGesture::setOffset(const QSizeF &value) { - Q_D(QGesture); - if (d->graphicsItem && receiver == parent()) - return false; - return filterEvent(event); + d_func()->offset = value; +} + +void QPanGesture::setAcceleration(qreal value) +{ + d_func()->acceleration = value; } /*! - \property QGesture::state + \class QPinchGesture + \since 4.6 + \brief The QPinchGesture class describes a pinch gesture made my the user. + \ingroup multitouch + \ingroup gestures + + A pinch gesture is a form of multitouch user input in which the user typically + touches two points on the input device with a thumb and finger, before moving + them closer together or further apart to change the scale factor, zoom, or level + of detail of the user interface. + + \image pinchgesture.png - \brief The current state of the gesture. + Instead of repeatedly applying the same pinching gesture, the user may + continue to touch the input device in one place, and apply a second touch + to a new point, continuing the gesture. When this occurs, gesture events + will continue to be delivered to the target object, containing an instance + of QPinchGesture in the Qt::GestureUpdated state. + + \sa {Gestures Programming}, QPanGesture, QSwipeGesture */ /*! - Returns the gesture recognition state. - */ -Qt::GestureState QGesture::state() const + \enum QPinchGesture::WhatChange + + This enum describes the changes that can occur to the properties of + the gesture object. + + \value ScaleFactorChanged The scale factor held by scaleFactor changed. + \value RotationAngleChanged The rotation angle held by rotationAngle changed. + \value CenterPointChanged The center point held by centerPoint changed. + + \sa whatChanged +*/ + +/*! + \property QPinchGesture::whatChanged + \brief the property of the gesture that has changed + + This property indicates which of the other properties has changed since + the previous gesture event included information about this gesture. You + can use this information to determine which aspect of your user interface + needs to be updated. + + \sa scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::totalScaleFactor + \brief the total scale factor + + The total scale factor measures the total change in scale factor from the + original value to the current scale factor. + + \sa scaleFactor, lastScaleFactor +*/ +/*! + \property QPinchGesture::lastScaleFactor + \brief the last scale factor recorded for this gesture + + The last scale factor contains the scale factor reported in the + \l scaleFactor property when a previous gesture event included + information about this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains zero. + + \sa scaleFactor, totalScaleFactor +*/ +/*! + \property QPinchGesture::scaleFactor + \brief the current scale factor + + The scale factor measures the scale factor associated with the distance + between two of the user's inputs on a multitouch device. + + \sa totalScaleFactor, lastScaleFactor +*/ + +/*! + \property QPinchGesture::totalRotationAngle + \brief the total angle covered by the gesture + + This total angle measures the complete angle covered by the gesture. Usually, this + is equal to the value held by the \l rotationAngle property, except in the case where + the user performs multiple rotations by removing and repositioning one of the touch + points, as described above. In this case, the total angle will be the sum of the + rotation angles for the multiple stages of the gesture. + + \sa rotationAngle, lastRotationAngle +*/ +/*! + \property QPinchGesture::lastRotationAngle + \brief the last reported angle covered by the gesture motion + + The last rotation angle is the angle as reported in the \l rotationAngle property + when a previous gesture event was delivered for this gesture. + + \sa rotationAngle, totalRotationAngle +*/ +/*! + \property QPinchGesture::rotationAngle + \brief the angle covered by the gesture motion + + \sa totalRotationAngle, lastRotationAngle +*/ + +/*! + \property QPinchGesture::startCenterPoint + \brief the starting position of the center point + + \sa centerPoint, lastCenterPoint +*/ +/*! + \property QPinchGesture::lastCenterPoint + \brief the last position of the center point recorded for this gesture + + \sa centerPoint, startCenterPoint +*/ +/*! + \property QPinchGesture::centerPoint + \brief the current center point + + The center point is the midpoint between the two input points in the gesture. + + \sa startCenterPoint, lastCenterPoint +*/ + +/*! + \internal +*/ +QPinchGesture::QPinchGesture(QObject *parent) + : QGesture(*new QPinchGesturePrivate, parent) { - return d_func()->state; + d_func()->gestureType = Qt::PinchGesture; } -/*! - Sets this gesture's recognition state to \a state and emits appropriate - signals. +QPinchGesture::WhatChanged QPinchGesture::whatChanged() const +{ + return d_func()->whatChanged; +} + +void QPinchGesture::setWhatChanged(QPinchGesture::WhatChanged value) +{ + d_func()->whatChanged = value; +} - This functions emits the signals according to the old state and the new - \a state, and it should be called after all the internal properties have been - initialized. - \sa started(), triggered(), finished(), canceled() - */ -void QGesture::updateState(Qt::GestureState state) +QPointF QPinchGesture::startCenterPoint() const { - Q_D(QGesture); - if (d->state == state) { - if (state == Qt::GestureUpdated) - emit triggered(); - return; - } - const Qt::GestureState oldState = d->state; - if (state != Qt::NoGesture && oldState > state) { - // comparing the state as ints: state should only be changed from - // started to (optionally) updated and to finished. - d->state = state; - qWarning("QGesture::updateState: incorrect new state"); - return; - } - if (oldState == Qt::NoGesture) { - d->state = Qt::GestureStarted; - emit started(); - } - d->state = state; - if (state == Qt::GestureUpdated) - emit triggered(); - else if (state == Qt::GestureFinished) - emit finished(); - else if (state == Qt::NoGesture) - emit canceled(); - - if (state == Qt::GestureFinished) { - // gesture is finished, so we reset the internal state. - d->state = Qt::NoGesture; - } -} - -/*! - Sets the \a graphicsItem the gesture is filtering events for. - - The gesture will install an event filter to the \a graphicsItem and - redirect them to the filterEvent() function. - - \sa graphicsItem() -*/ -void QGesture::setGraphicsItem(QGraphicsItem *graphicsItem) + return d_func()->startCenterPoint; +} + +QPointF QPinchGesture::lastCenterPoint() const { - Q_D(QGesture); - if (d->graphicsItem && d->eventFilterProxyGraphicsItem) - d->graphicsItem->removeSceneEventFilter(d->eventFilterProxyGraphicsItem); - d->graphicsItem = graphicsItem; - if (!d->eventFilterProxyGraphicsItem) - d->eventFilterProxyGraphicsItem = new QEventFilterProxyGraphicsItem(this); - if (graphicsItem) - graphicsItem->installSceneEventFilter(d->eventFilterProxyGraphicsItem); + return d_func()->lastCenterPoint; +} + +QPointF QPinchGesture::centerPoint() const +{ + return d_func()->centerPoint; +} + +void QPinchGesture::setStartCenterPoint(const QPointF &value) +{ + d_func()->startCenterPoint = value; +} + +void QPinchGesture::setLastCenterPoint(const QPointF &value) +{ + d_func()->lastCenterPoint = value; +} + +void QPinchGesture::setCenterPoint(const QPointF &value) +{ + d_func()->centerPoint = value; +} + + +qreal QPinchGesture::totalScaleFactor() const +{ + return d_func()->totalScaleFactor; +} + +qreal QPinchGesture::lastScaleFactor() const +{ + return d_func()->lastScaleFactor; +} + +qreal QPinchGesture::scaleFactor() const +{ + return d_func()->scaleFactor; +} + +void QPinchGesture::setTotalScaleFactor(qreal value) +{ + d_func()->totalScaleFactor = value; +} + +void QPinchGesture::setLastScaleFactor(qreal value) +{ + d_func()->lastScaleFactor = value; +} + +void QPinchGesture::setScaleFactor(qreal value) +{ + d_func()->scaleFactor = value; +} + + +qreal QPinchGesture::totalRotationAngle() const +{ + return d_func()->totalRotationAngle; +} + +qreal QPinchGesture::lastRotationAngle() const +{ + return d_func()->lastRotationAngle; +} + +qreal QPinchGesture::rotationAngle() const +{ + return d_func()->rotationAngle; +} + +void QPinchGesture::setTotalRotationAngle(qreal value) +{ + d_func()->totalRotationAngle = value; +} + +void QPinchGesture::setLastRotationAngle(qreal value) +{ + d_func()->lastRotationAngle = value; +} + +void QPinchGesture::setRotationAngle(qreal value) +{ + d_func()->rotationAngle = value; } /*! - Returns the graphics item the gesture is filtering events for. + \class QSwipeGesture + \since 4.6 + \brief The QSwipeGesture class describes a swipe gesture made by the user. + \ingroup gestures + + \image swipegesture.png - \sa setGraphicsItem() + \sa {Gestures Programming}, QPanGesture, QPinchGesture */ -QGraphicsItem* QGesture::graphicsItem() const + +/*! + \enum QSwipeGesture::SwipeDirection + + This enum describes the possible directions for the gesture's motion + along the horizontal and vertical axes. + + \value NoDirection The gesture had no motion associated with it on a particular axis. + \value Left The gesture involved a horizontal motion to the left. + \value Right The gesture involved a horizontal motion to the right. + \value Up The gesture involved an upward vertical motion. + \value Down The gesture involved a downward vertical motion. +*/ + +/*! + \property QSwipeGesture::horizontalDirection + \brief the horizontal direction of the gesture + + If the gesture has a horizontal component, the horizontal direction + is either Left or Right; otherwise, it is NoDirection. + + \sa verticalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::verticalDirection + \brief the vertical direction of the gesture + + If the gesture has a vertical component, the vertical direction + is either Up or Down; otherwise, it is NoDirection. + + \sa horizontalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::swipeAngle + \brief the angle of the motion associated with the gesture + + If the gesture has either a horizontal or vertical component, the + swipe angle describes the angle between the direction of motion and the + x-axis as defined using the standard widget + \l{The Coordinate System}{coordinate system}. + + \sa horizontalDirection, verticalDirection +*/ + +/*! + \internal +*/ +QSwipeGesture::QSwipeGesture(QObject *parent) + : QGesture(*new QSwipeGesturePrivate, parent) +{ + d_func()->gestureType = Qt::SwipeGesture; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const { - return d_func()->graphicsItem; + Q_D(const QSwipeGesture); + if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 90 || d->swipeAngle > 270) + return QSwipeGesture::Right; + else + return QSwipeGesture::Left; } -/*! \fn void QGesture::reset() +QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle <= 0 || d->swipeAngle == 180) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 180) + return QSwipeGesture::Up; + else + return QSwipeGesture::Down; +} - Resets the internal state of the gesture. This function might be called by - the filterEvent() implementation in a derived class, or by the user to - cancel a gesture. The base class implementation calls - updateState(Qt::NoGesture) which emits the canceled() - signal if the state() of the gesture indicated it was active. -*/ -void QGesture::reset() +qreal QSwipeGesture::swipeAngle() const +{ + return d_func()->swipeAngle; +} + +void QSwipeGesture::setSwipeAngle(qreal value) { - updateState(Qt::NoGesture); + d_func()->swipeAngle = value; } QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index 440565e..02eb526 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -51,11 +51,12 @@ QT_BEGIN_HEADER +Q_DECLARE_METATYPE(Qt::GestureState) + QT_BEGIN_NAMESPACE QT_MODULE(Gui) -class QGraphicsItem; class QGesturePrivate; class Q_GUI_EXPORT QGesture : public QObject { @@ -63,37 +64,150 @@ class Q_GUI_EXPORT QGesture : public QObject Q_DECLARE_PRIVATE(QGesture) Q_PROPERTY(Qt::GestureState state READ state) - Q_PROPERTY(QObject* gestureTarget READ gestureTarget WRITE setGestureTarget) + Q_PROPERTY(Qt::GestureType gestureType READ gestureType) + Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) + Q_PROPERTY(bool hasHotSpot READ hasHotSpot) + Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) public: - explicit QGesture(QObject *gestureTarget = 0, QObject *parent = 0); + explicit QGesture(QObject *parent = 0); ~QGesture(); - virtual bool filterEvent(QEvent *event) = 0; + Qt::GestureType gestureType() const; - void setGestureTarget(QObject *object); - QObject* gestureTarget() const; + Qt::GestureState state() const; - void setGraphicsItem(QGraphicsItem *); - QGraphicsItem *graphicsItem() const; + QObject *targetObject() const; + void setTargetObject(QObject *value); - Qt::GestureState state() const; + QPointF hotSpot() const; + void setHotSpot(const QPointF &value); + bool hasHotSpot() const; + void unsetHotSpot(); protected: - QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent); - bool eventFilter(QObject*, QEvent*); + QGesture(QGesturePrivate &dd, QObject *parent); + +private: + friend class QGestureEvent; + friend class QGestureRecognizer; + friend class QGestureManager; +}; - virtual void reset(); - void updateState(Qt::GestureState state); +class QPanGesturePrivate; +class Q_GUI_EXPORT QPanGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPanGesture) -Q_SIGNALS: - void started(); - void triggered(); - void finished(); - void canceled(); + Q_PROPERTY(QSizeF totalOffset READ totalOffset WRITE setTotalOffset) + Q_PROPERTY(QSizeF lastOffset READ lastOffset WRITE setLastOffset) + Q_PROPERTY(QSizeF offset READ offset WRITE setOffset) + Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration) -private: - friend class QWidget; +public: + QPanGesture(QObject *parent = 0); + + QSizeF totalOffset() const; + QSizeF lastOffset() const; + QSizeF offset() const; + qreal acceleration() const; + + void setTotalOffset(const QSizeF &value); + void setLastOffset(const QSizeF &value); + void setOffset(const QSizeF &value); + void setAcceleration(qreal value); + + friend class QPanGestureRecognizer; + friend class QWinNativePanGestureRecognizer; +}; + +class QPinchGesturePrivate; +class Q_GUI_EXPORT QPinchGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPinchGesture) + +public: + enum WhatChange { + ScaleFactorChanged = 0x1, + RotationAngleChanged = 0x2, + CenterPointChanged = 0x4 + }; + Q_DECLARE_FLAGS(WhatChanged, WhatChange) + + Q_PROPERTY(WhatChanged whatChanged READ whatChanged WRITE setWhatChanged) + + Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor WRITE setTotalScaleFactor) + Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor WRITE setLastScaleFactor) + Q_PROPERTY(qreal scaleFactor READ scaleFactor WRITE setScaleFactor) + + Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle WRITE setTotalRotationAngle) + Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle WRITE setLastRotationAngle) + Q_PROPERTY(qreal rotationAngle READ rotationAngle WRITE setRotationAngle) + + Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint WRITE setStartCenterPoint) + Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint WRITE setLastCenterPoint) + Q_PROPERTY(QPointF centerPoint READ centerPoint WRITE setCenterPoint) + +public: + QPinchGesture(QObject *parent = 0); + + WhatChanged whatChanged() const; + void setWhatChanged(WhatChanged value); + + QPointF startCenterPoint() const; + QPointF lastCenterPoint() const; + QPointF centerPoint() const; + void setStartCenterPoint(const QPointF &value); + void setLastCenterPoint(const QPointF &value); + void setCenterPoint(const QPointF &value); + + qreal totalScaleFactor() const; + qreal lastScaleFactor() const; + qreal scaleFactor() const; + void setTotalScaleFactor(qreal value); + void setLastScaleFactor(qreal value); + void setScaleFactor(qreal value); + + qreal totalRotationAngle() const; + qreal lastRotationAngle() const; + qreal rotationAngle() const; + void setTotalRotationAngle(qreal value); + void setLastRotationAngle(qreal value); + void setRotationAngle(qreal value); + + friend class QPinchGestureRecognizer; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPinchGesture::WhatChanged) + +QT_BEGIN_NAMESPACE + +class QSwipeGesturePrivate; +class Q_GUI_EXPORT QSwipeGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSwipeGesture) + Q_ENUMS(SwipeDirection) + + Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection STORED false) + Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection STORED false) + Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle) + +public: + enum SwipeDirection { NoDirection, Left, Right, Up, Down }; + QSwipeGesture(QObject *parent = 0); + + SwipeDirection horizontalDirection() const; + SwipeDirection verticalDirection() const; + + qreal swipeAngle() const; + void setSwipeAngle(qreal value); + + friend class QSwipeGestureRecognizer; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index 52e399f..7f69a4e 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -61,29 +61,83 @@ QT_BEGIN_NAMESPACE -class QObject; -class QGraphicsItem; class QGesturePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QGesture) public: QGesturePrivate() - : gestureTarget(0), graphicsItem(0), eventFilterProxyGraphicsItem(0), - state(Qt::NoGesture), implicitGesture(false) + : gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false), + targetObject(0), accept(true) { } - virtual void setupGestureTarget(QObject *o); + Qt::GestureType gestureType; + Qt::GestureState state; + QPointF hotSpot; + bool isHotSpotSet; + QObject *targetObject; + bool accept; +}; - QPointer<QObject> gestureTarget; - QGraphicsItem *graphicsItem; - QGraphicsItem *eventFilterProxyGraphicsItem; +class QPanGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPanGesture) - Qt::GestureState state; +public: + QPanGesturePrivate() + : acceleration(0) + { + } + + QSizeF totalOffset; + QSizeF lastOffset; + QSizeF offset; + QPoint lastPosition; + qreal acceleration; +}; + +class QPinchGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPinchGesture) + +public: + QPinchGesturePrivate() + : whatChanged(0), totalScaleFactor(0), lastScaleFactor(0), scaleFactor(0), + totalRotationAngle(0), lastRotationAngle(0), rotationAngle(0) + { + } + + QPinchGesture::WhatChanged whatChanged; + + QPointF startCenterPoint; + QPointF lastCenterPoint; + QPointF centerPoint; + + qreal totalScaleFactor; + qreal lastScaleFactor; + qreal scaleFactor; + + qreal totalRotationAngle; + qreal lastRotationAngle; + qreal rotationAngle; +}; + +class QSwipeGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QSwipeGesture) + +public: + QSwipeGesturePrivate() + : horizontalDirection(QSwipeGesture::NoDirection), + verticalDirection(QSwipeGesture::NoDirection), + swipeAngle(0) + { + } - // the flag specifies if the gesture was created implicitely by Qt. - bool implicitGesture; + QSwipeGesture::SwipeDirection horizontalDirection; + QSwipeGesture::SwipeDirection verticalDirection; + qreal swipeAngle; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp new file mode 100644 index 0000000..0f0aef2 --- /dev/null +++ b/src/gui/kernel/qgesturemanager.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** 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 QtGui module 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 "private/qgesturemanager_p.h" +#include "private/qstandardgestures_p.h" +#include "private/qwidget_p.h" +#include "private/qgesture_p.h" +#include "private/qgraphicsitem_p.h" +#include "qgesture.h" +#include "qevent.h" +#include "qgraphicsitem.h" + +#ifdef Q_WS_MAC +#include "qmacgesturerecognizer_mac_p.h" +#endif + +#include "qdebug.h" + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +QT_BEGIN_NAMESPACE + +QGestureManager::QGestureManager(QObject *parent) + : QObject(parent), state(NotGesture), lastCustomGestureId(0) +{ + qRegisterMetaType<Qt::GestureState>(); + +#if defined(Q_WS_MAC) + registerGestureRecognizer(new QMacSwipeGestureRecognizer); + registerGestureRecognizer(new QMacPinchGestureRecognizer); + #if defined(QT_MAC_USE_COCOA) + registerGestureRecognizer(new QMacPanGestureRecognizer); + #endif +#else + registerGestureRecognizer(new QPanGestureRecognizer); +#endif +} + +QGestureManager::~QGestureManager() +{ + +} + +Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + QGesture *dummy = recognizer->createGesture(0); + if (!dummy) { + qWarning("QGestureManager::registerGestureRecognizer: the recognizer doesn't provide gesture object"); + return Qt::GestureType(0); + } + Qt::GestureType type = dummy->gestureType(); + if (type == Qt::CustomGesture) { + // generate a new custom gesture id + ++lastCustomGestureId; + type = Qt::GestureType(Qt::CustomGesture + lastCustomGestureId); + } + recognizers.insertMulti(type, recognizer); + delete dummy; + return type; +} + +void QGestureManager::unregisterGestureRecognizer(Qt::GestureType) +{ + +} + +QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) +{ + // if the widget is being deleted we should be carefull and not to + // create a new state, as it will create QWeakPointer which doesnt work + // from the destructor. + if (object->isWidgetType()) { + if (static_cast<QWidget *>(object)->d_func()->data.in_destructor) + return 0; + } + + QWeakPointer<QGesture> state = objectGestures.value(QGestureManager::ObjectGesture(object, type)); + if (!state) { + QGestureRecognizer *recognizer = recognizers.value(type); + if (recognizer) { + state = recognizer->createGesture(object); + if (!state) + return 0; + if (state.data()->gestureType() == Qt::CustomGesture) { + // if the recognizer didn't fill in the gesture type, then this + // is a custom gesture with autogenerated it and we fill it. + state.data()->d_func()->gestureType = type; + } + objectGestures.insert(QGestureManager::ObjectGesture(object, type), state); + gestureToRecognizer[state.data()] = recognizer; + } + } + return state.data(); +} + +bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) +{ + QSet<QGesture *> triggeredGestures; + QSet<QGesture *> finishedGestures; + QSet<QGesture *> newMaybeGestures; + QSet<QGesture *> canceledGestures; + QSet<QGesture *> notGestures; + + QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(receiver); + if (receiver->isWidgetType() || graphicsObject) { + QMap<QObject *, Qt::GestureType> contexts; + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + if (!w->d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->parentWidget(); + while (w) + { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) + contexts.insertMulti(w, it.key()); + } + w = w->parentWidget(); + } + } else { + QGraphicsObject *item = graphicsObject; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the widget tree + item = item->parentObject(); + while (item) + { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) + contexts.insertMulti(item, it.key()); + } + item = item->parentObject(); + } + } + // filter the event through recognizers + typedef QMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; + for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { + Qt::GestureType gestureType = cit.value(); + QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator + rit = recognizers.lowerBound(gestureType), + re = recognizers.upperBound(gestureType); + for (; rit != re; ++rit) { + QGestureRecognizer *recognizer = rit.value(); + QObject *target = cit.key(); + QGesture *state = getState(target, gestureType); + if (!state) + continue; + QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); + QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; + if (type == QGestureRecognizer::GestureTriggered) { + DEBUG() << "QGestureManager: gesture triggered: " << state; + triggeredGestures << state; + } else if (type == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << state; + finishedGestures << state; + } else if (type == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << state; + newMaybeGestures << state; + } else if (type == QGestureRecognizer::NotGesture) { + DEBUG() << "QGestureManager: not gesture: " << state; + notGestures << state; + } else if (type == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager: gesture ignored the event: " << state; + } else { + DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + } + if (result & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " << state; + //TODO: consume events if asked + } + } + } + } else if (QGesture *state = qobject_cast<QGesture*>(receiver)) { + if (QGestureRecognizer *recognizer = gestureToRecognizer.value(state)) { + QGestureRecognizer::Result result = recognizer->filterEvent(state, state, event); + QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; + if (type == QGestureRecognizer::GestureTriggered) { + DEBUG() << "QGestureManager: gesture triggered: " << state; + triggeredGestures << state; + } else if (type == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << state; + finishedGestures << state; + } else if (type == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << state; + newMaybeGestures << state; + } else if (type == QGestureRecognizer::NotGesture) { + DEBUG() << "QGestureManager: not gesture: " << state; + notGestures << state; + } else if (type == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager: gesture ignored the event: " << state; + } else { + DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + } + } + } else { + return false; + } + + QSet<QGesture *> startedGestures = triggeredGestures - activeGestures; + triggeredGestures &= activeGestures; + + // check if a running gesture switched back to maybe state + QSet<QGesture *> activeToMaybeGestures = activeGestures & newMaybeGestures; + + // check if a running gesture switched back to not gesture state, i.e. were canceled + QSet<QGesture *> activeToCancelGestures = activeGestures & notGestures; + canceledGestures += activeToCancelGestures; + + // start timers for new gestures in maybe state + foreach (QGesture *state, newMaybeGestures) { + QBasicTimer &timer = maybeGestures[state]; + if (!timer.isActive()) + timer.start(3000, this); + } + // kill timers for gestures that were in maybe state + QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures | finishedGestures | canceledGestures | notGestures); + foreach(QGesture *gesture, notMaybeGestures) { + QMap<QGesture *, QBasicTimer>::iterator it = + maybeGestures.find(gesture); + if (it != maybeGestures.end()) { + it.value().stop(); + maybeGestures.erase(it); + } + } + + Q_ASSERT((startedGestures & finishedGestures).isEmpty()); + Q_ASSERT((startedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((startedGestures & canceledGestures).isEmpty()); + Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((finishedGestures & canceledGestures).isEmpty()); + Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty()); + + QSet<QGesture *> notStarted = finishedGestures - activeGestures; + if (!notStarted.isEmpty()) { + // there are some gestures that claim to be finished, but never started. + // probably those are "singleshot" gestures so we'll fake the started state. + foreach (QGesture *gesture, notStarted) + gesture->d_func()->state = Qt::GestureStarted; + deliverEvents(notStarted, receiver); + } + + activeGestures += startedGestures; + // sanity check: all triggered gestures should already be in active gestures list + Q_ASSERT((activeGestures & triggeredGestures).size() == triggeredGestures.size()); + activeGestures -= finishedGestures; + activeGestures -= activeToMaybeGestures; + activeGestures -= canceledGestures; + + // set the proper gesture state on each gesture + foreach (QGesture *gesture, startedGestures) + gesture->d_func()->state = Qt::GestureStarted; + foreach (QGesture *gesture, triggeredGestures) + gesture->d_func()->state = Qt::GestureUpdated; + foreach (QGesture *gesture, finishedGestures) + gesture->d_func()->state = Qt::GestureFinished; + foreach (QGesture *gesture, canceledGestures) + gesture->d_func()->state = Qt::GestureCanceled; + foreach (QGesture *gesture, activeToMaybeGestures) + gesture->d_func()->state = Qt::GestureFinished; + + if (!activeGestures.isEmpty() || !maybeGestures.isEmpty() || + !startedGestures.isEmpty() || !triggeredGestures.isEmpty() || + !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) { + DEBUG() << "QGestureManager::filterEvent:" + << "\n\tactiveGestures:" << activeGestures + << "\n\tmaybeGestures:" << maybeGestures.keys() + << "\n\tstarted:" << startedGestures + << "\n\ttriggered:" << triggeredGestures + << "\n\tfinished:" << finishedGestures + << "\n\tcanceled:" << canceledGestures; + } + + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, receiver); + + // reset gestures that ended + QSet<QGesture *> endedGestures = finishedGestures + canceledGestures; + foreach (QGesture *gesture, endedGestures) { + if (QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0)) { + recognizer->reset(gesture); + } + gestureTargets.remove(gesture); + } + return false; +} + +void QGestureManager::deliverEvents(const QSet<QGesture*> &gestures, QObject *lastReceiver) +{ + if (gestures.isEmpty()) + return; + + // group gestures by widgets + typedef QMap<QObject *, QList<QGesture *> > GesturesPerReceiver; + GesturesPerReceiver groupedGestures; + // for conflicted gestures the key is always the innermost widget (i.e. the child) + GesturesPerReceiver conflictedGestures; + QMultiHash<QObject *, QGesture *> objectGestures; + + foreach (QGesture *gesture, gestures) { + QObject *target = gestureTargets.value(gesture, 0); + if (!target) { + Q_ASSERT(gesture->state() == Qt::GestureStarted); + if (gesture->hasHotSpot()) { + // guess the target using the hotspot of the gesture + QPoint pt = gesture->hotSpot().toPoint(); + if (!pt.isNull()) { + if (QWidget *w = qApp->topLevelAt(pt)) + target = w->childAt(w->mapFromGlobal(pt)); + } + } + if (!target) { + target = gesture->targetObject(); + if (!target) + target = lastReceiver; + } + } + if (target) { + gestureTargets.insert(gesture, target); + if (target->isWidgetType()) + objectGestures.insert(target, gesture); + groupedGestures[target].append(gesture); + } else { + qWarning() << "QGestureManager::deliverEvent: could not find the target for gesture" + << gesture->gestureType(); + } + } + + typedef QMultiHash<QObject *, QGesture *>::const_iterator ObjectGesturesIterator; + for (ObjectGesturesIterator it = objectGestures.begin(), e = objectGestures.end(); it != e; ++it) { + QObject *object1 = it.key(); + QWidget *widget1 = qobject_cast<QWidget *>(object1); + QGraphicsObject *item1 = qobject_cast<QGraphicsObject *>(object1); + QGesture *gesture1 = it.value(); + ObjectGesturesIterator cit = it; + for (++cit; cit != e; ++cit) { + QObject *object2 = cit.key(); + QWidget *widget2 = qobject_cast<QWidget *>(object2); + QGraphicsObject *item2 = qobject_cast<QGraphicsObject *>(object2); + QGesture *gesture2 = cit.value(); + // TODO: ugly, rewrite this. + if ((widget1 && widget2 && widget2->isAncestorOf(widget1)) || + (item1 && item2 && item2->isAncestorOf(item1))) { + groupedGestures[object2].removeOne(gesture2); + groupedGestures[object1].removeOne(gesture1); + conflictedGestures[object1].append(gesture1); + } else if ((widget1 && widget2 && widget1->isAncestorOf(widget2)) || + (item1 && item2 && item1->isAncestorOf(item2))) { + groupedGestures[object2].removeOne(gesture2); + groupedGestures[object1].removeOne(gesture1); + conflictedGestures[object2].append(gesture2); + } + } + } + + DEBUG() << "deliverEvents: conflicted =" << conflictedGestures.values() + << " grouped =" << groupedGestures.values(); + + // if there are conflicting gestures, send the GestureOverride event + for (GesturesPerReceiver::const_iterator it = conflictedGestures.begin(), + e = conflictedGestures.end(); it != e; ++it) { + DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" + << it.key() + << " gestures:" << it.value(); + QGestureEvent event(it.value()); + event.t = QEvent::GestureOverride; + event.ignore(); + QApplication::sendEvent(it.key(), &event); + if (!event.isAccepted()) { + // nobody accepted the GestureOverride, put it back to deliver to + // the closest context (i.e. to the inner-most widget). + DEBUG() <<" override was not accepted"; + groupedGestures[it.key()].append(it.value()); + } + } + + for (GesturesPerReceiver::const_iterator it = groupedGestures.begin(), + e = groupedGestures.end(); it != e; ++it) { + if (!it.value().isEmpty()) { + DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() + << " gestures:" << it.value(); + QGestureEvent event(it.value()); + QApplication::sendEvent(it.key(), &event); + } + } +} + +void QGestureManager::timerEvent(QTimerEvent *event) +{ + QMap<QGesture*, QBasicTimer>::iterator it = maybeGestures.begin(), + e = maybeGestures.end(); + for (; it != e; ) { + QBasicTimer &timer = it.value(); + Q_ASSERT(timer.isActive()); + if (timer.timerId() == event->timerId()) { + timer.stop(); + QGesture *gesture = it.key(); + it = maybeGestures.erase(it); + DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" << gesture; + QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0); + if (recognizer) + recognizer->reset(gesture); + } else { + ++it; + } + } +} + +QT_END_NAMESPACE + +#include "moc_qgesturemanager_p.cpp" diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h new file mode 100644 index 0000000..c61819f --- /dev/null +++ b/src/gui/kernel/qgesturemanager_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 QtGui module 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$ +** +****************************************************************************/ + +#ifndef QGESTUREMANAGER_P_H +#define QGESTUREMANAGER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qobject.h" +#include "qbasictimer.h" +#include "private/qwidget_p.h" +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class QBasicTimer; +class QGestureManager : public QObject +{ + Q_OBJECT +public: + QGestureManager(QObject *parent); + ~QGestureManager(); + + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + + bool filterEvent(QObject *receiver, QEvent *event); + + // declared in qapplication.cpp + static QGestureManager* instance(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + QMultiMap<Qt::GestureType, QGestureRecognizer *> recognizers; + + QSet<QGesture *> activeGestures; + QMap<QGesture *, QBasicTimer> maybeGestures; + + enum State { + Gesture, + NotGesture, + MaybeGesture // this means timers are up and waiting for some + // more events, and input events are handled by + // gesture recognizer explicitely + } state; + + struct ObjectGesture + { + QWeakPointer<QObject> object; + Qt::GestureType gesture; + + ObjectGesture(QObject *o, const Qt::GestureType &g) : object(o), gesture(g) { } + inline bool operator<(const ObjectGesture& rhs) const + { + if (object.data() < rhs.object.data()) + return true; + if (object == rhs.object) + return gesture < rhs.gesture; + return false; + } + }; + + QMap<ObjectGesture, QWeakPointer<QGesture> > objectGestures; + QMap<QGesture *, QGestureRecognizer *> gestureToRecognizer; + + QHash<QGesture *, QObject *> gestureTargets; + + int lastCustomGestureId; + + QGesture *getState(QObject *widget, Qt::GestureType gesture); + void deliverEvents(const QSet<QGesture *> &gestures, QObject *lastReceiver); +}; + +QT_END_NAMESPACE + +#endif // QGESTUREMANAGER_P_H diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp new file mode 100644 index 0000000..9de3bcc --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** 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 QtGui module 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 "qgesturerecognizer.h" + +#include "private/qgesture_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QGestureRecognizer + \since 4.6 + \brief The QGestureRecognizer class provides the infrastructure for gesture recognition. + \ingroup gestures + + Gesture recognizers are responsible for creating and managing QGesture objects and + monitoring input events sent to QWidget and QGraphicsObject subclasses. + QGestureRecognizer is the base class for implementing custom gestures. + + Developers that only need to provide gesture recognition for standard gestures do not + need to use this class directly. Instances will be created behind the scenes by the + framework. + + \section1 Recognizing Gestures + + The process of recognizing gestures involves filtering input events sent to specific + objects, and modifying the associated QGesture objects to include relevant information + about the user's input. + + Gestures are created when the framework calls createGesture() to handle user input + for a particular instance of a QWidget or QGraphicsObject subclass. A QGesture object + is created for each widget or item that is configured to use gestures. + + Once a QGesture has been created for a target object, the gesture recognizer will + receive events for it in its filterEvent() handler function. + + When a gesture is canceled, the reset() function is called, giving the recognizer the + chance to update the appropriate properties in the corresponding QGesture object. + + \section1 Supporting New Gestures + + To add support for new gestures, you need to derive from QGestureRecognizer to create + a custom recognizer class, construct an instance of this class, and register it with + the application by calling QApplication::registerGestureRecognizer(). You can also + subclass QGesture to create a custom gesture class, or rely on dynamic properties + to express specific details of the gesture you want to handle. + + Your custom QGestureRecognizer subclass needs to reimplement the filterEvent() function + to handle and filter the incoming input events for QWidget and QGraphicsObject subclasses. + Although the logic for gesture recognition is implemented in this function, you can + store persistent information about the state of the recognition process in the QGesture + object supplied. The filterEvent() function must return a value of Qt::GestureState that + indicates the state of recognition for a given gesture and target object. This determines + whether or not a gesture event will be delivered to a target object. + + If you choose to represent a gesture by a custom QGesture subclass, you will need to + reimplement the createGesture() function to construct instances of your gesture class. + Similarly, you may need to reimplement the reset() function if your custom gesture + objects need to be specially handled when a gesture is canceled. + + \sa QGesture +*/ + +/*! + \enum QGestureRecognizer::ResultFlags + + This enum describes the result of the current event filtering step in + a gesture recognizer state machine. + + The result consists of a state value (one of Ignore, NotGesture, + MaybeGesture, GestureTriggered, GestureFinished) and an optional hint + (ConsumeEventHint). + + \value Ignore The event does not change the state of the recognizer. + + \value NotGesture The event made it clear that it is not a gesture. If the + gesture recognizer was in GestureTriggered state before, then the gesture + is canceled and the appropriate QGesture object will be delivered to the + target as a part of a QGestureEvent. + + \value MaybeGesture The event changed the internal state of the recognizer, + but it isn't clear yet if it is a gesture or not. The recognizer needs to + filter more events to decide. Gesture recognizers in the MaybeGesture state + may be reset automatically if they take too long to recognize gestures. + + \value GestureTriggered The gesture has been triggered and the appropriate + QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value GestureFinished The gesture has been finished successfully and the + appropriate QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value ConsumeEventHint This hint specifies that the gesture framework should + consume the filtered event and not deliver it to the receiver. + + \omitvalue ResultState_Mask + \omitvalue ResultHint_Mask + + \sa QGestureRecognizer::filterEvent() +*/ + +/*! + Constructs a new gesture recognizer object. +*/ +QGestureRecognizer::QGestureRecognizer() +{ +} + +/*! + Destroys the gesture recognizer. +*/ +QGestureRecognizer::~QGestureRecognizer() +{ +} + +/*! + This function is called by Qt to create a new QGesture object for the + given \a target (QWidget or QGraphicsObject). + + Reimplement this function to create a custom QGesture-derived gesture + object if necessary. +*/ +QGesture *QGestureRecognizer::createGesture(QObject *target) +{ + Q_UNUSED(target); + return new QGesture; +} + +/*! + This function is called by the framework to reset a given \a gesture. + + Reimplement this function to implement additional requirements for custom QGesture + objects. This may be necessary if you implement a custom QGesture whose properties + need special handling when the gesture is reset. +*/ +void QGestureRecognizer::reset(QGesture *gesture) +{ + if (gesture) { + QGesturePrivate *d = gesture->d_func(); + d->state = Qt::NoGesture; + d->hotSpot = QPointF(); + d->targetObject = 0; + } +} + +/*! + \fn QGestureRecognizer::filterEvent(QGesture *gesture, QObject *watched, QEvent *event) + + Handles the given \a event for the \a watched object, updating the state of the \a gesture + object as required, and returns a suitable Result for the current recognition step. + + This function is called by the framework to allow the recognizer to filter input events + dispatched to QWidget or QGraphicsObject instances that it is monitoring. + + The result reflects how much of the gesture has been recognized. The state of the + \a gesture object is set depending on the result. + + \sa Qt::GestureState +*/ + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h new file mode 100644 index 0000000..efd8565 --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 QtGui module 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$ +** +****************************************************************************/ + +#ifndef QGESTURERECOGNIZER_H +#define QGESTURERECOGNIZER_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QObject; +class QEvent; +class QGesture; +class Q_GUI_EXPORT QGestureRecognizer +{ +public: + enum ResultFlags + { + Ignore = 0x0001, + NotGesture = 0x0002, + MaybeGesture = 0x0004, + GestureTriggered = 0x0008, // Gesture started or updated + GestureFinished = 0x0010, + + ResultState_Mask = 0x00ff, + + ConsumeEventHint = 0x0100, + // StoreEventHint = 0x0200, + // ReplayStoredEventsHint = 0x0400, + // DiscardStoredEventsHint = 0x0800, + + ResultHint_Mask = 0xff00 + }; + Q_DECLARE_FLAGS(Result, ResultFlags) + + QGestureRecognizer(); + virtual ~QGestureRecognizer(); + + virtual QGesture *createGesture(QObject *target); + virtual QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event) = 0; + + virtual void reset(QGesture *state); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QGestureRecognizer::Result) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGESTURERECOGNIZER_H diff --git a/src/gui/kernel/qguiplatformplugin.cpp b/src/gui/kernel/qguiplatformplugin.cpp new file mode 100644 index 0000000..6e074a1 --- /dev/null +++ b/src/gui/kernel/qguiplatformplugin.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** 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 QtGui module 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 "qguiplatformplugin_p.h" +#include <qdebug.h> +#include <qfile.h> +#include <qdir.h> +#include <qsettings.h> +#include "private/qfactoryloader_p.h" +#include "qstylefactory.h" +#include "qapplication.h" +#include "qplatformdefs.h" +#include "qicon.h" + +#ifdef Q_WS_WINCE +#include "qguifunctions_wince.h" +extern bool qt_wince_is_smartphone(); //qguifunctions_wince.cpp +extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp +extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp +#endif + + +#if defined(Q_WS_X11) +#include "qkde_p.h" +#include "qt_x11_p.h" +#include <private/gtksymbols_p.h> +#endif + + +QT_BEGIN_NAMESPACE + + +/*! \internal + Return (an construct if necesseray) the Gui Platform plugin. + + The plugin key to be loaded is inside the QT_PLATFORM_PLUGIN environment variable. + If it is not set, it will be the DESKTOP_SESSION on X11. + + If no plugin can be loaded, the default one is returned. + */ +QGuiPlatformPlugin *qt_guiPlatformPlugin() +{ + static QGuiPlatformPlugin *plugin; + if (!plugin) + { +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + + QString key = QString::fromLocal8Bit(qgetenv("QT_PLATFORM_PLUGIN")); +#ifdef Q_WS_X11 + if (key.isEmpty()) { + switch(X11->desktopEnvironment) { + case DE_KDE: + key = QString::fromLatin1("kde"); + break; + default: + key = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION")); + break; + } + } +#endif + + if (!key.isEmpty() && QApplication::desktopSettingsAware()) { + QFactoryLoader loader(QGuiPlatformPluginInterface_iid, QLatin1String("/gui_platform")); + plugin = qobject_cast<QGuiPlatformPlugin *>(loader.instance(key)); + } +#endif // QT_NO_LIBRARY + + if(!plugin) { + static QGuiPlatformPlugin def; + plugin = &def; + } + } + return plugin; +} + + +/* \class QPlatformPlugin + QGuiPlatformPlugin can be used to integrate Qt applications in a platform built on top of Qt. + The application developer should not know or use the plugin, it is only used by Qt internaly. + + But full platform that are built on top of Qt may provide a plugin so 3rd party Qt application + running in the platform are integrated. + */ + +/* + The constructor can be used to install hooks in Qt + */ +QGuiPlatformPlugin::QGuiPlatformPlugin(QObject *parent) : QObject(parent) {} +QGuiPlatformPlugin::~QGuiPlatformPlugin() {} + + +/* return the string key to be used by default the application */ +QString QGuiPlatformPlugin::styleName() +{ +#if defined(Q_WS_WIN) && defined(Q_WS_WINCE) + if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) + return QLatin1String("WindowsMobile"); + else + return QLatin1String("WindowsCE"); +#elif defined(Q_WS_WIN) + if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsVista"); + else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP + && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) + return QLatin1String("WindowsXP"); + else + return QLatin1String("Windows"); // default styles for Windows +#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) + return QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + return QLatin1String("S60"); // default style for Symbian with S60 +#elif defined(Q_OS_SYMBIAN) + return QLatin1String("Windows"); // default style for Symbian without S60 +#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) + return QLatin1String("SGI"); // default style for X11 on IRIX +#elif defined(Q_WS_QWS) + return QLatin1String("Plastique"); // default style for X11 and small devices +#elif defined(Q_WS_MAC) + return QLatin1String("Macintosh"); // default style for all Mac's +#elif defined(Q_WS_X11) + QString stylename; + switch(X11->desktopEnvironment) { + case DE_KDE: + stylename = QKde::kdeStyle(); + break; + case DE_GNOME: { + QStringList availableStyles = QStyleFactory::keys(); + // Set QGtkStyle for GNOME if available + QString gtkStyleKey = QString::fromLatin1("GTK+"); + if (availableStyles.contains(gtkStyleKey)) { + stylename = gtkStyleKey; + break; + } + if (X11->use_xrender) + stylename = QLatin1String("cleanlooks"); + else + stylename = QLatin1String("windows"); + break; + } + case DE_CDE: + stylename = QLatin1String("cde"); + break; + default: + // Don't do anything + break; + } + return stylename; +#endif +} + +/* return an aditional default palette (only work on X11) */ +QPalette QGuiPlatformPlugin::palette() +{ +#ifdef Q_WS_X11 + if (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE) + return QKde::kdePalette(); +#endif + + return QPalette(); +} + +/* the default icon theme name for QIcon::fromTheme. */ +QString QGuiPlatformPlugin::systemIconThemeName() +{ + QString result; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_GNOME) { + result = QString::fromLatin1("gnome"); +#ifndef QT_NO_STYLE_GTK + result = QGtk::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), result); +#endif + } else if (X11->desktopEnvironment == DE_KDE) { + result = X11->desktopVersion >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + settings.beginGroup(QLatin1String("Icons")); + result = settings.value(QLatin1String("Theme"), result).toString(); + } +#endif + return result; +} + + +QStringList QGuiPlatformPlugin::iconThemeSearchPaths() +{ + QStringList paths; +#if defined(Q_WS_X11) + QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); + if (xdgDirString.isEmpty()) + xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); + + QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); + + for (int i = 0 ; i < xdgDirs.size() ; ++i) { + QDir dir(xdgDirs[i]); + if (dir.exists()) + paths.append(dir.path() + QLatin1String("/icons")); + } + if (X11->desktopEnvironment == DE_KDE) { + paths << QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share/icons"); + QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); + for (int i = 0 ; i< kdeDirs.count() ; ++i) { + QDir dir(QLatin1Char(':') + kdeDirs.at(i) + QLatin1String("/share/icons")); + if (dir.exists()) + paths.append(dir.path()); + } + } + + // Add home directory first in search path + QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); + if (homeDir.exists()) + paths.prepend(homeDir.path()); +#endif + +#if defined(Q_WS_WIN) + paths.append(qApp->applicationDirPath() + QLatin1String("/icons")); +#elif defined(Q_WS_MAC) + paths.append(qApp->applicationDirPath() + QLatin1String("/../Resources/icons")); +#endif + return paths; +} + +/* backend for QFileIconProvider, null icon means default */ +QIcon QGuiPlatformPlugin::fileSystemIcon(const QFileInfo &) +{ + return QIcon(); +} + +/* Like QStyle::styleHint */ +int QGuiPlatformPlugin::platformHint(PlatformHint hint) +{ + int ret = 0; + switch(hint) + { + case PH_ToolButtonStyle: + ret = Qt::ToolButtonIconOnly; +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolButtonStyle(); + } +#endif + break; + case PH_ToolBarIconSize: +#ifdef Q_WS_X11 + if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 + && QApplication::desktopSettingsAware()) { + ret = QKde::kdeToolBarIconSize(); + } +#endif + //by default keep ret = 0 so QCommonStyle will use the style default + break; + } + return ret; +} + + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qguiplatformplugin_p.h b/src/gui/kernel/qguiplatformplugin_p.h new file mode 100644 index 0000000..2a70ee7 --- /dev/null +++ b/src/gui/kernel/qguiplatformplugin_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 QtGui module 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$ +** +****************************************************************************/ + +#ifndef QGUIPLATFORM_P_H +#define QGUIPLATFORM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qplugin.h> +#include <QtCore/qfactoryinterface.h> +#include <QtGui/qdialog.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QStyle; +class QPalette; +class QIcon; +class QFileDialog; +class QColorDialog; +class QFileInfo; + +struct Q_GUI_EXPORT QGuiPlatformPluginInterface : public QFactoryInterface +{ +}; + +#define QGuiPlatformPluginInterface_iid "com.nokia.qt.QGuiPlatformPluginInterface" + +Q_DECLARE_INTERFACE(QGuiPlatformPluginInterface, QGuiPlatformPluginInterface_iid) + +class Q_GUI_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QGuiPlatformPluginInterface:QFactoryInterface) + public: + explicit QGuiPlatformPlugin(QObject *parent = 0); + ~QGuiPlatformPlugin(); + + virtual QStringList keys() const { return QStringList() << QLatin1String("default"); }; + + virtual QString styleName(); + virtual QPalette palette(); + virtual QString systemIconThemeName(); + virtual QStringList iconThemeSearchPaths(); + virtual QIcon fileSystemIcon(const QFileInfo &); + + enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; + virtual int platformHint(PlatformHint hint); + + + virtual void fileDialogDelete(QFileDialog *) {} + virtual bool fileDialogSetVisible(QFileDialog *, bool) { return false; } + virtual QDialog::DialogCode fileDialogResultCode(QFileDialog *) { return QDialog::Rejected; } + virtual void fileDialogSetDirectory(QFileDialog *, const QString &) {} + virtual QString fileDialogDirectory(const QFileDialog *) const { return QString(); } + virtual void fileDialogSelectFile(QFileDialog *, const QString &) {} + virtual QStringList fileDialogSelectedFiles(const QFileDialog *) const { return QStringList(); } + virtual void fileDialogSetFilter(QFileDialog *) {} + virtual void fileDialogSetNameFilters(QFileDialog *, const QStringList &) {} + virtual void fileDialogSelectNameFilter(QFileDialog *, const QString &) {} + virtual QString fileDialogSelectedNameFilter(const QFileDialog *) const { return QString(); } + + virtual void colorDialogDelete(QColorDialog *) {} + virtual bool colorDialogSetVisible(QColorDialog *, bool) { return false; } + virtual void colorDialogSetCurrentColor(QColorDialog *, const QColor &) {} +}; + +//internal +QGuiPlatformPlugin *qt_guiPlatformPlugin(); + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif // QGUIPLATFORMPLUGIN_H diff --git a/src/gui/kernel/qkde.cpp b/src/gui/kernel/qkde.cpp index 6c8909f..edc53ac 100644 --- a/src/gui/kernel/qkde.cpp +++ b/src/gui/kernel/qkde.cpp @@ -141,14 +141,33 @@ QString QKde::kdeStyle() return QLatin1String("windows"); } -/*!\internal - placeholder to load icon from kde. - to be implemented - */ -QIcon QKde::kdeIcon(const QString &name) + +int QKde::kdeToolButtonStyle() +{ + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + settings.beginGroup(QLatin1String("Toolbar style")); + QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString(); + if (toolbarStyle == QLatin1String("TextBesideIcon")) + return Qt::ToolButtonTextBesideIcon; + else if (toolbarStyle == QLatin1String("TextOnly")) + return Qt::ToolButtonTextOnly; + else if (toolbarStyle == QLatin1String("TextUnderIcon")) + return Qt::ToolButtonTextUnderIcon; + + return Qt::ToolButtonTextBesideIcon; +} + +int QKde::kdeToolBarIconSize() { - //###todo - return QIcon(); + static int iconSize = -1; + if (iconSize == -1) { + QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), + QSettings::IniFormat); + settings.beginGroup(QLatin1String("ToolbarIcons")); + iconSize = settings.value(QLatin1String("Size")).toInt(); + } + return iconSize; } QT_END_NAMESPACE diff --git a/src/gui/kernel/qkde_p.h b/src/gui/kernel/qkde_p.h index 4063f0e..c22a145 100644 --- a/src/gui/kernel/qkde_p.h +++ b/src/gui/kernel/qkde_p.h @@ -61,12 +61,17 @@ QT_BEGIN_NAMESPACE -// This namespace contains helper function to help KDE integration +/*!\internal + This namespace contains helper function to help KDE integration + They are only used if we detect the use of KDE and the KDE platform plugin is not found (old KDE version) + Or if the detected KDE version is KDE3 +*/ namespace QKde { QString kdeHome(); QString kdeStyle(); QPalette kdePalette(); - QIcon kdeIcon(const QString &name); + int kdeToolButtonStyle(); + int kdeToolBarIconSize(); } diff --git a/src/gui/kernel/qkeymapper_win.cpp b/src/gui/kernel/qkeymapper_win.cpp index 10958f3..be207df 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -905,8 +905,8 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool if(msg.wParam == VK_PROCESSKEY) return true; - // Ignore invalid virtual keycode (see bug 127424) - if (msg.wParam == 0xFF) + // Ignore invalid virtual keycodes (see bugs 127424, QTBUG-3630) + if (msg.wParam == 0 || msg.wParam == 0xFF) return true; // Translate VK_* (native) -> Key_* (Qt) keys diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm new file mode 100644 index 0000000..7b19a54 --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** 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 QtGui module 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 "qmacgesturerecognizer_mac_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qevent_p.h" +#include "qwidget.h" +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +QMacSwipeGestureRecognizer::QMacSwipeGestureRecognizer() +{ +} + +QGesture *QMacSwipeGestureRecognizer::createGesture(QObject * /*target*/) +{ + return new QSwipeGesture; +} + +QGestureRecognizer::Result +QMacSwipeGestureRecognizer::filterEvent(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch (ev->gestureType) { + case QNativeGestureEvent::Swipe: { + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(ev->angle); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; } + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacSwipeGestureRecognizer::reset(QGesture *gesture) +{ + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(0); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +QMacPinchGestureRecognizer::QMacPinchGestureRecognizer() +{ +} + +QGesture *QMacPinchGestureRecognizer::createGesture(QObject * /*target*/) +{ + return new QPinchGesture; +} + +QGestureRecognizer::Result +QMacPinchGestureRecognizer::filterEvent(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + reset(gesture); + g->setStartCenterPoint(static_cast<QWidget*>(obj)->mapFromGlobal(ev->position)); + g->setCenterPoint(g->startCenterPoint()); + g->setWhatChanged(QPinchGesture::CenterPointChanged); + return QGestureRecognizer::MaybeGesture | QGestureRecognizer::ConsumeEventHint; + case QNativeGestureEvent::Rotate: { + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setRotationAngle(g->rotationAngle() + ev->percentage); + g->setWhatChanged(QPinchGesture::RotationAngleChanged); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; + } + case QNativeGestureEvent::Zoom: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setScaleFactor(g->scaleFactor() + ev->percentage); + g->setWhatChanged(QPinchGesture::ScaleFactorChanged); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; + case QNativeGestureEvent::GestureEnd: + return QGestureRecognizer::GestureFinished | QGestureRecognizer::ConsumeEventHint; + break; + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacPinchGestureRecognizer::reset(QGesture *gesture) +{ + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + g->setWhatChanged(0); + g->setScaleFactor(1.0f); + g->setTotalScaleFactor(1.0f); + g->setLastScaleFactor(1.0f); + g->setRotationAngle(0.0f); + g->setTotalRotationAngle(0.0f); + g->setLastRotationAngle(0.0f); + g->setCenterPoint(QPointF()); + g->setStartCenterPoint(QPointF()); + g->setLastCenterPoint(QPointF()); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +#if defined(QT_MAC_USE_COCOA) + +QMacPanGestureRecognizer::QMacPanGestureRecognizer() : _panCanceled(true) +{ +} + +QGesture *QMacPanGestureRecognizer::createGesture(QObject *target) +{ + if (!target) + return new QPanGesture; + + if (QWidget *w = qobject_cast<QWidget *>(target)) { + w->setAttribute(Qt::WA_AcceptTouchEvents); + w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + return new QPanGesture; + } + return 0; +} + +QGestureRecognizer::Result +QMacPanGestureRecognizer::filterEvent(QGesture *gesture, QObject *target, QEvent *event) +{ + const int panBeginDelay = 300; + const int panBeginRadius = 3; + + QPanGesture *g = static_cast<QPanGesture *>(gesture); + + switch (event->type()) { + case QEvent::TouchBegin: { + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) { + reset(gesture); + _startPos = QCursor::pos(); + _lastPos = _startPos; + _panTimer.start(panBeginDelay, target); + _panCanceled = false; + return QGestureRecognizer::MaybeGesture; + } + break;} + case QEvent::TouchEnd: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) + return QGestureRecognizer::GestureFinished; + break;} + case QEvent::TouchUpdate: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) { + if (_panTimer.isActive()) { + // INVARIANT: Still in maybeGesture. Check if the user + // moved his finger so much that it makes sense to cancel the pan: + const QPointF p = QCursor::pos(); + if ((p - _startPos).manhattanLength() > panBeginRadius) { + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::NotGesture; + } + } else { + const QPointF p = QCursor::pos(); + const QPointF posOffset = p - _lastPos; + g->setLastOffset(g->offset()); + g->setOffset(QSizeF(posOffset.x(), posOffset.y())); + g->setTotalOffset(g->lastOffset() + g->offset()); + _lastPos = p; + return QGestureRecognizer::GestureTriggered; + } + } else if (_panTimer.isActive()) { + // I only want to cancel the pan if the user is pressing + // more than one finger, and the pan hasn't started yet: + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::NotGesture; + } + break;} + case QEvent::Timer: { + QTimerEvent *ev = static_cast<QTimerEvent *>(event); + if (ev->timerId() == _panTimer.timerId()) { + _panTimer.stop(); + if (_panCanceled) + break; + // Begin new pan session! + _startPos = QCursor::pos(); + _lastPos = _startPos; + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + } + break; } + default: + break; + } + + return QGestureRecognizer::Ignore; +} + +void QMacPanGestureRecognizer::reset(QGesture *gesture) +{ + QPanGesture *g = static_cast<QPanGesture *>(gesture); + _startPos = QPointF(); + _lastPos = QPointF(); + _panCanceled = true; + g->setOffset(QSizeF(0, 0)); + g->setLastOffset(QSizeF(0, 0)); + g->setTotalOffset(QSizeF(0, 0)); + g->setAcceleration(qreal(1)); + QGestureRecognizer::reset(gesture); +} +#endif // QT_MAC_USE_COCOA + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qmacgesturerecognizer_mac_p.h b/src/gui/kernel/qmacgesturerecognizer_mac_p.h new file mode 100644 index 0000000..bdc2e08 --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 QtGui module 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$ +** +****************************************************************************/ + +#ifndef QMACSWIPEGESTURERECOGNIZER_MAC_P_H +#define QMACSWIPEGESTURERECOGNIZER_MAC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qtimer.h" +#include "qpoint.h" +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class QMacSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QMacSwipeGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +class QMacPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QMacPinchGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +#if defined(QT_MAC_USE_COCOA) + +class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer +{ +public: + QMacPanGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +private: + QPointF _startPos; + QPointF _lastPos; + QBasicTimer _panTimer; + bool _panCanceled; +}; + +#endif + +QT_END_NAMESPACE + +#endif // QMACSWIPEGESTURERECOGNIZER_MAC_P_H diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 265f971..6116a5e 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -112,7 +112,7 @@ QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *act { const char* text = standardSoftKeyText(standardKey); QAction *action = new QAction(QSoftKeyManager::tr(text), actionWidget); - QAction::SoftKeyRole softKeyRole; + QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; switch (standardKey) { case OkSoftKey: case SelectSoftKey: @@ -121,12 +121,10 @@ QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *act softKeyRole = QAction::PositiveSoftKey; break; case CancelSoftKey: - default: softKeyRole = QAction::NegativeSoftKey; break; } action->setSoftKeyRole(softKeyRole); - action->setEnabled(actionWidget->isEnabled()); return action; } @@ -201,6 +199,7 @@ bool QSoftKeyManager::event(QEvent *e) void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) { CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + nativeContainer->DrawableWindow()->SetPointerCapturePriority(1); //keep softkeys available in modal dialog QT_TRAP_THROWING(nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS)); int position = -1; @@ -210,7 +209,7 @@ void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) for (int index = 0; index < softkeys.count(); index++) { const QAction* softKeyAction = softkeys.at(index); switch (softKeyAction->softKeyRole()) { - // Positive Actions go on LSK + // Positive Actions on the LSK case QAction::PositiveSoftKey: position = 0; break; @@ -253,7 +252,8 @@ bool QSoftKeyManager::handleCommand(int command) QAction *action = softKeys.at(i); if (action->softKeyRole() != QAction::NoSoftKey) { if (j == index) { - if (action->isEnabled()) { + QWidget *parent = action->parentWidget(); + if (parent && parent->isEnabled()) { action->activate(QAction::Trigger); return true; } diff --git a/src/gui/kernel/qsoftkeymanager_p.h b/src/gui/kernel/qsoftkeymanager_p.h index c4bb84d..b455445 100644 --- a/src/gui/kernel/qsoftkeymanager_p.h +++ b/src/gui/kernel/qsoftkeymanager_p.h @@ -74,7 +74,7 @@ public: SelectSoftKey, DoneSoftKey, MenuSoftKey, - CancelSoftKey, + CancelSoftKey }; static void updateSoftKeys(); diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 3cfb987..dfc3499 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -39,174 +39,45 @@ ** ****************************************************************************/ -#include "qstandardgestures.h" #include "qstandardgestures_p.h" - -#include <qabstractscrollarea.h> -#include <qscrollbar.h> -#include <private/qapplication_p.h> -#include <private/qevent_p.h> -#include <private/qwidget_p.h> -#include <qmath.h> +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qwidget.h" QT_BEGIN_NAMESPACE -#ifdef Q_WS_WIN -QWidgetPrivate *qt_widget_private(QWidget *widget); -#endif - -/*! - \class QPanGesture - \preliminary - \since 4.6 - - \brief The QPanGesture class represents a Pan gesture, - providing additional information related to panning. -*/ - -/*! - \enum QSwipeGesture::SwipeDirection - \brief This enum specifies the direction of the swipe gesture. - - \value NoDirection - \value Left - \value Right - \value Up - \value Down -*/ - -/*! - Creates a new pan gesture handler object and marks it as a child of - \a parent. The pan gesture handler watches \a gestureTarget for its - events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QPanGesture::QPanGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QPanGesturePrivate, gestureTarget, parent) +QPanGestureRecognizer::QPanGestureRecognizer() { - setObjectName(QLatin1String("QPanGesture")); -} - -void QPanGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QPanGesture); - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - if (qAppPriv->widgetGestures[w].pan == q) - qAppPriv->widgetGestures[w].pan = 0; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#elif defined(Q_WS_MAC) - w->setAttribute(Qt::WA_AcceptTouchEvents, false); - w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents, false); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - qAppPriv->widgetGestures[w].pan = q; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#elif defined(Q_WS_MAC) - w->setAttribute(Qt::WA_AcceptTouchEvents); - w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! \internal */ -bool QPanGesture::event(QEvent *event) -{ -#if defined(QT_MAC_USE_COCOA) - Q_D(QPanGesture); - if (event->type() == QEvent::Timer) { - const QTimerEvent *te = static_cast<QTimerEvent *>(event); - if (te->timerId() == d->singleTouchPanTimer.timerId()) { - d->singleTouchPanTimer.stop(); - updateState(Qt::GestureStarted); - } - } -#endif - - return QObject::event(event); } -bool QPanGesture::eventFilter(QObject *receiver, QEvent *event) +QGesture *QPanGestureRecognizer::createGesture(QObject *target) { - Q_D(QPanGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#ifdef Q_WS_WIN - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::iterator it; - it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver)); - if (it == qAppPriv->widgetGestures.end()) - return false; - if (this != it.value().pan) - return false; - Qt::GestureState nextState = Qt::NoGesture; - switch(ev->gestureType) { - case QNativeGestureEvent::GestureBegin: - // next we might receive the first gesture update event, so we - // prepare for it. - d->state = Qt::NoGesture; - return false; - case QNativeGestureEvent::Pan: - nextState = Qt::GestureUpdated; - event->accept(); - break; - case QNativeGestureEvent::GestureEnd: - if (state() == Qt::NoGesture) - return false; // some other gesture has ended - nextState = Qt::GestureFinished; - break; - default: - return false; - } - if (state() == Qt::NoGesture) { - d->lastOffset = d->totalOffset = d->offset = QSize(); - } else { - d->lastOffset = d->offset; - d->offset = QSize(ev->position.x() - d->lastPosition.x(), - ev->position.y() - d->lastPosition.y()); - d->totalOffset += d->offset; - } - d->lastPosition = ev->position; - updateState(nextState); - return true; + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); } -#endif - return QGesture::eventFilter(receiver, event); + return new QPanGesture; } -/*! \internal */ -bool QPanGesture::filterEvent(QEvent *event) +QGestureRecognizer::Result QPanGestureRecognizer::filterEvent(QGesture *state, QObject *, QEvent *event) { - Q_D(QPanGesture); + QPanGesture *q = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = q->d_func(); - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#if defined(Q_WS_WIN) const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); - if (event->type() == QEvent::TouchBegin) { + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MaybeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastPosition = p.pos().toPoint(); d->lastOffset = d->totalOffset = d->offset = QSize(); - } else if (event->type() == QEvent::TouchEnd) { - if (state() != Qt::NoGesture) { + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { if (ev->touchPoints().size() == 2) { QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); @@ -216,11 +87,14 @@ bool QPanGesture::filterEvent(QEvent *event) p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; d->totalOffset += d->offset; } - updateState(Qt::GestureFinished); + result = QGestureRecognizer::GestureFinished; + } else { + result = QGestureRecognizer::NotGesture; } - reset(); - } else if (event->type() == QEvent::TouchUpdate) { - if (ev->touchPoints().size() == 2) { + break; + } + case QEvent::TouchUpdate: { + if (ev->touchPoints().size() >= 2) { QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); d->lastOffset = d->offset; @@ -230,10 +104,60 @@ bool QPanGesture::filterEvent(QEvent *event) d->totalOffset += d->offset; if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 || d->totalOffset.width() < -10 || d->totalOffset.height() < -10) { - updateState(Qt::GestureUpdated); + result = QGestureRecognizer::GestureTriggered; + } else { + result = QGestureRecognizer::MaybeGesture; } } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->lastPosition = QPoint(); + d->acceleration = 0; + +//#if defined(QT_MAC_USE_COCOA) +// d->singleTouchPanTimer.stop(); +// d->prevMousePos = QPointF(0, 0); +//#endif + + QGestureRecognizer::reset(state); +} + +/*! \internal */ +/* +bool QPanGestureRecognizer::event(QEvent *event) +{ +#if defined(QT_MAC_USE_COCOA) + Q_D(QPanGesture); + if (event->type() == QEvent::Timer) { + const QTimerEvent *te = static_cast<QTimerEvent *>(event); + if (te->timerId() == d->singleTouchPanTimer.timerId()) { + d->singleTouchPanTimer.stop(); + updateState(Qt::GestureStarted); + } } +#endif + + bool consume = false; + +#if defined(Q_WS_WIN) #elif defined(QT_MAC_USE_COCOA) // The following implements single touch // panning on Mac: @@ -244,16 +168,25 @@ bool QPanGesture::filterEvent(QEvent *event) switch (event->type()) { case QEvent::TouchBegin: { if (ev->touchPoints().size() == 1) { + d->delayManager->setEnabled(true); + consume = d->delayManager->append(d->gestureTarget, *event); d->lastPosition = QCursor::pos(); d->singleTouchPanTimer.start(panBeginDelay, this); } break;} case QEvent::TouchEnd: { - if (state() != Qt::NoGesture) + d->delayManager->setEnabled(false); + if (state() != Qt::NoGesture) { updateState(Qt::GestureFinished); + consume = true; + d->delayManager->clear(); + } else { + d->delayManager->replay(); + } reset(); break;} case QEvent::TouchUpdate: { + consume = d->delayManager->append(d->gestureTarget, *event); if (ev->touchPoints().size() == 1) { if (state() == Qt::NoGesture) { // INVARIANT: The singleTouchTimer has still not fired. @@ -261,11 +194,15 @@ bool QPanGesture::filterEvent(QEvent *event) // the starting point that it makes sense to cancel: const QPointF startPos = ev->touchPoints().at(0).startPos().toPoint(); const QPointF p = ev->touchPoints().at(0).pos().toPoint(); - if ((startPos - p).manhattanLength() > panBeginRadius) + if ((startPos - p).manhattanLength() > panBeginRadius) { + d->delayManager->replay(); + consume = false; reset(); - else + } else { d->lastPosition = QCursor::pos(); + } } else { + d->delayManager->clear(); QPointF mousePos = QCursor::pos(); QPointF dist = mousePos - d->lastPosition; d->lastPosition = mousePos; @@ -275,527 +212,25 @@ bool QPanGesture::filterEvent(QEvent *event) updateState(Qt::GestureUpdated); } } else if (state() == Qt::NoGesture) { + d->delayManager->replay(); + consume = false; reset(); } break;} + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + if (d->delayManager->isEnabled()) + consume = d->delayManager->append(d->gestureTarget, *event); + break; default: return false; } #else Q_UNUSED(event); #endif - return false; -} - -/*! \internal */ -void QPanGesture::reset() -{ - Q_D(QPanGesture); - d->lastOffset = d->totalOffset = d->offset = QSize(0, 0); - d->lastPosition = QPoint(0, 0); - -#if defined(QT_MAC_USE_COCOA) - d->singleTouchPanTimer.stop(); - d->prevMousePos = QPointF(0, 0); -#endif - - QGesture::reset(); -} - -/*! - \property QPanGesture::totalOffset - - Specifies a total pan offset since the start of the gesture. -*/ -QSizeF QPanGesture::totalOffset() const -{ - Q_D(const QPanGesture); - return d->totalOffset; -} - -/*! - \property QPanGesture::lastOffset - - Specifies a pan offset the last time the gesture was triggered. -*/ -QSizeF QPanGesture::lastOffset() const -{ - Q_D(const QPanGesture); - return d->lastOffset; -} - -/*! - \property QPanGesture::offset - - Specifies the current pan offset since the last time the gesture was - triggered. -*/ -QSizeF QPanGesture::offset() const -{ - Q_D(const QPanGesture); - return d->offset; -} - -////////////////////////////////////////////////////////////////////////////// - -/*! - \class QPinchGesture - \preliminary - \since 4.6 - - \brief The QPinchGesture class represents a Pinch gesture, - providing additional information related to zooming and/or rotation. -*/ - -/*! - Creates a new Pinch gesture handler object and marks it as a child - of \a parent. The pan gesture handler watches \a gestureTarget for its - events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QPinchGesture::QPinchGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QPinchGesturePrivate, gestureTarget, parent) -{ - setObjectName(QLatin1String("QPinchGesture")); -} - -void QPinchGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QPinchGesture); - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - QApplicationPrivate::instance()->widgetGestures[w].pinch = 0; -#ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - QApplicationPrivate::instance()->widgetGestures[w].pinch = q; -#ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! \internal */ -bool QPinchGesture::event(QEvent *event) -{ - return QObject::event(event); -} - -bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event) -{ - Q_D(QPinchGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); -#if defined(Q_WS_WIN) - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::iterator it; - it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver)); - if (it == qAppPriv->widgetGestures.end()) - return false; - if (this != it.value().pinch) - return false; -#endif - Qt::GestureState nextState = Qt::NoGesture; - - switch(ev->gestureType) { - case QNativeGestureEvent::GestureBegin: - // next we might receive the first gesture update event, so we - // prepare for it. - d->state = Qt::NoGesture; - d->changes = 0; - d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.; - d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.; - d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF(); -#if defined(Q_WS_WIN) - d->initialDistance = 0; - d->lastSequenceId = ev->sequenceId; -#endif - return false; - case QNativeGestureEvent::Rotate: { - d->lastScaleFactor = d->scaleFactor; - d->lastRotationAngle = d->rotationAngle; -#if defined(Q_WS_MAC) - d->rotationAngle += ev->percentage; - nextState = Qt::GestureUpdated; -#elif defined(Q_WS_WIN) - // This is a workaround for an issue with the native rotation - // gesture on Windows 7. For some reason the rotation angle in the - // first WM_GESTURE message in a sequence contains value that is - // off a little bit and causes the rotating item to "jump", so - // we just ignore the first WM_GESTURE in every sequence. - bool windowsRotateWorkaround = false; - if (!d->lastSequenceId) { - windowsRotateWorkaround = true; - d->lastSequenceId = ev->sequenceId; - } - if (d->lastSequenceId > 0 && d->lastSequenceId != (ulong)-1 && ev->sequenceId != d->lastSequenceId) { - // this is the first WM_GESTURE message in a sequence. - d->totalRotationAngle += d->rotationAngle; - windowsRotateWorkaround = true; - // a magic value to mark that the next WM_GESTURE message is - // the second message in a sequence and we should clear the - // lastRotationAngle - d->lastSequenceId = (ulong)-1; - } - if (!windowsRotateWorkaround) { - d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument) * 180. / M_PI; - if (d->lastSequenceId == (ulong)-1) { - // a special case since we need to set the lastRotationAngle to - // rotationAngle when the first WM_GESTURE is received in each - // sequence. - d->lastRotationAngle = d->rotationAngle; - } - d->lastSequenceId = ev->sequenceId; - } - if (!windowsRotateWorkaround) - nextState = Qt::GestureUpdated; -#endif - d->changes = QPinchGesture::RotationAngleChanged; - event->accept(); - break; - } - case QNativeGestureEvent::Zoom: - d->lastRotationAngle = d->rotationAngle; - d->lastScaleFactor = d->scaleFactor; -#if defined(Q_WS_WIN) - if (d->initialDistance != 0) { - int distance = int(qint64(ev->argument)); - if (d->lastSequenceId && ev->sequenceId != d->lastSequenceId) { - d->totalScaleFactor *= d->scaleFactor; - d->initialDistance = int(qint64(ev->argument)); - d->lastScaleFactor = d->scaleFactor = (qreal) distance / d->initialDistance; - } else { - d->scaleFactor = (qreal) distance / d->initialDistance; - } - d->lastSequenceId = ev->sequenceId; - } else { - d->initialDistance = int(qint64(ev->argument)); - } -#elif defined(Q_WS_MAC) - d->scaleFactor += ev->percentage; -#endif - nextState = Qt::GestureUpdated; - d->changes = QPinchGesture::ScaleFactorChanged; - event->accept(); - break; - case QNativeGestureEvent::GestureEnd: - if (state() == Qt::NoGesture) - return false; // some other gesture has ended - nextState = Qt::GestureFinished; - break; - default: - return false; - } - if (d->startCenterPoint.isNull()) - d->startCenterPoint = d->centerPoint; - d->lastCenterPoint = d->centerPoint; - d->centerPoint = static_cast<QWidget*>(receiver)->mapFromGlobal(ev->position); - if (d->lastCenterPoint != d->centerPoint) - d->changes |= QPinchGesture::CenterPointChanged; - updateState(nextState); - return true; - } -#endif - return QGesture::eventFilter(receiver, event); -} - - -/*! \internal */ -bool QPinchGesture::filterEvent(QEvent *event) -{ - Q_D(QPinchGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - - Q_UNUSED(event); - return false; -} - -/*! \internal */ -void QPinchGesture::reset() -{ - Q_D(QPinchGesture); - d->changes = 0; - d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.; - d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.; - d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF(); - QGesture::reset(); -} - -/*! \enum QPinchGesture::WhatChange - \value ScaleFactorChanged - \value RotationAngleChanged - \value CenterPointChanged -*/ - -/*! - \property QPinchGesture::whatChanged - - Specifies which values were changed in the gesture. -*/ -QPinchGesture::WhatChanged QPinchGesture::whatChanged() const -{ - return d_func()->changes; -} - -/*! - \property QPinchGesture::totalScaleFactor - - Specifies a total scale factor of the pinch gesture since the gesture - started. -*/ -qreal QPinchGesture::totalScaleFactor() const -{ - Q_D(const QPinchGesture); - return d->totalScaleFactor * d->scaleFactor; -} - -/*! - \property QPinchGesture::scaleFactor - - Specifies a scale factor of the pinch gesture. - - If the gesture consists of several pinch sequences (i.e. zoom and rotate - sequences), then this property specifies the scale factor in the current - sequence. When pinching changes the rotation angle only, the value of this - property is 1. -*/ -qreal QPinchGesture::scaleFactor() const -{ - return d_func()->scaleFactor; -} - -/*! - \property QPinchGesture::lastScaleFactor - - Specifies a previous scale factor of the pinch gesture. -*/ -qreal QPinchGesture::lastScaleFactor() const -{ - return d_func()->lastScaleFactor; -} - -/*! - \property QPinchGesture::totalRotationAngle - - Specifies a total rotation angle of the gesture since the gesture started. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::totalRotationAngle() const -{ - Q_D(const QPinchGesture); - return d->totalRotationAngle + d->rotationAngle; -} - -/*! - \property QPinchGesture::rotationAngle - - Specifies a rotation angle of the gesture. - - If the gesture consists of several pinch sequences (i.e. zoom and rotate - sequences), then this property specifies the rotation angle in the current - sequence. When pinching changes the scale factor only, the value of this - property is 0. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::rotationAngle() const -{ - return d_func()->rotationAngle; -} - -/*! - \property QPinchGesture::lastRotationAngle - - Specifies a previous rotation angle of the gesture. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::lastRotationAngle() const -{ - return d_func()->lastRotationAngle; -} - -/*! - \property QPinchGesture::centerPoint - - Specifies a center point of the gesture. The point can be used as a center - point that the object is rotated around. -*/ -QPointF QPinchGesture::centerPoint() const -{ - return d_func()->centerPoint; -} - -/*! - \property QPinchGesture::lastCenterPoint - - Specifies a previous center point of the gesture. -*/ -QPointF QPinchGesture::lastCenterPoint() const -{ - return d_func()->lastCenterPoint; -} - -/*! - \property QPinchGesture::startCenterPoint - - Specifies an initial center point of the gesture. Difference between the - startCenterPoint and the centerPoint is the distance at which pinching - fingers has shifted. -*/ -QPointF QPinchGesture::startCenterPoint() const -{ - return d_func()->startCenterPoint; -} - -////////////////////////////////////////////////////////////////////////////// - -/*! - \class QSwipeGesture - \preliminary - \since 4.6 - - \brief The QSwipeGesture class represents a swipe gesture, - providing additional information related to swiping. -*/ - -/*! - Creates a new Swipe gesture handler object and marks it as a - child of \a parent. The swipe gesture handler watches \a - gestureTarget for its events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QSwipeGesture::QSwipeGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QSwipeGesturePrivate, gestureTarget, parent) -{ - setObjectName(QLatin1String("QSwipeGesture")); -} - -void QSwipeGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QSwipeGesture); - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - QApplicationPrivate::instance()->widgetGestures[w].swipe = 0; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - QApplicationPrivate::instance()->widgetGestures[w].swipe = q; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! - \property QSwipeGesture::swipeAngle - - Holds the angle of the swipe gesture, 0..360. -*/ -qreal QSwipeGesture::swipeAngle() const -{ - Q_D(const QSwipeGesture); - return d->swipeAngle; -} - -/*! - \property QSwipeGesture::horizontalDirection - - Holds the direction for the horizontal component of the swipe - gesture, SwipeDirection::Left or SwipeDirection::Right. - SwipeDirection::NoDirection if there is no horizontal - component to the swipe gesture. -*/ -QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const -{ - Q_D(const QSwipeGesture); - if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) - return QSwipeGesture::NoDirection; - else if (d->swipeAngle < 90 || d->swipeAngle > 270) - return QSwipeGesture::Right; - else - return QSwipeGesture::Left; -} - - -/*! - \property QSwipeGesture::verticalDirection - - Holds the direction for the vertical component of the swipe - gesture, SwipeDirection::Down or SwipeDirection::Up. - SwipeDirection::NoDirection if there is no vertical - component to the swipe gesture. -*/ -QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const -{ - Q_D(const QSwipeGesture); - if (d->swipeAngle <= 0 || d->swipeAngle == 180) - return QSwipeGesture::NoDirection; - else if (d->swipeAngle < 180) - return QSwipeGesture::Up; - else - return QSwipeGesture::Down; -} - -bool QSwipeGesture::eventFilter(QObject *receiver, QEvent *event) -{ - Q_D(QSwipeGesture); - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); - switch (ev->gestureType) { - case QNativeGestureEvent::Swipe: - d->swipeAngle = ev->angle; - updateState(Qt::GestureStarted); - updateState(Qt::GestureUpdated); - updateState(Qt::GestureFinished); - break; - default: - return false; - } - return true; - } - return QGesture::eventFilter(receiver, event); -} - -/*! \internal */ -bool QSwipeGesture::filterEvent(QEvent *) -{ - return false; -} - -/*! \internal */ -void QSwipeGesture::reset() -{ - Q_D(QSwipeGesture); - d->swipeAngle = -1; - QGesture::reset(); + return QGestureRecognizer::Ignore; } + */ QT_END_NAMESPACE - -#include "moc_qstandardgestures.cpp" - diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h deleted file mode 100644 index 9e8291b..0000000 --- a/src/gui/kernel/qstandardgestures.h +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** -** -** 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 QtGui module 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$ -** -****************************************************************************/ - -#ifndef QSTANDARDGESTURES_H -#define QSTANDARDGESTURES_H - -#include <QtGui/qevent.h> -#include <QtCore/qbasictimer.h> - -#include <QtGui/qgesture.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QPanGesturePrivate; -class Q_GUI_EXPORT QPanGesture : public QGesture -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPanGesture) - - Q_PROPERTY(QSizeF totalOffset READ totalOffset) - Q_PROPERTY(QSizeF lastOffset READ lastOffset) - Q_PROPERTY(QSizeF offset READ offset) - -public: - QPanGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - - QSizeF totalOffset() const; - QSizeF lastOffset() const; - QSizeF offset() const; - -protected: - void reset(); - -private: - bool event(QEvent *event); - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; - friend class QAbstractScrollAreaPrivate; -}; - -class QPinchGesturePrivate; -class Q_GUI_EXPORT QPinchGesture : public QGesture -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPinchGesture) - -public: - enum WhatChange { - ScaleFactorChanged = 0x1, - RotationAngleChanged = 0x2, - CenterPointChanged = 0x4 - }; - Q_DECLARE_FLAGS(WhatChanged, WhatChange) - - Q_PROPERTY(WhatChanged whatChanged READ whatChanged) - - Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor) - Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor) - Q_PROPERTY(qreal scaleFactor READ scaleFactor) - - Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle) - Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle) - Q_PROPERTY(qreal rotationAngle READ rotationAngle) - - Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint) - Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint) - Q_PROPERTY(QPointF centerPoint READ centerPoint) - -public: - - QPinchGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - void reset(); - - WhatChanged whatChanged() const; - - QPointF startCenterPoint() const; - QPointF lastCenterPoint() const; - QPointF centerPoint() const; - - qreal totalScaleFactor() const; - qreal lastScaleFactor() const; - qreal scaleFactor() const; - - qreal totalRotationAngle() const; - qreal lastRotationAngle() const; - qreal rotationAngle() const; - -private: - bool event(QEvent *event); - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; -}; - -class QSwipeGesturePrivate; -class Q_GUI_EXPORT QSwipeGesture : public QGesture -{ - Q_OBJECT - Q_ENUMS(SwipeDirection) - - Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection) - Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection) - Q_PROPERTY(qreal swipeAngle READ swipeAngle) - - Q_DECLARE_PRIVATE(QSwipeGesture) - -public: - enum SwipeDirection { NoDirection, Left, Right, Up, Down }; - QSwipeGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - void reset(); - - SwipeDirection horizontalDirection() const; - SwipeDirection verticalDirection() const; - qreal swipeAngle() const; - -private: - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; -}; -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QSTANDARDGESTURES_H diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h index 79aadfd..fec5c2f 100644 --- a/src/gui/kernel/qstandardgestures_p.h +++ b/src/gui/kernel/qstandardgestures_p.h @@ -53,83 +53,20 @@ // We mean it. // -#include "qevent.h" -#include "qbasictimer.h" -#include "qdebug.h" - -#include "qgesture.h" -#include "qgesture_p.h" - -#include "qstandardgestures.h" -#include "qbasictimer.h" +#include "qgesturerecognizer.h" +#include "private/qgesture_p.h" QT_BEGIN_NAMESPACE -class QPanGesturePrivate : public QGesturePrivate -{ - Q_DECLARE_PUBLIC(QPanGesture) - -public: - void setupGestureTarget(QObject *o); - - QSizeF totalOffset; - QSizeF lastOffset; - QSizeF offset; - QPointF lastPosition; - -#if defined(QT_MAC_USE_COCOA) - QBasicTimer singleTouchPanTimer; - QPointF prevMousePos; -#endif -}; - -class QPinchGesturePrivate : public QGesturePrivate +class QPanGestureRecognizer : public QGestureRecognizer { - Q_DECLARE_PUBLIC(QPinchGesture) - public: - QPinchGesturePrivate() - : changes(0), totalScaleFactor(0.), lastScaleFactor(0.), scaleFactor(0.), - totalRotationAngle(0.), lastRotationAngle(0.), rotationAngle(0.) -#ifdef Q_WS_WIN - ,initialDistance(0), lastSequenceId(0) -#endif - { - } + QPanGestureRecognizer(); - void setupGestureTarget(QObject *o); - - QPinchGesture::WhatChanged changes; - - qreal totalScaleFactor; // total scale factor, excluding the current sequence. - qreal lastScaleFactor; - qreal scaleFactor; // scale factor in the current sequence. - - qreal totalRotationAngle; // total rotation angle, excluding the current sequence. - qreal lastRotationAngle; - qreal rotationAngle; // rotation angle in the current sequence. - - QPointF startCenterPoint; - QPointF lastCenterPoint; - QPointF centerPoint; -#ifdef Q_WS_WIN - int initialDistance; - ulong lastSequenceId; -#endif -}; - -class QSwipeGesturePrivate : public QGesturePrivate -{ - Q_DECLARE_PUBLIC(QSwipeGesture) - -public: - QSwipeGesturePrivate() - : swipeAngle(-1) - { - } + QGesture *createGesture(QObject *target); - void setupGestureTarget(QObject *o); - qreal swipeAngle; + QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 4cbf762..8da415f 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -115,6 +115,7 @@ #include "private/qevent_p.h" #include "private/qgraphicssystem_p.h" +#include "private/qgesturemanager_p.h" // widget/widget data creation count //#define QWIDGET_EXTRA_DEBUG @@ -901,9 +902,8 @@ void QWidget::setAutoFillBackground(bool enabled) \sa QEvent, QPainter, QGridLayout, QBoxLayout \section1 Softkeys - \since 4.6 - Softkeys are usually physical keys on a device that have a corresponding label or + Since Qt 4.6, Softkeys are usually physical keys on a device that have a corresponding label or other visual representation on the screen that is generally located next to its physical counterpart. They are most often found on mobile phone platforms. In modern touch based user interfaces it is also possible to have softkeys that do @@ -1502,6 +1502,8 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier mapper->remove(data.winid); } + const WId oldWinId = data.winid; + data.winid = id; #if defined(Q_WS_X11) hd = id; // X11: hd == ident @@ -1509,6 +1511,16 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier if (mapper && id && !userDesktopWidget) { mapper->insert(data.winid, q); } + + if(oldWinId != id) { + // Do not emit an event when the old winId is destroyed. This only + // happens (a) during widget destruction, and (b) immediately prior + // to creation of a new winId, for example as a result of re-parenting. + if(id != 0) { + QEvent e(QEvent::WinIdChange); + QCoreApplication::sendEvent(q, &e); + } + } } void QWidgetPrivate::createTLExtra() @@ -2227,8 +2239,8 @@ QWidget *QWidget::find(WId id) against. If Qt is using Carbon, the {WId} is actually an HIViewRef. If Qt is using Cocoa, {WId} is a pointer to an NSView. - \note We recommend that you do not store this value as it is likely to - change at run-time. + This value may change at run-time. An event with type QEvent::WinIdChange + will be sent to the widget following a change in window system identifier. \sa find() */ @@ -8333,6 +8345,9 @@ bool QWidget::event(QEvent *event) (void) QApplication::sendEvent(this, &mouseEvent); break; } + case QEvent::Gesture: + event->ignore(); + break; #ifndef QT_NO_PROPERTIES case QEvent::DynamicPropertyChange: { const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName(); @@ -11669,6 +11684,19 @@ QGraphicsProxyWidget *QWidget::graphicsProxyWidget() const Synonym for QList<QWidget *>. */ +/*! + Subscribes the widget to a given \a gesture with a \a context. + + \sa QGestureEvent + \since 4.6 +*/ +void QWidget::grabGesture(Qt::GestureType gesture, Qt::GestureContext context) +{ + Q_D(QWidget); + d->gestureContext.insert(gesture, context); + (void)QGestureManager::instance(); // create a gesture manager +} + QT_END_NAMESPACE #include "moc_qwidget.cpp" @@ -11982,3 +12010,10 @@ void QWidget::clearMask() XRender extension is not supported on the X11 display, or if the handle could not be created. */ + +#ifdef Q_OS_SYMBIAN +void QWidgetPrivate::_q_delayedDestroy(WId winId) +{ + delete winId; +} +#endif diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 76418af..e603a1a 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -96,7 +96,6 @@ class QIcon; class QWindowSurface; class QLocale; class QGraphicsProxyWidget; -class QGestureManager; class QGraphicsEffect; #if defined(Q_WS_X11) class QX11Info; @@ -355,6 +354,8 @@ public: QGraphicsEffect *graphicsEffect() const; void setGraphicsEffect(QGraphicsEffect *effect); + void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture); + public Q_SLOTS: void setWindowTitle(const QString &); #ifndef QT_NO_STYLE_STYLESHEET @@ -725,18 +726,17 @@ private: friend class QGLContext; friend class QGLWidget; friend class QGLWindowSurface; - friend class QGLWindowSurfaceGLPaintDevice; - friend class QVGWindowSurface; friend class QX11PaintEngine; friend class QWin32PaintEngine; friend class QShortcutPrivate; friend class QShortcutMap; friend class QWindowSurface; - friend class QD3DWindowSurface; friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidgetPrivate; friend class QStyleSheetStyle; friend struct QWidgetExceptionCleaner; + friend class QGestureManager; + friend class QWinNativePanGestureRecognizer; #ifdef Q_WS_MAC friend class QCoreGraphicsPaintEnginePrivate; @@ -773,6 +773,9 @@ private: private: Q_DISABLE_COPY(QWidget) Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden()) +#ifdef Q_OS_SYMBIAN + Q_PRIVATE_SLOT(d_func(), void _q_delayedDestroy(WId winId)) +#endif QWidgetData *data; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index c06ef73..f7c2712 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -64,6 +64,8 @@ #include "QtGui/qapplication.h" #include <private/qgraphicseffect_p.h> +#include <private/qgesture_p.h> + #ifdef Q_WS_WIN #include "QtCore/qt_windows.h" #include <private/qdnd_p.h> @@ -294,7 +296,8 @@ public: void setMask_sys(const QRegion &); #ifdef Q_OS_SYMBIAN void setSoftKeys_sys(const QList<QAction*> &softkeys); - void activateSymbianWindow(); + void activateSymbianWindow(WId wid = 0); + void _q_delayedDestroy(WId winId); #endif void raise_sys(); @@ -578,6 +581,7 @@ public: #ifndef QT_NO_ACTION QList<QAction*> actions; #endif + QMap<Qt::GestureType, Qt::GestureContext> gestureContext; // Bit fields. uint high_attributes[3]; // the low ones are in QWidget::widget_attributes @@ -604,6 +608,7 @@ public: bool isBackgroundInherited() const; #elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() + uint nativeGesturePanEnabled : 1; bool shouldShowMaximizeButton(); void winUpdateIsOpaque(); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 3328cee..8ce5001 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -56,6 +56,12 @@ #include <aknappui.h> #endif +// This is necessary in order to be able to perform delayed invokation on slots +// which take arguments of type WId. One example is +// QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of +// CCoeControl objects until after the CONE event handler has finished running. +Q_DECLARE_METATYPE(WId) + QT_BEGIN_NAMESPACE extern bool qt_nograb(); @@ -318,8 +324,6 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de bool desktop = (type == Qt::Desktop); //bool tool = (type == Qt::Tool || type == Qt::Drawer); - WId id = 0; - if (popup) flags |= Qt::WindowStaysOnTopHint; // a popup stays on top @@ -341,13 +345,10 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de data.crect.setSize(QSize(width, height)); } - CCoeControl *destroyw = 0; + CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0; createExtra(); if (window) { - if (destroyOldWindow) - destroyw = data.winid; - id = window; setWinId(window); TRect tr = window->Rect(); data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); @@ -355,10 +356,15 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de } else if (topLevel) { if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); - QSymbianControl *control= q_check_ptr(new QSymbianControl(q)); - id = (WId)control; - setWinId(id); - QT_TRAP_THROWING(control->ConstructL(true,desktop)); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); + QT_TRAP_THROWING(control->ConstructL(true, desktop)); + + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; if (!desktop) { TInt stackingFlags; @@ -368,7 +374,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -391,11 +397,22 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de int x, y, w, h; data.crect.getRect(&x, &y, &w, &h); control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget - QSymbianControl *control = new QSymbianControl(q); - setWinId(control); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); QT_TRAP_THROWING(control->ConstructL(!parentWidget)); + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; + TInt stackingFlags; if ((q->windowType() & Qt::Popup) == Qt::Popup) { stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; @@ -403,7 +420,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -418,12 +435,21 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de | EPointerFilterMove | EPointerFilterDrag, 0); if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) - activateSymbianWindow(); + activateSymbianWindow(control.data()); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); } if (destroyw) { destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); - CBase::Delete(destroyw); + + // Delay deletion of the control in case this function is called in the + // context of a CONE event handler such as + // CCoeControl::ProcessPointerEventL + QMetaObject::invokeMethod(q, "_q_delayedDestroy", + Qt::QueuedConnection, Q_ARG(WId, destroyw)); } if (q->testAttribute(Qt::WA_AcceptTouchEvents)) @@ -434,7 +460,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de void QWidgetPrivate::show_sys() { Q_Q(QWidget); - + if (q->testAttribute(Qt::WA_OutsideWSRange)) return; @@ -468,7 +494,7 @@ void QWidgetPrivate::show_sys() invalidateBuffer(q->rect()); } -void QWidgetPrivate::activateSymbianWindow() +void QWidgetPrivate::activateSymbianWindow(WId wid) { Q_Q(QWidget); @@ -476,8 +502,12 @@ void QWidgetPrivate::activateSymbianWindow() Q_ASSERT(q->testAttribute(Qt::WA_Mapped)); Q_ASSERT(!extra->activated); - WId id = q->internalWinId(); - QT_TRAP_THROWING(id->ActivateL()); + if(!wid) + wid = q->internalWinId(); + + Q_ASSERT(wid); + + QT_TRAP_THROWING(wid->ActivateL()); extra->activated = 1; } @@ -490,7 +520,12 @@ void QWidgetPrivate::hide_sys() QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId()); if (id) { - if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() + //Incorrect optimisation - for popup windows, Qt's focus is moved before + //hide_sys is called, resulting in the popup window keeping its elevated + //position in the CONE control stack. + //This can result in keyboard focus being in an invisible widget in some + //conditions - e.g. QTBUG-4733 + //if(id->IsFocused()) // Avoid unnecessary calls to FocusChanged() id->setFocusSafely(false); id->MakeVisible(false); if (QWidgetBackingStore *bs = maybeBackingStore()) @@ -566,8 +601,14 @@ void QWidgetPrivate::reparentChildren() w->d_func()->invalidateBuffer(w->rect()); WId parent = q->effectiveWinId(); WId child = w->effectiveWinId(); - if (parent != child) - child->SetParent(parent); + if (parent != child) { + // Child widget is native. Because Symbian windows cannot be + // re-parented, we must re-create the window. + const WId window = 0; + const bool initializeWindow = false; + const bool destroyOldWindow = true; + w->d_func()->create_sys(window, initializeWindow, destroyOldWindow); + } // ### TODO: We probably also need to update the component array here w->d_func()->reparentChildren(); } else { @@ -1253,7 +1294,7 @@ void QWidget::grabMouse() WId id = effectiveWinId(); id->SetPointerCapture(true); QWidgetPrivate::mouseGrabber = this; - + #ifndef QT_NO_CURSOR QApplication::setOverrideCursor(cursor()); #endif diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index a0982f4..2b11bec 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -2029,11 +2029,6 @@ void QWidgetPrivate::winSetupGestures() if (!q || !q->isVisible()) return; QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::const_iterator it = - qAppPriv->widgetGestures.find(q); - if (it == qAppPriv->widgetGestures.end()) - return; - const QStandardGestures &gestures = it.value(); WId winid = q->effectiveWinId(); bool needh = false; @@ -2052,10 +2047,10 @@ void QWidgetPrivate::winSetupGestures() singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; } if (winid && qAppPriv->SetGestureConfig) { - GESTURECONFIG gc[3]; + GESTURECONFIG gc[1]; memset(gc, 0, sizeof(gc)); gc[0].dwID = GID_PAN; - if (gestures.pan) { + if (nativeGesturePanEnabled) { gc[0].dwWant = GC_PAN; if (needv && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; @@ -2069,16 +2064,16 @@ void QWidgetPrivate::winSetupGestures() gc[0].dwBlock = GC_PAN; } - gc[1].dwID = GID_ZOOM; - if (gestures.pinch) - gc[1].dwWant = GC_ZOOM; - else - gc[1].dwBlock = GC_ZOOM; - gc[2].dwID = GID_ROTATE; - if (gestures.pinch) - gc[2].dwWant = GC_ROTATE; - else - gc[2].dwBlock = GC_ROTATE; +// gc[1].dwID = GID_ZOOM; +// if (gestures.pinch) +// gc[1].dwWant = GC_ZOOM; +// else +// gc[1].dwBlock = GC_ZOOM; +// gc[2].dwID = GID_ROTATE; +// if (gestures.pinch) +// gc[2].dwWant = GC_ROTATE; +// else +// gc[2].dwBlock = GC_ROTATE; qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); } diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp new file mode 100644 index 0000000..4619594 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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 QtGui module 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 "private/qwinnativepangesturerecognizer_win_p.h" + +#include "qevent.h" +#include "qgraphicsitem.h" +#include "qgesture.h" + +#include "private/qgesture_p.h" +#include "private/qevent_p.h" +#include "private/qapplication_p.h" +#include "private/qwidget_p.h" + +QT_BEGIN_NAMESPACE + +QWinNativePanGestureRecognizer::QWinNativePanGestureRecognizer() +{ +} + +QGesture* QWinNativePanGestureRecognizer::createGesture(QObject *target) const +{ + if (!target) + return new QPanGesture; // a special case + if (qobject_cast<QGraphicsObject*>(target)) + return 0; + if (!target->isWidgetType()) + return 0; + + QWidget *q = static_cast<QWidget*>(target); + QWidgetPrivate *d = q->d_func(); + d->nativeGesturePanEnabled = true; + d->winSetupGestures(); + + return new QPanGesture; +} + +QGestureRecognizer::Result QWinNativePanGestureRecognizer::filterEvent(QGesture *state, QObject *, QEvent *event) +{ + QPanGesture *q = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = q->d_func(); + + QGestureRecognizer::Result result = QGestureRecognizer::Ignore; + if (event->type() == QEvent::NativeGesture) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + break; + case QNativeGestureEvent::Pan: + result = QGestureRecognizer::GestureTriggered; + event->accept(); + break; + case QNativeGestureEvent::GestureEnd: + if (q->state() == Qt::NoGesture) + return QGestureRecognizer::Ignore; // some other gesture has ended + result = QGestureRecognizer::GestureFinished; + break; + default: + return QGestureRecognizer::Ignore; + } + if (q->state() == Qt::NoGesture) { + d->lastOffset = d->totalOffset = d->offset = QSize(); + } else { + d->lastOffset = d->offset; + d->offset = QSize(ev->position.x() - d->lastPosition.x(), + ev->position.y() - d->lastPosition.y()); + d->totalOffset += d->offset; + } + d->lastPosition = ev->position; + } + return result; +} + +void QWinNativePanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->lastPosition = QPoint(); + d->acceleration = 0; + + QGestureRecognizer::reset(state); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h new file mode 100644 index 0000000..a1e8511 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 QtGui module 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$ +** +****************************************************************************/ + +#ifndef QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H +#define QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QGestureRecognizer> + +QT_BEGIN_NAMESPACE + +class QWinNativePanGestureRecognizer : public QGestureRecognizer +{ +public: + QWinNativePanGestureRecognizer(); + + QGesture* createGesture(QObject *target) const; + + QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +QT_END_NAMESPACE + +#endif // QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index d9b824b..4da993b 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -176,22 +176,25 @@ QT_BEGIN_NAMESPACE \section1 Predefined Colors - There are 20 predefined QColors: Qt::white, Qt::black, - Qt::red, Qt::darkRed, Qt::green, Qt::darkGreen, Qt::blue, - Qt::darkBlue, Qt::cyan, Qt::darkCyan, Qt::magenta, - Qt::darkMagenta, Qt::yellow, Qt::darkYellow, Qt::gray, - Qt::darkGray, Qt::lightGray, Qt::color0, Qt::color1, and - Qt::transparent. + There are 20 predefined QColors described by the Qt::GlobalColor enum, + including black, white, primary and secondary colors, darker versions + of these colors and three shades of gray. QColor also recognizes a + variety of color names; the static colorNames() function returns a + QStringList color names that QColor knows about. \img qt-colors.png Qt Colors - QColor provides the static colorNames() function which returns a - QStringList containing the color names Qt knows about. + Additionally, the Qt::color0, Qt::color1 and Qt::transparent colors + are used for special purposes. - The colors Qt::color0 (zero pixel value) and Qt::color1 (non-zero - pixel value) are special colors for drawing in QBitmaps. Painting with - Qt::color0 sets the bitmap bits to 0 (transparent, i.e. background), and - painting with Qt::color1 sets the bits to 1 (opaque, i.e. foreground). + Qt::color0 (zero pixel value) and Qt::color1 (non-zero pixel value) + are special colors for drawing in QBitmaps. Painting with Qt::color0 + sets the bitmap bits to 0 (transparent; i.e., background), and painting + with Qt::color1 sets the bits to 1 (opaque; i.e., foreground). + + Qt::transparent is used to indicate a transparent pixel. When painting + with this value, a pixel value will be used that is appropriate for the + underlying pixel format in use. \section1 The HSV Color Model diff --git a/src/gui/painting/qdrawutil.cpp b/src/gui/painting/qdrawutil.cpp index c20d8d8..1182b9a 100644 --- a/src/gui/painting/qdrawutil.cpp +++ b/src/gui/painting/qdrawutil.cpp @@ -1147,8 +1147,8 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin yTarget[rows - 1] = targetCenterBottom; yTarget[rows] = targetRect.top() + targetRect.height(); - qreal dx; - qreal dy; + qreal dx = targetCenterWidth; + qreal dy = targetCenterHeight; switch (rules.horizontal) { case Qt::StretchTile: diff --git a/src/gui/painting/qpaintdevice.cpp b/src/gui/painting/qpaintdevice.cpp index 95c0b44..6114938 100644 --- a/src/gui/painting/qpaintdevice.cpp +++ b/src/gui/painting/qpaintdevice.cpp @@ -65,4 +65,9 @@ int QPaintDevice::metric(PaintDeviceMetric) const return 0; } +Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, QPaintDevice::PaintDeviceMetric metric) +{ + return device->metric(metric); +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h index 92aa3cb..c8e86b8 100644 --- a/src/gui/painting/qpaintdevice.h +++ b/src/gui/painting/qpaintdevice.h @@ -137,6 +137,7 @@ public: friend class QPainter; friend class QFontEngineMac; friend class QX11PaintEngine; + friend Q_GUI_EXPORT int qt_paint_device_metric(const QPaintDevice *device, PaintDeviceMetric metric); }; #ifdef QT3_SUPPORT diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 6037bd5..240403d 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -4213,13 +4213,6 @@ void QRasterBuffer::prepare(QCustomRasterPaintDevice *device) drawHelper = qDrawHelper + format; } -class MetricAccessor : public QWidget { -public: - int metric(PaintDeviceMetric m) { - return QWidget::metric(m); - } -}; - int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const { switch (m) { @@ -4231,7 +4224,7 @@ int QCustomRasterPaintDevice::metric(PaintDeviceMetric m) const break; } - return (static_cast<MetricAccessor*>(widget)->metric(m)); + return qt_paint_device_metric(widget, m); } int QCustomRasterPaintDevice::bytesPerLine() const diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp index e17dba1..6f4f398 100644 --- a/src/gui/painting/qpaintengine_s60.cpp +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate { public: - QS60PaintEnginePrivate(QS60PaintEngine *engine) { } + QS60PaintEnginePrivate(QS60PaintEngine *engine) { Q_UNUSED(engine); } }; QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data) diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index d712669..195be0a 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -932,7 +932,7 @@ void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, con fill(path, brush); } -void QPaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) +void QPaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints /*hints*/) { qreal oldOpacity = state()->opacity; QTransform oldTransform = state()->matrix; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 81ed06b..3ec9bd6 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -54,6 +54,7 @@ // #include <QtGui/qpaintengine.h> +#include <QtGui/qdrawutil.h> #include <private/qpaintengine_p.h> #include <private/qstroker_p.h> @@ -71,12 +72,6 @@ class QPainterState; class QPaintEngineExPrivate; struct StrokeHandler; -namespace QDrawPixmaps -{ - struct Data; - enum DrawingHint; -} - struct QIntRect { int x1, y1, x2, y2; inline void set(const QRect &r) { diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index a050cb2..41efc80 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -411,6 +411,8 @@ Qt::PenStyle QPen::style() const pattern using the setDashPattern() function which implicitly converts the style of the pen to Qt::CustomDashLine. + \note This function resets the dash offset to zero. + \sa style(), {QPen#Pen Style}{Pen Style} */ @@ -420,7 +422,9 @@ void QPen::setStyle(Qt::PenStyle s) return; detach(); d->style = s; - static_cast<QPenData *>(d)->dashPattern.clear(); + QPenData *dd = static_cast<QPenData *>(d); + dd->dashPattern.clear(); + dd->dashOffset = 0; } /*! @@ -538,8 +542,12 @@ void QPen::setDashOffset(qreal offset) if (qFuzzyCompare(offset, static_cast<QPenData *>(d)->dashOffset)) return; detach(); - static_cast<QPenData *>(d)->dashOffset = offset; - d->style = Qt::CustomDashLine; + QPenData *dd = static_cast<QPenData *>(d); + dd->dashOffset = offset; + if (d->style != Qt::CustomDashLine) { + dd->dashPattern = dashPattern(); + d->style = Qt::CustomDashLine; + } } /*! diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index 664ad48..dc4e43b 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -85,7 +85,9 @@ QS60WindowSurface::~QS60WindowSurface() void QS60WindowSurface::beginPaint(const QRegion &rgn) { if (!qt_widget_private(window())->isOpaque) { - QImage image = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data())->image; + QS60PixmapData *pixmapData = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data()); + pixmapData->beginDataAccess(); + QImage &image = pixmapData->image; QRgb *data = reinterpret_cast<QRgb *>(image.bits()); const int row_stride = image.bytesPerLine() / 4; @@ -103,6 +105,7 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn) row += row_stride; } } + pixmapData->endDataAccess(); } } diff --git a/src/gui/s60framework/qs60mainapplication.cpp b/src/gui/s60framework/qs60mainapplication.cpp index 2973c97..82e7743 100644 --- a/src/gui/s60framework/qs60mainapplication.cpp +++ b/src/gui/s60framework/qs60mainapplication.cpp @@ -60,27 +60,32 @@ CApaApplication *newS60Application() _LIT(KQtWrapperResourceFile, "\\resource\\apps\\s60main.rsc"); /*! - * \class QS60MainApplication - * \obsolete - * \since 4.6 - * \brief The QS60MainApplication class provides support for migration from S60. - * - * The QS60MainApplication provides a helper class for use in migrating from existing S60 based - * applications to Qt based applications. It is used in the exact same way as the - * \c CAknApplication class from Symbian, but internally provides extensions used by Qt. - * - * When modifying old S60 applications that rely on implementing functions in \c CAknApplication, - * the class should be modified to inherit from this class instead of \c CAknApplication. Then the - * application can choose to override only certain functions. To make Qt use the custom application - * objects, pass a factory function to - * QApplication::QApplication(QApplication::QS60MainApplicationFactory, int &, char **). - * - * For more information on \c CAknApplication, please see the S60 documentation. - * - * Unlike other Qt classes, QS60MainApplication behaves like an S60 class, and can throw Symbian - * leaves. - * - * \sa QS60MainDocument, QS60MainAppUi, QApplication::QS60MainApplicationFactory + \class QS60MainApplication + \since 4.6 + \brief The QS60MainApplication class provides support for migration from S60. + + \warning This class is provided only to get access to S60 specific + functionality in the application framework classes. It is not + portable. We strongly recommend against using it in new applications. + + The QS60MainApplication provides a helper class for use in migrating + from existing S60 based applications to Qt based applications. It is + used in the exact same way as the \c CAknApplication class from + Symbian, but internally provides extensions used by Qt. + + When modifying old S60 applications that rely on implementing + functions in \c CAknApplication, the class should be modified to + inherit from this class instead of \c CAknApplication. Then the + application can choose to override only certain functions. To make + Qt use the custom application objects, pass a factory function to + \c{QApplication::QApplication(QApplication::QS60MainApplicationFactory, int &, char **)}. + + For more information on \c CAknApplication, please see the S60 documentation. + + Unlike other Qt classes, QS60MainApplication behaves like an S60 class, and can throw Symbian + leaves. + + \sa QS60MainDocument, QS60MainAppUi, QApplication::QS60MainApplicationFactory */ /*! diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp index d8181f8..e630253 100644 --- a/src/gui/s60framework/qs60mainappui.cpp +++ b/src/gui/s60framework/qs60mainappui.cpp @@ -58,25 +58,31 @@ QT_BEGIN_NAMESPACE /*! - * \class QS60MainAppUi - * \obsolete - * \since 4.6 - * \brief Helper class for S60 migration - * - * The QS60MainAppUi provides a helper class for use in migrating from existing S60 based - * applications to Qt based applications. It is used in the exact same way as the - * \c CAknAppUi class from Symbian, but internally provides extensions used by Qt. - * - * When modifying old S60 applications that rely on implementing functions in \c CAknAppUi, - * the class should be modified to inherit from this class instead of \c CAknAppUi. Then the - * application can choose to override only certain functions. - * - * For more information on \c CAknAppUi, please see the S60 documentation. - * - * Unlike other Qt classes, QS60MainAppUi behaves like an S60 class, and can throw Symbian - * leaves. - * - * \sa QS60MainDocument, QS60MainApplication + \class QS60MainAppUi + \since 4.6 + \brief The QS60MainAppUi class is a helper class for S60 migration. + + \warning This class is provided only to get access to S60 specific + functionality in the application framework classes. It is not + portable. We strongly recommend against using it in new applications. + + The QS60MainAppUi provides a helper class for use in migrating from + existing S60 based applications to Qt based applications. It is used + in the exact same way as the \c CAknAppUi class from Symbian, but + internally provides extensions used by Qt. + + When modifying old S60 applications that rely on implementing + functions in \c CAknAppUi, the class should be modified to inherit + from this class instead of \c CAknAppUi. Then the application can + choose to override only certain functions. + + For more information on \c CAknAppUi, please see the S60 + documentation. + + Unlike other Qt classes, QS60MainAppUi behaves like an S60 class, + and can throw Symbian leaves. + + \sa QS60MainDocument, QS60MainApplication */ /*! diff --git a/src/gui/s60framework/qs60maindocument.cpp b/src/gui/s60framework/qs60maindocument.cpp index 52595db..7405784 100644 --- a/src/gui/s60framework/qs60maindocument.cpp +++ b/src/gui/s60framework/qs60maindocument.cpp @@ -47,25 +47,31 @@ QT_BEGIN_NAMESPACE /*! - * \class QS60MainDocument - * \obsolete - * \since 4.6 - * \brief Helper class for S60 migration - * - * The QS60MainDocument provides a helper class for use in migrating from existing S60 based - * applications to Qt based applications. It is used in the exact same way as the - * \c CAknDocument class from Symbian, but internally provides extensions used by Qt. - * - * When modifying old S60 applications that rely on implementing functions in \c CAknDocument, - * the class should be modified to inherit from this class instead of \c CAknDocument. Then the - * application can choose to override only certain functions. - * - * For more information on \c CAknDocument, please see the S60 documentation. - * - * Unlike other Qt classes, QS60MainDocument behaves like an S60 class, and can throw Symbian - * leaves. - * - * \sa QS60MainApplication, QS60MainAppUi + \class QS60MainDocument + \since 4.6 + \brief The QS60MainDocument class is a helper class for S60 migration. + + \warning This class is provided only to get access to S60 specific + functionality in the application framework classes. It is not + portable. We strongly recommend against using it in new applications. + + The QS60MainDocument provides a helper class for use in migrating + from existing S60 based applications to Qt based applications. It is + used in the exact same way as the \c CAknDocument class from + Symbian, but internally provides extensions used by Qt. + + When modifying old S60 applications that rely on implementing + functions in \c CAknDocument, the class should be modified to + inherit from this class instead of \c CAknDocument. Then the + application can choose to override only certain functions. + + For more information on \c CAknDocument, please see the S60 + documentation. + + Unlike other Qt classes, QS60MainDocument behaves like an S60 class, + and can throw Symbian leaves. + + \sa QS60MainApplication, QS60MainAppUi */ /*! diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp index d62f717..6ec5796 100644 --- a/src/gui/styles/gtksymbols.cpp +++ b/src/gui/styles/gtksymbols.cpp @@ -984,15 +984,18 @@ QIcon QGtk::getFilesystemIcon(const QFileInfo &info) if (QGtk::gnome_vfs_init && QGtk::gnome_icon_lookup_sync) { QGtk::gnome_vfs_init(); GtkIconTheme *theme = QGtk::gtk_icon_theme_get_default(); - QString fileurl = QUrl::fromLocalFile(info.absoluteFilePath()).toEncoded(); + QByteArray fileurl = QUrl::fromLocalFile(info.absoluteFilePath()).toEncoded(); char * icon_name = QGtk::gnome_icon_lookup_sync(theme, NULL, - qPrintable(fileurl), + fileurl.data(), NULL, GNOME_ICON_LOOKUP_FLAGS_NONE, NULL); - return QIcon::fromTheme(icon_name); + QString iconName = QString::fromUtf8(icon_name); g_free(icon_name); + if (iconName.startsWith(QLatin1Char('/'))) + return QIcon(iconName); + return QIcon::fromTheme(iconName); } return icon; } diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index df4f866..5886512 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -63,7 +63,6 @@ #include <qtoolbar.h> #include <qtoolbutton.h> #include <qrubberband.h> -#include <../kernel/qkde_p.h> #include <private/qcommonstylepixmaps_p.h> #include <private/qmath_p.h> #include <private/qstylehelper_p.h> @@ -75,6 +74,7 @@ #include <qdir.h> #include <qsettings.h> #include <qpixmapcache.h> +#include <private/qguiplatformplugin_p.h> #include <limits.h> @@ -837,35 +837,6 @@ static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbut } #endif // QT_NO_TOOLBUTTON - -#ifdef Q_WS_X11 // These functions are used to parse the X11 freedesktop icon spec - -/*!internal - -Checks if you are running KDE and looks up the toolbar -from the KDE configuration file - -*/ -int QCommonStylePrivate::lookupToolButtonStyle() const -{ - int result = Qt::ToolButtonIconOnly; - if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4) { - QSettings settings(QKde::kdeHome() + - QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - settings.beginGroup(QLatin1String("Toolbar style")); - QString toolbarStyle = settings.value(QLatin1String("ToolButtonStyle"), QLatin1String("TextBesideIcon")).toString(); - if (toolbarStyle == QLatin1String("TextBesideIcon")) - result = Qt::ToolButtonTextBesideIcon; - else if (toolbarStyle == QLatin1String("TextOnly")) - result = Qt::ToolButtonTextOnly; - else if (toolbarStyle == QLatin1String("TextUnderIcon")) - result = Qt::ToolButtonTextUnderIcon; - } - return result; -} - -#endif //Q_WS_X11 - #ifndef QT_NO_ITEMVIEWS QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItemV4 *option, int role) const @@ -4688,19 +4659,8 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid break; case PM_ToolBarIconSize: -#ifdef Q_WS_X11 - if (X11->desktopVersion >= 4) { - static int iconSize = 0; - if (!iconSize) { - QSettings settings(QKde::kdeHome() + - QLatin1String("/share/config/kdeglobals"), - QSettings::IniFormat); - settings.beginGroup(QLatin1String("ToolbarIcons")); - iconSize = settings.value(QLatin1String("Size"), QLatin1String("22")).toInt(); - } - ret = iconSize; - } else -#endif + ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ToolBarIconSize); + if (!ret) ret = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); break; @@ -5098,7 +5058,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget break; case SH_ItemView_ActivateItemOnSingleClick: - ret = false; + ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ItemView_ActivateItemOnSingleClick); break; case SH_TitleBar_ModifyNotification: @@ -5192,13 +5152,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget ret = true; break; case SH_ToolButtonStyle: - ret = Qt::ToolButtonIconOnly; -#ifdef Q_WS_X11 - { - static int buttonStyle = d_func()->lookupToolButtonStyle(); - return buttonStyle; - } -#endif + ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ToolButtonStyle); break; case SH_RequestSoftwareInputPanel: ret = RSIP_OnMouseClickAndAlreadyFocused; diff --git a/src/gui/styles/qcommonstyle_p.h b/src/gui/styles/qcommonstyle_p.h index 7162392..a905601 100644 --- a/src/gui/styles/qcommonstyle_p.h +++ b/src/gui/styles/qcommonstyle_p.h @@ -122,7 +122,6 @@ public: } #endif mutable QIcon tabBarcloseButtonIcon; - int lookupToolButtonStyle() const; #ifndef QT_NO_TABBAR void tabLayout(const QStyleOptionTabV3 *opt, const QWidget *widget, QRect *textRect, QRect *pixmapRect) const; #endif diff --git a/src/gui/styles/qplastiquestyle.cpp b/src/gui/styles/qplastiquestyle.cpp index 5052755..ce2109a 100644 --- a/src/gui/styles/qplastiquestyle.cpp +++ b/src/gui/styles/qplastiquestyle.cpp @@ -3309,7 +3309,7 @@ void QPlastiqueStyle::drawControl(ControlElement element, const QStyleOption *op // Draw the text centered QFont font = painter->font(); - font.setPointSize(font.pointSize() - 1); + font.setPointSize(QFontInfo(font).pointSize() - 1); painter->setFont(font); painter->setPen(dockWidget->palette.windowText().color()); painter->drawText(titleRect, diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 6bdb79e..4fa1d03 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -706,11 +706,10 @@ void QS60StylePrivate::setThemePalette(QPalette *palette) const palette->setColor(QPalette::AlternateBase, Qt::transparent); palette->setBrush(QPalette::Base, Qt::transparent); // set button and tooltipbase based on pixel colors -// After natitive pixmap support, colorFromFrameGraphics caused reproducable crashes on some setups. -// const QColor buttonColor = colorFromFrameGraphics(SF_ButtonNormal); -// palette->setColor(QPalette::Button, buttonColor); -// const QColor toolTipColor = colorFromFrameGraphics(SF_ToolTip); -// palette->setColor(QPalette::ToolTipBase, toolTipColor); + const QColor buttonColor = colorFromFrameGraphics(SF_ButtonNormal); + palette->setColor(QPalette::Button, buttonColor); + const QColor toolTipColor = colorFromFrameGraphics(SF_ToolTip); + palette->setColor(QPalette::ToolTipBase, toolTipColor); palette->setColor(QPalette::Light, palette->color(QPalette::Button).lighter()); palette->setColor(QPalette::Dark, palette->color(QPalette::Button).darker()); palette->setColor(QPalette::Midlight, palette->color(QPalette::Button).lighter(125)); @@ -1865,7 +1864,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, painter->save(); painter->setRenderHint(QPainter::Antialiasing); painter->setOpacity(opacity); - painter->setPen(QPen(option->palette.color(QPalette::Highlight), penWidth)); + painter->setPen(QPen(option->palette.color(QPalette::Text), penWidth)); painter->drawRoundedRect(adjustedRect, roundRectRadius, roundRectRadius); painter->restore(); } diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 0aed71a..738e36a 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -949,7 +949,7 @@ struct QtFontDesc #if !defined(Q_WS_MAC) static void match(int script, const QFontDef &request, const QString &family_name, const QString &foundry_name, int force_encoding_id, - QtFontDesc *desc, const QList<int> &blacklistedFamilies = QList<int>()); + QtFontDesc *desc, const QList<int> &blacklistedFamilies = QList<int>(), bool forceXLFD=false); #if defined(Q_WS_X11) || defined(Q_WS_QWS) static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef) @@ -1316,7 +1316,7 @@ unsigned int bestFoundry(int script, unsigned int score, int styleStrategy, */ static void match(int script, const QFontDef &request, const QString &family_name, const QString &foundry_name, int force_encoding_id, - QtFontDesc *desc, const QList<int> &blacklistedFamilies) + QtFontDesc *desc, const QList<int> &blacklistedFamilies, bool forceXLFD) { Q_UNUSED(force_encoding_id); @@ -1351,7 +1351,12 @@ static void match(int script, const QFontDef &request, unsigned int score = ~0u; +#ifdef Q_WS_X11 + load(family_name, script, forceXLFD); +#else + Q_UNUSED(forceXLFD); load(family_name, script); +#endif QFontDatabasePrivate *db = privateDb(); for (int x = 0; x < db->count; ++x) { diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index ae93f90..382c4fe 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -1204,9 +1204,9 @@ static void loadFontConfig() static void initializeDb(); -static void load(const QString &family = QString(), int script = -1) +static void load(const QString &family = QString(), int script = -1, bool forceXLFD = false) { - if (X11->has_fontconfig) { + if (X11->has_fontconfig && !forceXLFD) { initializeDb(); return; } @@ -1784,7 +1784,7 @@ QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &req QString family, foundry; QT_PREPEND_NAMESPACE(parseFontName)(families_and_foundries.at(i), foundry, family); FM_DEBUG("loadXlfd: >>>>>>>>>>>>>>trying to match '%s' encoding=%d", family.toLatin1().data(), force_encoding_id); - QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc); + QT_PREPEND_NAMESPACE(match)(script, request, family, foundry, force_encoding_id, &desc, QList<int>(), true); if (desc.family) break; } @@ -1847,23 +1847,26 @@ QFontEngine *QFontDatabase::loadXlfd(int screen, int script, const QFontDef &req } } else { QList<int> encodings; - if (desc.encoding) - encodings.append(int(desc.encoding->encoding)); + if (desc.encoding) { + if (desc.encoding->encoding >= 0) + encodings.append(int(desc.encoding->encoding)); + } if (desc.size) { // append all other encodings for the matched font for (int i = 0; i < desc.size->count; ++i) { QtFontEncoding *e = desc.size->encodings + i; - if (e == desc.encoding) - continue; + if (e == desc.encoding || e->encoding < 0) + continue; encodings.append(int(e->encoding)); } } // fill in the missing encodings const XlfdEncoding *enc = xlfd_encoding; for (; enc->name; ++enc) { - if (!encodings.contains(enc->id)) + if (!encodings.contains(enc->id) && enc->id >= 0) { encodings.append(enc->id); + } } #if defined(FONT_MATCH_DEBUG) @@ -1925,6 +1928,13 @@ void QFontDatabase::load(const QFontPrivate *d, int script) #ifndef QT_NO_FONTCONFIG } else if (X11->has_fontconfig) { fe = loadFc(d, script, req); + + if (fe != 0 && fe->fontDef.pixelSize != req.pixelSize) { + delete fe; + fe = loadXlfd(d->screen, script, req); + } + + #endif } else if (mainThread) { fe = loadXlfd(d->screen, script, req); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index e5a88fc..21b9cca 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1160,7 +1160,7 @@ Q_GLOBAL_STATIC_WITH_INITIALIZER(QVector<QRgb>, qt_grayPalette, { QRgb *it = x->data(); for (int i = 0; i < x->size(); ++i, ++it) *it = 0xff000000 | i | (i<<8) | (i<<16); -}); +}) const QVector<QRgb> &QFontEngine::grayPalette() { diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 40db7b4..758d8af 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -138,9 +138,10 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, con QCFString name; ATSFontGetName(atsFontRef, kATSOptionFlagsDefault, &name); - QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pointSize); - QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pointSize, 0); - ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pointSize, 0, symbolicTraits, symbolicTraits); + + QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize); + QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, 0); + ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, 0, symbolicTraits, symbolicTraits); // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does // not exist for the given font. (for example italic) diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp index 5ea4554..ff3f628 100644 --- a/src/gui/text/qfontengine_x11.cpp +++ b/src/gui/text/qfontengine_x11.cpp @@ -488,9 +488,10 @@ glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout &glyphs) QFixed y = overall.yoff + glyphs.offsets[i].y - xcs->ascent; overall.x = qMin(overall.x, x); overall.y = qMin(overall.y, y); + // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel xmax = qMax(xmax, overall.xoff + glyphs.offsets[i].x + xcs->rbearing); ymax = qMax(ymax, y + xcs->ascent + xcs->descent); - overall.xoff += glyphs.advances_x[i]; + overall.xoff += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6); } else { QFixed size = _fs->ascent; overall.x = qMin(overall.x, overall.xoff); @@ -511,6 +512,8 @@ glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph) glyph_metrics_t gm; XCharStruct *xcs = charStruct(_fs, glyph); if (xcs) { + // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel + // XCharStruct::width is defined as the advance gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent, xcs->width, 0); } else { diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index db4c07c..ee8b751 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -505,9 +505,13 @@ void QTextControlPrivate::startDrag() drag->setMimeData(data); Qt::DropActions actions = Qt::CopyAction; - if (interactionFlags & Qt::TextEditable) + Qt::DropAction action; + if (interactionFlags & Qt::TextEditable) { actions |= Qt::MoveAction; - Qt::DropAction action = drag->exec(actions, Qt::MoveAction); + action = drag->exec(actions, Qt::MoveAction); + } else { + action = drag->exec(actions, Qt::CopyAction); + } if (action == Qt::MoveAction && drag->target() != contextWidget) cursor.removeSelectedText(); diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index 3521ade..9b7e8de 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -550,9 +550,9 @@ void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer, QTextCharFor } } if (format.hasProperty(QTextFormat::FontLetterSpacing)) - writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontLetterSpacing()) ); + writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontLetterSpacing())); if (format.hasProperty(QTextFormat::FontWordSpacing)) - writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontWordSpacing()) ); + writer.writeAttribute(foNS, QString::fromLatin1("word-spacing"), pixelToPoint(format.fontWordSpacing())); if (format.hasProperty(QTextFormat::FontUnderline)) writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-type"), format.fontUnderline() ? QString::fromLatin1("single") : QString::fromLatin1("none")); diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp index 9ae3a15..c0bd5e7 100644 --- a/src/gui/util/qdesktopservices_win.cpp +++ b/src/gui/util/qdesktopservices_win.cpp @@ -41,6 +41,7 @@ #include <qsettings.h> #include <qdir.h> +#include <qlibrary.h> #include <qurl.h> #include <qstringlist.h> #include <qprocess.h> @@ -58,6 +59,11 @@ # endif #endif +#if defined(Q_CC_MINGW) && !defined(CSIDL_MYMUSIC) +#define CSIDL_MYMUSIC 13 +#define CSIDL_MYVIDEO 14 +#endif + #ifndef QT_NO_DESKTOPSERVICES QT_BEGIN_NAMESPACE @@ -168,50 +174,76 @@ static bool launchWebBrowser(const QUrl &url) QString QDesktopServices::storageLocation(StandardLocation type) { -#if !defined(QT_NO_SETTINGS) - QSettings settings(QSettings::UserScope, QLatin1String("Microsoft"), QLatin1String("Windows")); - settings.beginGroup(QLatin1String("CurrentVersion/Explorer/Shell Folders")); + QString result; + +#ifndef Q_OS_WINCE + QLibrary library(QLatin1String("shell32")); +#else + QLibrary library(QLatin1String("coredll")); +#endif // Q_OS_WINCE + typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPWSTR, int, BOOL); + static GetSpecialFolderPath SHGetSpecialFolderPath = + (GetSpecialFolderPath)library.resolve("SHGetSpecialFolderPathW"); + if (!SHGetSpecialFolderPath) + return QString(); + + wchar_t path[MAX_PATH]; + switch (type) { - case CacheLocation: - // Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache - // location for everyone. Most applications seem to be using a - // cache directory located in their AppData directory - return storageLocation(DataLocation) + QLatin1String("\\cache"); case DataLocation: - if (!settings.contains(QLatin1String("Local AppData"))) - break; - return settings.value(QLatin1String("Local AppData")).toString() - + QLatin1String("\\") + QCoreApplication::organizationName() - + QLatin1String("\\") + QCoreApplication::applicationName(); +#if defined Q_WS_WINCE + if (SHGetSpecialFolderPath(0, path, CSIDL_APPDATA, FALSE)) +#else + if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE)) +#endif + result = QString::fromWCharArray(path); + if (!QCoreApplication::organizationName().isEmpty()) + result = result + QLatin1String("\\") + QCoreApplication::organizationName(); + if (!QCoreApplication::applicationName().isEmpty()) + result = result + QLatin1String("\\") + QCoreApplication::applicationName(); break; + case DesktopLocation: - return settings.value(QLatin1String("Desktop")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_DESKTOPDIRECTORY, FALSE)) + result = QString::fromWCharArray(path); break; case DocumentsLocation: - return settings.value(QLatin1String("Personal")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_PERSONAL, FALSE)) + result = QString::fromWCharArray(path); break; case FontsLocation: - return settings.value(QLatin1String("Fonts")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_FONTS, FALSE)) + result = QString::fromWCharArray(path); break; case ApplicationsLocation: - return settings.value(QLatin1String("Programs")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_PROGRAMS, FALSE)) + result = QString::fromWCharArray(path); break; case MusicLocation: - return settings.value(QLatin1String("My Music")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_MYMUSIC, FALSE)) + result = QString::fromWCharArray(path); break; case MoviesLocation: - return settings.value(QLatin1String("My Video")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_MYVIDEO, FALSE)) + result = QString::fromWCharArray(path); break; case PicturesLocation: - return settings.value(QLatin1String("My Pictures")).toString(); + if (SHGetSpecialFolderPath(0, path, CSIDL_MYPICTURES, FALSE)) + result = QString::fromWCharArray(path); break; + case CacheLocation: + // Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache + // location for everyone. Most applications seem to be using a + // cache directory located in their AppData directory + return storageLocation(DataLocation) + QLatin1String("\\cache"); + case QDesktopServices::HomeLocation: return QDir::homePath(); break; @@ -221,8 +253,7 @@ QString QDesktopServices::storageLocation(StandardLocation type) default: break; } -#endif - return QString(); + return result; } QString QDesktopServices::displayName(StandardLocation type) diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index d8702cf..0896256 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -52,11 +52,6 @@ #include "qboxlayout.h" #include "qpainter.h" -#ifdef Q_WS_WIN -#include "qstandardgestures.h" -#include <private/qstandardgestures_p.h> -#endif - #include "qabstractscrollarea_p.h" #include <qwidget.h> @@ -165,7 +160,7 @@ QAbstractScrollAreaPrivate::QAbstractScrollAreaPrivate() viewport(0), cornerWidget(0), left(0), top(0), right(0), bottom(0), xoffset(0), yoffset(0), viewportFilter(0) #ifdef Q_WS_WIN - , panGesture(0), singleFingerPanEnabled(false) + , singleFingerPanEnabled(false) #endif { } @@ -298,14 +293,6 @@ void QAbstractScrollAreaPrivate::init() q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); layoutChildren(); - -#ifdef Q_WS_WIN - panGesture = new QPanGesture(viewport, q); - panGesture->d_func()->implicitGesture = true; - QObject::connect(panGesture, SIGNAL(started()), q, SLOT(_q_gestureTriggered())); - QObject::connect(panGesture, SIGNAL(triggered()), q, SLOT(_q_gestureTriggered())); - QObject::connect(panGesture, SIGNAL(finished()), q, SLOT(_q_gestureTriggered())); -#endif // Q_WS_WIN } #ifdef Q_WS_WIN @@ -556,9 +543,6 @@ void QAbstractScrollArea::setViewport(QWidget *widget) if (isVisible()) d->viewport->show(); QMetaObject::invokeMethod(this, "setupViewport", Q_ARG(QWidget *, widget)); -#ifdef Q_WS_WIN - d->panGesture->setGestureTarget(widget); -#endif delete oldViewport; } } @@ -1351,26 +1335,24 @@ void QAbstractScrollArea::setupViewport(QWidget *viewport) Q_UNUSED(viewport); } -#ifdef Q_WS_WIN -void QAbstractScrollAreaPrivate::_q_gestureTriggered() -{ - Q_Q(QAbstractScrollArea); - QPanGesture *g = qobject_cast<QPanGesture*>(q->sender()); - if (!g) - return; - QScrollBar *hBar = q->horizontalScrollBar(); - QScrollBar *vBar = q->verticalScrollBar(); - QSizeF delta = g->lastOffset(); - if (!delta.isNull()) { - if (QApplication::isRightToLeft()) - delta.rwidth() *= -1; - int newX = hBar->value() - delta.width(); - int newY = vBar->value() - delta.height(); - hbar->setValue(newX); - vbar->setValue(newY); - } -} -#endif +//void QAbstractScrollAreaPrivate::_q_gestureTriggered() +//{ +// Q_Q(QAbstractScrollArea); +// QPanGesture *g = qobject_cast<QPanGesture*>(q->sender()); +// if (!g) +// return; +// QScrollBar *hBar = q->horizontalScrollBar(); +// QScrollBar *vBar = q->verticalScrollBar(); +// QSizeF delta = g->lastOffset(); +// if (!delta.isNull()) { +// if (QApplication::isRightToLeft()) +// delta.rwidth() *= -1; +// int newX = hBar->value() - delta.width(); +// int newY = vBar->value() - delta.height(); +// hbar->setValue(newX); +// vbar->setValue(newY); +// } +//} QT_END_NAMESPACE diff --git a/src/gui/widgets/qabstractscrollarea.h b/src/gui/widgets/qabstractscrollarea.h index 3773477..b3a1861 100644 --- a/src/gui/widgets/qabstractscrollarea.h +++ b/src/gui/widgets/qabstractscrollarea.h @@ -129,10 +129,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_vslide(int)) Q_PRIVATE_SLOT(d_func(), void _q_showOrHideScrollBars()) -#ifdef Q_WS_WIN - Q_PRIVATE_SLOT(d_func(), void _q_gestureTriggered()) -#endif - friend class QStyleSheetStyle; friend class QWidgetPrivate; }; diff --git a/src/gui/widgets/qabstractscrollarea_p.h b/src/gui/widgets/qabstractscrollarea_p.h index 0bb2851..bfb8917 100644 --- a/src/gui/widgets/qabstractscrollarea_p.h +++ b/src/gui/widgets/qabstractscrollarea_p.h @@ -60,7 +60,6 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_SCROLLAREA -class QPanGesture; class QScrollBar; class QAbstractScrollAreaScrollBarContainer; class Q_AUTOTEST_EXPORT QAbstractScrollAreaPrivate: public QFramePrivate @@ -102,8 +101,6 @@ public: QScopedPointer<QObject> viewportFilter; #ifdef Q_WS_WIN - QPanGesture *panGesture; - virtual void _q_gestureTriggered(); bool singleFingerPanEnabled; void setSingleFingerPanEnabled(bool on = true); #endif diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 19a8b63..588a48e 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -715,8 +715,7 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) #else stepsToScroll = int(d->offset_accumulated) * QApplication::wheelScrollLines() * d->singleStep; #endif - if (qAbs(stepsToScroll) > d->pageStep) - stepsToScroll = currentOffset > 0 ? d->pageStep : -d->pageStep; + stepsToScroll = qBound(-d->pageStep, stepsToScroll, d->pageStep); } if (d->invertedControls) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index b606538..0e888d6 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -2174,11 +2174,14 @@ void QComboBox::insertSeparator(int index) /*! Removes the item at the given \a index from the combobox. This will update the current index if the index is removed. + + This function does nothing if \a index is out of range. */ void QComboBox::removeItem(int index) { - Q_ASSERT(index >= 0 && index < count()); Q_D(QComboBox); + if (index < 0 || index >= count()) + return; d->model->removeRows(index, 1, d->root); } diff --git a/src/gui/widgets/qdialogbuttonbox.cpp b/src/gui/widgets/qdialogbuttonbox.cpp index 6cc720d..10f8db8 100644 --- a/src/gui/widgets/qdialogbuttonbox.cpp +++ b/src/gui/widgets/qdialogbuttonbox.cpp @@ -468,18 +468,6 @@ void QDialogButtonBoxPrivate::layoutButtons() if (center) buttonLayout->addStretch(); - -#ifdef QT_SOFTKEYS_ENABLED - QWidget *dialog = 0; - QWidget *p = q; - while (p && !p->isWindow()) { - p = p->parentWidget(); - if (dialog = qobject_cast<QDialog *>(p)) - break; - } - if (dialog) - q->setFixedSize(0, 0); -#endif } QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton, @@ -572,7 +560,7 @@ QAction* QDialogButtonBoxPrivate::createSoftKey(QAbstractButton *button, QDialog Q_Q(QDialogButtonBox); QAction::SoftKeyRole softkeyRole; - QAction *action = new QAction(button->text(), q); + QAction *action = new QAction(button->text(), button); switch (role) { case ApplyRole: @@ -593,7 +581,6 @@ QAction* QDialogButtonBoxPrivate::createSoftKey(QAbstractButton *button, QDialog } QObject::connect(action, SIGNAL(triggered()), button, SIGNAL(clicked())); action->setSoftKeyRole(softkeyRole); - action->setEnabled(button->isEnabled()); return action; } #endif @@ -1196,10 +1183,12 @@ bool QDialogButtonBox::event(QEvent *event) if (!hasDefault && firstAcceptButton) firstAcceptButton->setDefault(true); #ifdef QT_SOFTKEYS_ENABLED - if (dialog) + if (dialog) { + setFixedSize(0,0); dialog->addActions(d->softKeyActions.values()); - else + } else { addActions(d->softKeyActions.values()); + } #endif }else if (event->type() == QEvent::LanguageChange) { d->retranslateStrings(); diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 5930540..7f9ff82 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1290,7 +1290,7 @@ void QLineControl::setCursorBlinkPeriod(int msec) m_blinkStatus = 1; } else { m_blinkTimer = 0; - if (m_blinkStatus == 0) + if (m_blinkStatus == 1) emit updateNeeded(inputMask().isEmpty() ? cursorRect() : QRect()); } m_blinkPeriod = msec; diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index 0947e1b..501e62f 100644 --- a/src/gui/widgets/qmainwindow.cpp +++ b/src/gui/widgets/qmainwindow.cpp @@ -119,7 +119,7 @@ void QMainWindowPrivate::init() q->setAttribute(Qt::WA_Hover); #ifdef QT_SOFTKEYS_ENABLED menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, q); - menuBarAction->setObjectName("_q_menuSoftKeyAction"); + menuBarAction->setObjectName(QLatin1String("_q_menuSoftKeyAction")); #endif } @@ -933,7 +933,7 @@ static bool checkDockWidgetArea(Qt::DockWidgetArea area, const char *where) } #ifndef QT_NO_TABBAR -/*! +/*! \property QMainWindow::documentMode \brief whether the tab bar for tabbed dockwidgets is set to document mode. \since 4.5 @@ -954,7 +954,7 @@ void QMainWindow::setDocumentMode(bool enabled) #endif // QT_NO_TABBAR #ifndef QT_NO_TABWIDGET -/*! +/*! \property QMainWindow::tabShape \brief the tab shape used for tabbed dock widgets. \since 4.5 diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 4fc3d3d..cee38ee 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -1425,7 +1425,7 @@ QMenuPrivate::QMacMenuPrivate::syncAction(QMacMenuAction *action) SetMenuItemProperty(data.submenuHandle, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), &caused); #else NSMenu *subMenu = static_cast<NSMenu *>(action->action->menu()->macMenu()); - if ([subMenu supermenu] != nil) { + if ([subMenu supermenu] && [subMenu supermenu] != [item menu]) { // The menu is already a sub-menu of another one. Cocoa will throw an exception, // in such cases. For the time being, a new QMenu with same set of actions is the // only workaround. @@ -1718,7 +1718,7 @@ QMenuBarPrivate::QMacMenuBarPrivate::syncAction(QMacMenuAction *action) GetMenuItemProperty(action->menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(caused), 0, &caused); SetMenuItemProperty(submenu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), &caused); #else - if ([submenu supermenu] != nil) + if ([submenu supermenu] && [submenu supermenu] != [item menu]) return; else [item setSubmenu:submenu]; diff --git a/src/gui/widgets/qmenu_symbian.cpp b/src/gui/widgets/qmenu_symbian.cpp index c656ef8..d757f98 100644 --- a/src/gui/widgets/qmenu_symbian.cpp +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -74,12 +74,13 @@ struct SymbianMenuItem QAction* action; }; +Q_GLOBAL_STATIC_WITH_ARGS(QAction, contextAction, (0)) + static QList<SymbianMenuItem*> symbianMenus; static QList<QMenuBar*> nativeMenuBars; static uint qt_symbian_menu_static_cmd_id = QT_SYMBIAN_FIRST_MENU_ITEM; static QPointer<QWidget> widgetWithContextMenu; static QList<QAction*> contextMenuActionList; -static QAction contextAction(0); static int contexMenuCommand=0; bool menuExists() @@ -400,8 +401,8 @@ void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() contextMenuActionList.clear(); if (widgetWithContextMenu) { contexMenuCommand = qt_symbian_menu_static_cmd_id; // Increased inside insertNativeMenuItems - contextAction.setText(QMenuBar::tr("Actions")); - contextMenuActionList.append(&contextAction); + contextAction()->setText(QMenuBar::tr("Actions")); + contextMenuActionList.append(contextAction()); insertNativeMenuItems(contextMenuActionList); } } diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index 2ed6cd7..22438bf 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -65,11 +65,6 @@ #include <limits.h> #include <qtexttable.h> #include <qvariant.h> - -#ifdef Q_WS_WIN -#include <qstandardgestures.h> -#endif - #include <qinputcontext.h> #ifndef QT_NO_TEXTEDIT @@ -2937,33 +2932,29 @@ QAbstractTextDocumentLayout::PaintContext QPlainTextEdit::getPaintContext() cons (\a available is true) or unavailable (\a available is false). */ -#ifdef Q_WS_WIN - -void QPlainTextEditPrivate::_q_gestureTriggered() -{ - Q_Q(QPlainTextEdit); - QPanGesture *g = qobject_cast<QPanGesture*>(q->sender()); - if (!g) - return; - QScrollBar *hBar = q->horizontalScrollBar(); - QScrollBar *vBar = q->verticalScrollBar(); - if (g->state() == Qt::GestureStarted) - originalOffsetY = vBar->value(); - QSizeF totalOffset = g->totalOffset(); - if (!totalOffset.isNull()) { - if (QApplication::isRightToLeft()) - totalOffset.rwidth() *= -1; - // QPlainTextEdit scrolls by lines only in vertical direction - QFontMetrics fm(q->document()->defaultFont()); - int lineHeight = fm.height(); - int newX = hBar->value() - g->lastOffset().width(); - int newY = originalOffsetY - totalOffset.height()/lineHeight; - hbar->setValue(newX); - vbar->setValue(newY); - } -} - -#endif +//void QPlainTextEditPrivate::_q_gestureTriggered() +//{ +// Q_Q(QPlainTextEdit); +// QPanGesture *g = qobject_cast<QPanGesture*>(q->sender()); +// if (!g) +// return; +// QScrollBar *hBar = q->horizontalScrollBar(); +// QScrollBar *vBar = q->verticalScrollBar(); +// if (g->state() == Qt::GestureStarted) +// originalOffsetY = vBar->value(); +// QSizeF totalOffset = g->totalOffset(); +// if (!totalOffset.isNull()) { +// if (QApplication::isRightToLeft()) +// totalOffset.rwidth() *= -1; +// // QPlainTextEdit scrolls by lines only in vertical direction +// QFontMetrics fm(q->document()->defaultFont()); +// int lineHeight = fm.height(); +// int newX = hBar->value() - g->lastOffset().width(); +// int newY = originalOffsetY - totalOffset.height()/lineHeight; +// hbar->setValue(newX); +// vbar->setValue(newY); +// } +//} QT_END_NAMESPACE diff --git a/src/gui/widgets/qplaintextedit.h b/src/gui/widgets/qplaintextedit.h index 1d6881b..60aed1d 100644 --- a/src/gui/widgets/qplaintextedit.h +++ b/src/gui/widgets/qplaintextedit.h @@ -270,10 +270,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_verticalScrollbarActionTriggered(int)) Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged()) -#ifdef Q_WS_WIN - Q_PRIVATE_SLOT(d_func(), void _q_gestureTriggered()) -#endif - friend class QPlainTextEditControl; }; diff --git a/src/gui/widgets/qplaintextedit_p.h b/src/gui/widgets/qplaintextedit_p.h index 5fe6f4d..7adf403 100644 --- a/src/gui/widgets/qplaintextedit_p.h +++ b/src/gui/widgets/qplaintextedit_p.h @@ -72,7 +72,6 @@ class QMimeData; class QPlainTextEdit; class ExtraArea; -class QPanGesture; class QPlainTextEditControl : public QTextControl { @@ -179,10 +178,6 @@ public: void _q_modificationChanged(bool); int originalOffsetY; - -#ifdef Q_WS_WIN - void _q_gestureTriggered(); -#endif }; QT_END_NAMESPACE diff --git a/src/gui/widgets/qtoolbarextension_p.h b/src/gui/widgets/qtoolbarextension_p.h index 5d622ec..5fe74a9 100644 --- a/src/gui/widgets/qtoolbarextension_p.h +++ b/src/gui/widgets/qtoolbarextension_p.h @@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_TOOLBUTTON -class QToolBarExtension : public QToolButton +class Q_AUTOTEST_EXPORT QToolBarExtension : public QToolButton { Q_OBJECT Qt::Orientation orientation; |