diff options
author | Frans Englich <frans.englich@nokia.com> | 2009-09-29 10:56:05 (GMT) |
---|---|---|
committer | Frans Englich <frans.englich@nokia.com> | 2009-09-29 10:56:05 (GMT) |
commit | 17c17adbd706d32723ecedeb207c7e467f9fa8eb (patch) | |
tree | 22d6d314dc7320d0b728578a734d636a1d74d9ae /src/gui | |
parent | 1ff83d2b44fe07d1bc6b243fad270dfa7d860dc7 (diff) | |
parent | dcd185e58face87105f484e98ecb195af0790a22 (diff) | |
download | Qt-17c17adbd706d32723ecedeb207c7e467f9fa8eb.zip Qt-17c17adbd706d32723ecedeb207c7e467f9fa8eb.tar.gz Qt-17c17adbd706d32723ecedeb207c7e467f9fa8eb.tar.bz2 |
Merge commit 'qt/4.6' into mmfphonon
Diffstat (limited to 'src/gui')
51 files changed, 821 insertions, 495 deletions
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index 222524e..840b9d6 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -47,21 +47,31 @@ QT_BEGIN_NAMESPACE +// Current GL and VG contexts. These are used to determine if +// we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). +// If a background thread modifies the value, the worst that will +// happen is a redundant eglMakeCurrent() in the foreground thread. +static QEglContext * volatile currentGLContext = 0; +static QEglContext * volatile currentVGContext = 0; + QEglContext::QEglContext() : apiType(QEgl::OpenGL) , dpy(EGL_NO_DISPLAY) , ctx(EGL_NO_CONTEXT) - , surf(EGL_NO_SURFACE) , cfg(0) - , share(false) + , currentSurface(EGL_NO_SURFACE) , current(false) - , reserved(0) { } QEglContext::~QEglContext() { destroy(); + + if (currentGLContext == this) + currentGLContext = 0; + if (currentVGContext == this) + currentVGContext = 0; } bool QEglContext::isValid() const @@ -69,11 +79,6 @@ bool QEglContext::isValid() const return (ctx != EGL_NO_CONTEXT); } -bool QEglContext::isSharing() const -{ - return share; -} - bool QEglContext::isCurrent() const { return current; @@ -148,7 +153,7 @@ bool QEglContext::chooseConfig } // Create the EGLContext. -bool QEglContext::createContext(QEglContext *shareContext) +bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties *properties) { // We need to select the correct API before calling eglCreateContext(). #ifdef EGL_OPENGL_ES_API @@ -162,6 +167,8 @@ bool QEglContext::createContext(QEglContext *shareContext) // Create a new context for the configuration. QEglProperties contextProps; + if (properties) + contextProps = *properties; #if defined(QT_OPENGL_ES_2) if (apiType == QEgl::OpenGL) contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); @@ -182,31 +189,17 @@ bool QEglContext::createContext(QEglContext *shareContext) return false; } } - share = (shareContext != 0); return true; } -// Recreate the surface for a paint device because the native id has changed. -bool QEglContext::recreateSurface(QPaintDevice *device) -{ - // Bail out if the surface has not been created for the first time yet. - if (surf == EGL_NO_SURFACE) - return true; - - // Destroy the old surface. - eglDestroySurface(dpy, surf); - surf = EGL_NO_SURFACE; - - // Create a new one. - return createSurface(device); -} - -// Destroy the EGL surface object. -void QEglContext::destroySurface() +// Destroy an EGL surface object. If it was current on this context +// then call doneCurrent() for it first. +void QEglContext::destroySurface(EGLSurface surface) { - if (surf != EGL_NO_SURFACE) { - eglDestroySurface(dpy, surf); - surf = EGL_NO_SURFACE; + if (surface != EGL_NO_SURFACE) { + if (surface == currentSurface) + doneCurrent(); + eglDestroySurface(dpy, surface); } } @@ -217,21 +210,28 @@ void QEglContext::destroy() eglDestroyContext(dpy, ctx); dpy = EGL_NO_DISPLAY; ctx = EGL_NO_CONTEXT; - surf = EGL_NO_SURFACE; cfg = 0; - share = false; } -bool QEglContext::makeCurrent() +bool QEglContext::makeCurrent(EGLSurface surface) { if (ctx == EGL_NO_CONTEXT) { qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; return false; } + // If lazyDoneCurrent() was called on the surface, then we may be able + // to assume that it is still current within the thread. + if (surface == currentSurface && currentContext(apiType) == this) { + current = true; + return true; + } + current = true; + currentSurface = surface; + setCurrentContext(apiType, this); - bool ok = eglMakeCurrent(dpy, surf, surf, ctx); + bool ok = eglMakeCurrent(dpy, surface, surface, ctx); if (!ok) qWarning() << "QEglContext::makeCurrent():" << errorString(eglGetError()); return ok; @@ -245,6 +245,8 @@ bool QEglContext::doneCurrent() return false; current = false; + currentSurface = EGL_NO_SURFACE; + setCurrentContext(apiType, 0); // We need to select the correct API before calling eglMakeCurrent() // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG @@ -264,12 +266,23 @@ bool QEglContext::doneCurrent() return ok; } -bool QEglContext::swapBuffers() +// Act as though doneCurrent() was called, but keep the context +// and the surface active for the moment. This allows makeCurrent() +// to skip a call to eglMakeCurrent() if we are using the same +// surface as the last set of painting operations. We leave the +// currentContext() pointer as-is for now. +bool QEglContext::lazyDoneCurrent() +{ + current = false; + return true; +} + +bool QEglContext::swapBuffers(EGLSurface surface) { if(ctx == EGL_NO_CONTEXT) return false; - bool ok = eglSwapBuffers(dpy, surf); + bool ok = eglSwapBuffers(dpy, surface); if (!ok) qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError()); return ok; @@ -305,15 +318,6 @@ void QEglContext::waitClient() #endif } -// Query the actual size of the EGL surface. -QSize QEglContext::surfaceSize() const -{ - int w, h; - eglQuerySurface(dpy, surf, EGL_WIDTH, &w); - eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); - return QSize(w, h); -} - // Query the value of a configuration attribute. bool QEglContext::configAttrib(int name, EGLint *value) const { @@ -411,4 +415,20 @@ bool QEglContext::hasExtension(const char* extensionName) return extensions().contains(QLatin1String(extensionName)); } +QEglContext *QEglContext::currentContext(QEgl::API api) +{ + if (api == QEgl::OpenGL) + return currentGLContext; + else + return currentVGContext; +} + +void QEglContext::setCurrentContext(QEgl::API api, QEglContext *context) +{ + if (api == QEgl::OpenGL) + currentGLContext = context; + else + currentVGContext = context; +} + QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index 366bd9e..dc399da 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -80,7 +80,6 @@ public: ~QEglContext(); bool isValid() const; - bool isSharing() const; bool isCurrent() const; QEgl::API api() const { return apiType; } @@ -88,22 +87,20 @@ public: bool openDisplay(QPaintDevice *device); bool chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); - bool createContext(QEglContext *shareContext = 0); - bool createSurface(QPaintDevice *device, const QEglProperties *properties = 0); - bool recreateSurface(QPaintDevice *device); - void destroySurface(); + bool createContext(QEglContext *shareContext = 0, const QEglProperties *properties = 0); + EGLSurface createSurface(QPaintDevice *device, const QEglProperties *properties = 0); + void destroySurface(EGLSurface surface); void destroy(); - bool makeCurrent(); + bool makeCurrent(EGLSurface surface); bool doneCurrent(); - bool swapBuffers(); + bool lazyDoneCurrent(); + bool swapBuffers(EGLSurface surface); void waitNative(); void waitClient(); - QSize surfaceSize() const; - bool configAttrib(int name, EGLint *value) const; static void clearError() { eglGetError(); } @@ -111,10 +108,12 @@ public: static QString errorString(EGLint code); EGLDisplay display() const { return dpy; } + EGLContext context() const { return ctx; } - EGLSurface surface() const { return surf; } - void setSurface(EGLSurface surface) { surf = surface; } + void setContext(EGLContext context) { ctx = context; } + EGLConfig config() const { return cfg; } + void setConfig(EGLConfig config) { cfg = config; } QEglProperties configProperties(EGLConfig cfg = 0) const; @@ -129,13 +128,14 @@ private: QEgl::API apiType; EGLDisplay dpy; EGLContext ctx; - EGLSurface surf; EGLConfig cfg; - bool share; + EGLSurface currentSurface; bool current; - void *reserved; // For extension data in future versions. static EGLDisplay getDisplay(QPaintDevice *device); + + static QEglContext *currentContext(QEgl::API api); + static void setCurrentContext(QEgl::API api, QEglContext *context); }; QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp index 2754589..590b666 100644 --- a/src/gui/egl/qegl_qws.cpp +++ b/src/gui/egl/qegl_qws.cpp @@ -57,11 +57,11 @@ QT_BEGIN_NAMESPACE // We don't have QGLScreen to create EGL surfaces for us, // so surface creation needs to be done in QtOpenGL or // QtOpenVG for Qt/Embedded. -bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) { Q_UNUSED(device); Q_UNUSED(properties); - return false; + return EGL_NO_SURFACE; } EGLDisplay QEglContext::getDisplay(QPaintDevice *device) diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index fa0b5cb..2101f0b 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) { // Create the native drawable for the paint device. int devType = device->devType(); @@ -67,7 +67,7 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop } if (!ok) { qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; + return EGL_NO_SURFACE; } // Create the EGL surface to draw into, based on the native drawable. @@ -76,15 +76,14 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop props = properties->properties(); else props = 0; + EGLSurface surf; if (devType == QInternal::Widget) surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); else surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - if (surf == EGL_NO_SURFACE) { + if (surf == EGL_NO_SURFACE) qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; - } - return true; + return surf; } EGLDisplay QEglContext::getDisplay(QPaintDevice *device) diff --git a/src/gui/egl/qegl_wince.cpp b/src/gui/egl/qegl_wince.cpp index e07d748..bf07f85 100644 --- a/src/gui/egl/qegl_wince.cpp +++ b/src/gui/egl/qegl_wince.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE -bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) { // Create the native drawable for the paint device. int devType = device->devType(); @@ -67,7 +67,7 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop } if (!ok) { qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; + return EGL_NO_SURFACE; } // Create the EGL surface to draw into, based on the native drawable. @@ -76,15 +76,15 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop props = properties->properties(); else props = 0; + EGLSurface surf; if (devType == QInternal::Widget) surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); else surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); if (surf == EGL_NO_SURFACE) { qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; } - return true; + return surf; } EGLDisplay QEglContext::getDisplay(QPaintDevice *device) diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp index 5f34f8e..9d556a8 100644 --- a/src/gui/egl/qegl_x11.cpp +++ b/src/gui/egl/qegl_x11.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE -bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +EGLSurface QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) { // Create the native drawable for the paint device. int devType = device->devType(); @@ -72,7 +72,7 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop } if (!ok) { qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; + return EGL_NO_SURFACE; } // Create the EGL surface to draw into, based on the native drawable. @@ -81,6 +81,7 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop props = properties->properties(); else props = 0; + EGLSurface surf; if (devType == QInternal::Widget) surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); else @@ -88,9 +89,8 @@ bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *prop if (surf == EGL_NO_SURFACE) { qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" << errorString(eglGetError()); - return false; } - return true; + return surf; } EGLDisplay QEglContext::getDisplay(QPaintDevice *device) diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 78b6b53..b3ebb2b 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -171,23 +171,23 @@ QGraphicsAnchorLayout::~QGraphicsAnchorLayout() } /*! - * Creates an anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge - * of item \a secondItem. The magnitude of the anchor is picked up from the style. Anchors - * between a layout edge and an item edge will have a size of 0. - * If there is already an anchor between the edges, the the new anchor will replace the old one. - * - * \a firstItem and \a secondItem are automatically added to the layout if they are not part - * of the layout. This means that count() can increase with up to 2. - * - * The spacing an anchor will get depends on the type of anchor. For instance, anchors from the - * Right edge of one item to the Left edge of another (or vice versa) will use the default - * horizontal spacing. The same behaviour applies to Bottom to Top anchors, (but they will use - * the default vertical spacing). For all other anchor combinations, the spacing will be 0. - * All anchoring functions will follow this rule. - * - * The spacing can also be set manually by using QGraphicsAnchor::setSpacing() method. - * - * \sa addCornerAnchors(), addAnchors() + Creates an anchor between the edge \a firstEdge of item \a firstItem and the edge \a secondEdge + of item \a secondItem. The magnitude of the anchor is picked up from the style. Anchors + between a layout edge and an item edge will have a size of 0. + If there is already an anchor between the edges, the the new anchor will replace the old one. + + \a firstItem and \a secondItem are automatically added to the layout if they are not part + of the layout. This means that count() can increase with up to 2. + + The spacing an anchor will get depends on the type of anchor. For instance, anchors from the + Right edge of one item to the Left edge of another (or vice versa) will use the default + horizontal spacing. The same behaviour applies to Bottom to Top anchors, (but they will use + the default vertical spacing). For all other anchor combinations, the spacing will be 0. + All anchoring functions will follow this rule. + + The spacing can also be set manually by using QGraphicsAnchor::setSpacing() method. + + \sa addCornerAnchors(), addAnchors() */ QGraphicsAnchor * QGraphicsAnchorLayout::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, @@ -200,8 +200,8 @@ QGraphicsAnchorLayout::addAnchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint } /*! - Returns the anchor between the anchor points defined by \a firstItem and \a firstEdge and - \a secondItem and \a secondEdge. If there is no such anchor, the function will return 0. + Returns the anchor between the anchor points defined by \a firstItem and \a firstEdge and + \a secondItem and \a secondEdge. If there is no such anchor, the function will return 0. */ QGraphicsAnchor * QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint firstEdge, @@ -212,30 +212,30 @@ QGraphicsAnchorLayout::anchor(QGraphicsLayoutItem *firstItem, Qt::AnchorPoint fi } /*! - * Creates two anchors between \a firstItem and \a secondItem, where one is for the horizontal - * edge and another one for the vertical edge that the corners \a firstCorner and \a - * secondCorner specifies. - * The magnitude of the anchors is picked up from the style. - * - * This is a convenience function, since anchoring corners can be expressed as anchoring two edges. - * For instance, - * \code - * layout->addAnchor(layout, Qt::AnchorTop, b, Qt::AnchorTop); - * layout->addAnchor(layout, Qt::AnchorLeft, b, Qt::AnchorLeft); - * \endcode - * - * has the same effect as - * - * \code - * layout->addCornerAnchors(layout, Qt::TopLeft, b, Qt::TopLeft); - * \endcode - * - * If there is already an anchor between the edge pairs, it will be replaced by the anchors that - * this function specifies. - * - * \a firstItem and \a secondItem are automatically added to the layout if they are not part - * of the layout. This means that count() can increase with up to 2. - */ + Creates two anchors between \a firstItem and \a secondItem, where one is for the horizontal + edge and another one for the vertical edge that the corners \a firstCorner and \a + secondCorner specifies. + The magnitude of the anchors is picked up from the style. + + This is a convenience function, since anchoring corners can be expressed as anchoring two edges. + For instance, + \code + layout->addAnchor(layout, Qt::AnchorTop, b, Qt::AnchorTop); + layout->addAnchor(layout, Qt::AnchorLeft, b, Qt::AnchorLeft); + \endcode + + has the same effect as + + \code + layout->addCornerAnchors(layout, Qt::TopLeft, b, Qt::TopLeft); + \endcode + + If there is already an anchor between the edge pairs, it will be replaced by the anchors that + this function specifies. + + \a firstItem and \a secondItem are automatically added to the layout if they are not part of the + layout. This means that count() can increase with up to 2. +*/ void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem, Qt::Corner firstCorner, QGraphicsLayoutItem *secondItem, @@ -360,7 +360,7 @@ qreal QGraphicsAnchorLayout::verticalSpacing() const } /*! - \reimp + \reimp */ void QGraphicsAnchorLayout::setGeometry(const QRectF &geom) { diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 7041d58..49aabf5 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -542,7 +542,7 @@ static bool simplifySequentialChunk(Graph<AnchorVertex, AnchorData> *graph, void QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation) { static bool noSimplification = !qgetenv("QT_ANCHORLAYOUT_NO_SIMPLIFICATION").isEmpty(); - if (noSimplification) + if (noSimplification || items.isEmpty()) return; if (graphSimplified[orientation]) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3249bb1..c3934c7 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -1479,6 +1479,7 @@ QList<QGraphicsItem *> QGraphicsItem::children() const */ QList<QGraphicsItem *> QGraphicsItem::childItems() const { + const_cast<QGraphicsItem *>(this)->d_ptr->ensureSortedChildren(); return d_ptr->children; } @@ -4048,6 +4049,82 @@ void QGraphicsItem::setZValue(qreal z) } /*! + \internal + + Ensures that the list of children is sorted by insertion order, and that + the siblingIndexes are packed (no gaps), and start at 0. + + ### This function is almost identical to + QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes(). +*/ +void QGraphicsItemPrivate::ensureSequentialSiblingIndex() +{ + if (!sequentialOrdering) { + qSort(children.begin(), children.end(), insertionOrder); + sequentialOrdering = 1; + needSortChildren = 1; + } + if (holesInSiblingIndex) { + holesInSiblingIndex = 0; + for (int i = 0; i < children.size(); ++i) + children[i]->d_ptr->siblingIndex = i; + } +} + +/*! + \since 4.6 + + Stacks this item before \a sibling, which must be a sibling item (i.e., the + two items must share the same parent item, or must both be toplevel items). + The \a sibling must have the same Z value as this item, otherwise calling + this function will have no effect. + + By default, all items are stacked by insertion order (i.e., the first item + you add is drawn before the next item you add). If two items' Z values are + different, then the item with the highest Z value is drawn on top. When the + Z values are the same, the insertion order will decide the stacking order. + + \sa setZValue(), ItemStacksBehindParent +*/ +void QGraphicsItem::stackBefore(const QGraphicsItem *sibling) +{ + if (sibling == this) + return; + if (!sibling || d_ptr->parent != sibling->parentItem()) { + qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling); + return; + } + QList<QGraphicsItem *> *siblings = d_ptr->parent + ? &d_ptr->parent->d_ptr->children + : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0); + if (!siblings) { + qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling); + return; + } + + // First, make sure that the sibling indexes have no holes. This also + // marks the children list for sorting. + if (d_ptr->parent) + d_ptr->parent->d_ptr->ensureSequentialSiblingIndex(); + else + d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes(); + + // Only move items with the same Z value, and that need moving. + int siblingIndex = sibling->d_ptr->siblingIndex; + int myIndex = d_ptr->siblingIndex; + if (myIndex >= siblingIndex && d_ptr->z == sibling->d_ptr->z) { + siblings->move(myIndex, siblingIndex); + // Fixup the insertion ordering. + for (int i = 0; i < siblings->size(); ++i) { + int &index = siblings->at(i)->d_ptr->siblingIndex; + if (i != siblingIndex && index >= siblingIndex && index <= myIndex) + ++index; + } + d_ptr->siblingIndex = siblingIndex; + } +} + +/*! Returns the bounding rect of this item's descendants (i.e., its children, their children, etc.) in local coordinates. The rectangle will contain all descendants after they have been mapped @@ -4753,20 +4830,36 @@ void QGraphicsItemPrivate::resolveDepth() /*! \internal + + ### This function is almost identical to + QGraphicsScenePrivate::registerTopLevelItem(). */ void QGraphicsItemPrivate::addChild(QGraphicsItem *child) { - needSortChildren = 1; + // Remove all holes from the sibling index list. Now the max index + // number is equal to the size of the children list. + ensureSequentialSiblingIndex(); + needSortChildren = 1; // ### maybe 0 child->d_ptr->siblingIndex = children.size(); children.append(child); } /*! \internal + + ### This function is almost identical to + QGraphicsScenePrivate::unregisterTopLevelItem(). */ void QGraphicsItemPrivate::removeChild(QGraphicsItem *child) { - children.removeOne(child); + // When removing elements in the middle of the children list, + // there will be a "gap" in the list of sibling indexes (0,1,3,4). + if (!holesInSiblingIndex) + holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1; + if (sequentialOrdering && !holesInSiblingIndex) + children.removeAt(child->d_ptr->siblingIndex); + else + children.removeOne(child); // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because // the child is not guaranteed to be at the index after the list is sorted. // (see ensureSortedChildren()). diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 089d6fe..99d2e12 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -302,6 +302,7 @@ public: // Stacking order qreal zValue() const; void setZValue(qreal z); + void stackBefore(const QGraphicsItem *sibling); // Hit test virtual QRectF boundingRect() const = 0; diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index fd2ff34..3feccdc 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -153,7 +153,7 @@ public: dirtyClipPath(1), emptyClipPath(0), inSetPosHelper(0), - needSortChildren(1), + needSortChildren(1), // ### can be 0 by default? allChildrenDirty(0), fullUpdatePending(0), flags(0), @@ -174,6 +174,8 @@ public: mouseSetsFocus(1), explicitActivate(0), wantsActive(0), + holesInSiblingIndex(0), + sequentialOrdering(1), globalStackingOrder(-1), q_ptr(0) { @@ -421,6 +423,8 @@ public: inline QTransform transformToParent() const; inline void ensureSortedChildren(); + static inline bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b); + void ensureSequentialSiblingIndex(); QPainterPath cachedClipPath; QRectF childrenBoundingRect; @@ -493,6 +497,8 @@ public: // New 32 bits quint32 explicitActivate : 1; quint32 wantsActive : 1; + quint32 holesInSiblingIndex : 1; + quint32 sequentialOrdering : 1; // Optional stacking order int globalStackingOrder; @@ -646,14 +652,32 @@ inline QTransform QGraphicsItemPrivate::transformToParent() const return matrix; } +/*! + \internal +*/ inline void QGraphicsItemPrivate::ensureSortedChildren() { if (needSortChildren) { qSort(children.begin(), children.end(), qt_notclosestLeaf); needSortChildren = 0; + sequentialOrdering = 1; + for (int i = 0; i < children.size(); ++i) { + if (children[i]->d_ptr->siblingIndex != i) { + sequentialOrdering = 0; + break; + } + } } } +/*! + \internal +*/ +inline bool QGraphicsItemPrivate::insertionOrder(QGraphicsItem *a, QGraphicsItem *b) +{ + return a->d_ptr->siblingIndex < b->d_ptr->siblingIndex; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index f9800bc..2e9a30c 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -420,6 +420,8 @@ void QGraphicsLayout::widgetEvent(QEvent *e) */ /*! + \since 4.6 + This function is a convenience function provided for custom layouts, and will go through all items in the layout and reparent their graphics items to the closest QGraphicsWidget ancestor of the layout. diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 0655ecc..4b74b67 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -283,6 +283,8 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() processDirtyItemsEmitted(false), selectionChanging(0), needSortTopLevelItems(true), + holesInTopLevelSiblingIndex(false), + topLevelSequentialOrdering(true), stickyFocus(false), hasFocus(false), focusItem(0), @@ -379,24 +381,36 @@ void QGraphicsScenePrivate::_q_emitUpdated() /*! \internal + + ### This function is almost identical to QGraphicsItemPrivate::addChild(). */ void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item) { - needSortTopLevelItems = true; + item->d_ptr->ensureSequentialSiblingIndex(); + needSortTopLevelItems = true; // ### maybe false item->d_ptr->siblingIndex = topLevelItems.size(); topLevelItems.append(item); } /*! \internal + + ### This function is almost identical to QGraphicsItemPrivate::removeChild(). */ void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item) { - topLevelItems.removeOne(item); + if (!holesInTopLevelSiblingIndex) + holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1; + if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex) + topLevelItems.removeAt(item->d_ptr->siblingIndex); + else + topLevelItems.removeOne(item); // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because // the item is not guaranteed to be at the index after the list is sorted // (see ensureSortedTopLevelItems()). item->d_ptr->siblingIndex = -1; + if (topLevelSequentialOrdering) + topLevelSequentialOrdering = !holesInTopLevelSiblingIndex; } /*! @@ -1239,6 +1253,29 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou /*! \internal + Ensures that the list of toplevels is sorted by insertion order, and that + the siblingIndexes are packed (no gaps), and start at 0. + + ### This function is almost identical to + QGraphicsItemPrivate::ensureSequentialSiblingIndex(). +*/ +void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes() +{ + if (!topLevelSequentialOrdering) { + qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder); + topLevelSequentialOrdering = true; + needSortTopLevelItems = 1; + } + if (holesInTopLevelSiblingIndex) { + holesInTopLevelSiblingIndex = 0; + for (int i = 0; i < topLevelItems.size(); ++i) + topLevelItems[i]->d_ptr->siblingIndex = i; + } +} + +/*! + \internal + Set the font and propagate the changes if the font is different from the current font. */ diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 3b03624..46917ce 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -111,6 +111,9 @@ public: QList<QGraphicsItem *> unpolishedItems; QList<QGraphicsItem *> topLevelItems; bool needSortTopLevelItems; + bool holesInTopLevelSiblingIndex; + bool topLevelSequentialOrdering; + QMap<QGraphicsItem *, QPointF> movingItemsInitialPositions; void registerTopLevelItem(QGraphicsItem *item); void unregisterTopLevelItem(QGraphicsItem *item); @@ -255,6 +258,8 @@ public: } } + void ensureSequentialTopLevelSiblingIndexes(); + QStyle *style; QFont font; void setFont_helper(const QFont &font); diff --git a/src/gui/graphicsview/qgraphicssceneindex.cpp b/src/gui/graphicsview/qgraphicssceneindex.cpp index 3ea957f..f0404fd 100644 --- a/src/gui/graphicsview/qgraphicssceneindex.cpp +++ b/src/gui/graphicsview/qgraphicssceneindex.cpp @@ -265,12 +265,13 @@ bool QGraphicsSceneIndexPrivate::itemCollidesWithPath(const QGraphicsItem *item, /*! \internal + This function returns the items in ascending order. */ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRectF exposeRect, QGraphicsSceneIndexIntersector *intersector, QList<QGraphicsItem *> *items, const QTransform &viewTransform, - Qt::ItemSelectionMode mode, Qt::SortOrder order, + Qt::ItemSelectionMode mode, qreal parentOpacity) const { Q_ASSERT(item); @@ -326,7 +327,7 @@ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRe if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) continue; recursive_items_helper(child, exposeRect, intersector, items, viewTransform, - mode, order, opacity); + mode, opacity); } } @@ -343,7 +344,7 @@ void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRe if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) continue; recursive_items_helper(child, exposeRect, intersector, items, viewTransform, - mode, order, opacity); + mode, opacity); } } } diff --git a/src/gui/graphicsview/qgraphicssceneindex_p.h b/src/gui/graphicsview/qgraphicssceneindex_p.h index 768c724..adebfde 100644 --- a/src/gui/graphicsview/qgraphicssceneindex_p.h +++ b/src/gui/graphicsview/qgraphicssceneindex_p.h @@ -138,7 +138,7 @@ public: void recursive_items_helper(QGraphicsItem *item, QRectF exposeRect, QGraphicsSceneIndexIntersector *intersector, QList<QGraphicsItem *> *items, const QTransform &viewTransform, - Qt::ItemSelectionMode mode, Qt::SortOrder order, qreal parentOpacity = 1.0) const; + Qt::ItemSelectionMode mode, qreal parentOpacity = 1.0) const; inline void items_helper(const QRectF &rect, QGraphicsSceneIndexIntersector *intersector, QList<QGraphicsItem *> *items, const QTransform &viewTransform, Qt::ItemSelectionMode mode, Qt::SortOrder order) const; @@ -156,7 +156,7 @@ inline void QGraphicsSceneIndexPrivate::items_helper(const QRectF &rect, QGraphi Q_Q(const QGraphicsSceneIndex); const QList<QGraphicsItem *> tli = q->estimateTopLevelItems(rect, Qt::AscendingOrder); for (int i = 0; i < tli.size(); ++i) - recursive_items_helper(tli.at(i), rect, intersector, items, viewTransform, mode, order); + recursive_items_helper(tli.at(i), rect, intersector, items, viewTransform, mode); if (order == Qt::DescendingOrder) { const int n = items->size(); for (int i = 0; i < n / 2; ++i) diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index e3a991e..1ece8b1 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -48,6 +48,33 @@ QT_BEGIN_NAMESPACE +/*! + \internal + \class QSimplex + + The QSimplex class is a Linear Programming problem solver based on the two-phase + simplex method. + + It takes a set of QSimplexConstraints as its restrictive constraints and an + additional QSimplexConstraint as its objective function. Then methods to maximize + and minimize the problem solution are provided. + + The two-phase simplex method is based on the following steps: + First phase: + 1.a) Modify the original, complex, and possibly not feasible problem, into a new, + easy to solve problem. + 1.b) Set as the objective of the new problem, a feasible solution for the original + complex problem. + 1.c) Run simplex to optimize the modified problem and check whether a solution for + the original problem exists. + + Second phase: + 2.a) Go back to the original problem with the feasibl (but not optimal) solution + found in the first phase. + 2.b) Set the original objective. + 3.c) Run simplex to optimize the original problem towards its optimal solution. +*/ + QSimplex::QSimplex() : objective(0), rows(0), columns(0), firstArtificial(0), matrix(0) { } @@ -84,15 +111,32 @@ void QSimplex::clearDataStructures() objective = 0; } +/*! + \internal + Sets the new constraints in the simplex solver and returns whether the problem + is feasible. + + This method sets the new constraints, normalizes them, creates the simplex matrix + and runs the first simplex phase. +*/ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) { + //////////////////////////// + // Reset to initial state // + //////////////////////////// clearDataStructures(); if (newConstraints.isEmpty()) return true; // we are ok with no constraints constraints = newConstraints; - // Set Variables direct mapping + /////////////////////////////////////// + // Prepare variables and constraints // + /////////////////////////////////////// + + // Set Variables direct mapping. + // "variables" is a list that provides a stable, indexed list of all variables + // used in this problem. QSet<QSimplexVariable *> variablesSet; for (int i = 0; i < constraints.size(); ++i) variablesSet += \ @@ -100,12 +144,25 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) variables = variablesSet.toList(); // Set Variables reverse mapping + // We also need to be able to find the index for a given variable, to do that + // we store in each variable its index. for (int i = 0; i < variables.size(); ++i) { // The variable "0" goes at the column "1", etc... variables[i]->index = i + 1; } // Normalize Constraints + // In this step, we prepare the constraints in two ways: + // Firstly, we modify all constraints of type "LessOrEqual" or "MoreOrEqual" + // by the adding slack or surplus variables and making them "Equal" constraints. + // Secondly, we need every single constraint to have a direct, easy feasible + // solution. Constraints that have slack variables are already easy to solve, + // to all the others we add artificial variables. + // + // At the end we modify the constraints as follows: + // - LessOrEqual: SLACK variable is added. + // - Equal: ARTIFICIAL variable is added. + // - More or Equal: ARTIFICIAL and SURPLUS variables are added. int variableIndex = variables.size(); QList <QSimplexVariable *> artificialList; @@ -138,12 +195,18 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) } } + // All original, slack and surplus have already had its index set + // at this point. We now set the index of the artificial variables + // as to ensure they are at the end of the variable list and therefore + // can be easily removed at the end of this method. firstArtificial = variableIndex + 1; for (int i = 0; i < artificialList.size(); ++i) artificialList[i]->index = ++variableIndex; artificialList.clear(); - // Matrix + ///////////////////////////// + // Fill the Simplex matrix // + ///////////////////////////// // One for each variable plus the Basic and BFS columns (first and last) columns = variableIndex + 2; @@ -188,24 +251,61 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) setValueAt(i, columns - 1, c->constant); } - // Set temporary objective: -1 * sum_of_artificial_vars + // Set objective for the first-phase Simplex. + // Z = -1 * sum_of_artificial_vars for (int j = firstArtificial; j < columns - 1; ++j) setValueAt(0, j, 1.0); // Maximize our objective (artificial vars go to zero) solveMaxHelper(); + // If there is a solution where the sum of all artificial + // variables is zero, then all of them can be removed and yet + // we will have a feasible (but not optimal) solution for the + // original problem. + // Otherwise, we clean up our structures and report there is + // no feasible solution. if (valueAt(0, columns - 1) != 0.0) { qWarning() << "QSimplex: No feasible solution!"; clearDataStructures(); return false; } - // Remove artificial variables + // Remove artificial variables. We already have a feasible + // solution for the first problem, thus we don't need them + // 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; } +/*! + \internal + + Run simplex on the current matrix with the current objective. + + This is the iterative method. The matrix lines are combined + as to modify the variable values towards the best solution possible. + The method returns when the matrix is in the optimal state. +*/ void QSimplex::solveMaxHelper() { reducedRowEchelon(); @@ -235,23 +335,21 @@ void QSimplex::clearColumns(int first, int last) void QSimplex::dumpMatrix() { - printf("---- Simplex Matrix ----\n"); + qDebug("---- Simplex Matrix ----\n"); - printf(" "); + QString str(QLatin1String(" ")); for (int j = 0; j < columns; ++j) - printf(" <% 2d >", j); - printf("\n"); - + str += QString::fromAscii(" <%1 >").arg(j, 2); + qDebug("%s", qPrintable(str)); for (int i = 0; i < rows; ++i) { - printf("Row %2d:", i); + str = QString::fromAscii("Row %1:").arg(i, 2); qreal *row = matrix + i * columns; - for (int j = 0; j < columns; ++j) { - printf(" % 2.2f", row[j]); - } - printf("\n"); + for (int j = 0; j < columns; ++j) + str += QString::fromAscii("%1").arg(row[j], 7, 'f', 2); + qDebug("%s", qPrintable(str)); } - printf("------------------------\n\n"); + qDebug("------------------------\n"); } void QSimplex::combineRows(int toIndex, int fromIndex, qreal factor) @@ -292,6 +390,23 @@ int QSimplex::findPivotColumn() return minIndex; } +/*! + \internal + + For a given pivot column, find the pivot row. That is, the row with the + minimum associated "quotient" where: + + - quotient is the division of the value in the last column by the value + in the pivot column. + - rows with value less or equal to zero are ignored + - if two rows have the same quotient, lines are chosen based on the + highest variable index (value in the first column) + + The last condition avoids a bug where artificial variables would be + left behind for the second-phase simplex, and with 'good' + constraints would be removed before it, what would lead to incorrect + results. +*/ int QSimplex::pivotRowForColumn(int column) { qreal min = qreal(999999999999.0); // ### @@ -306,6 +421,8 @@ int QSimplex::pivotRowForColumn(int column) if (quotient < min) { min = quotient; minIndex = i; + } else if ((quotient == min) && (valueAt(i, 0) > valueAt(minIndex, 0))) { + minIndex = i; } } @@ -320,6 +437,12 @@ void QSimplex::reducedRowEchelon() } } +/*! + \internal + + Does one iteration towards a better solution for the problem. + See 'solveMaxHelper'. +*/ bool QSimplex::iterate() { // Find Pivot column @@ -351,7 +474,7 @@ bool QSimplex::iterate() setValueAt(pivotRow, 0, pivotColumn); // dumpMatrix(); - // printf("------------ end of iteration --------------\n"); + // qDebug("------------ end of iteration --------------\n"); return true; } @@ -361,7 +484,13 @@ bool QSimplex::iterate() Both solveMin and solveMax are interfaces to this method. The enum solverFactor admits 2 values: Minimum (-1) and Maximum (+1). - */ + + This method sets the original objective and runs the second phase + Simplex to obtain the optimal solution for the problem. As the internal + simplex solver is only able to _maximize_ objectives, we handle the + minimization case by inverting the original objective and then + maximizing it. +*/ qreal QSimplex::solver(solverFactor factor) { // Remove old objective @@ -381,16 +510,30 @@ qreal QSimplex::solver(solverFactor factor) return factor * valueAt(0, columns - 1); } +/*! + \internal + Minimize the original objective. +*/ qreal QSimplex::solveMin() { return solver(Minimum); } +/*! + \internal + Maximize the original objective. +*/ qreal QSimplex::solveMax() { return solver(Maximum); } +/*! + \internal + + Reads results from the simplified matrix and saves them in the + "result" member of each QSimplexVariable. +*/ void QSimplex::collectResults() { // All variables are zero unless overridden below. diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 89d7de5..1ac56a7 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -314,7 +314,7 @@ private: QImageData *d; friend class QRasterPixmapData; - friend class QDetachedPixmap; + friend class QPixmapCacheEntry; friend Q_GUI_EXPORT qint64 qt_image_id(const QImage &image); friend const QVector<QRgb> *qt_image_colortable(const QImage &image); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index aff186b..074f3eb 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -696,14 +696,17 @@ bool QImageReader::autoDetectImageFormat() const /*! - Specifies that the image reader should decide which plugin to use - solely based on the contents in the datastream. + If \a ignored is set to true, then the image reader will ignore + specified formats or file extensions and decide which plugin to + use only based on the contents in the datastream. Setting this flag means that all image plugins gets loaded. Each plugin will read the first bytes in the image data and decide if - the plugin is compatible or not. The flag is set to \a ignored. + the plugin is compatible or not. - This also disables auto detecting image format. + This also disables auto detecting the image format. + + \sa decideFormatFromContent() */ void QImageReader::setDecideFormatFromContent(bool ignored) @@ -713,8 +716,11 @@ void QImageReader::setDecideFormatFromContent(bool ignored) /*! - Returns wether the image reader should decide which plugin to use - sloley based on the contents of the datastream + Returns whether the image reader should decide which plugin to use + only based on the contents of the datastream rather than on the file + extension. + + \sa setDecideFormatFromContent() */ bool QImageReader::decideFormatFromContent() const diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp index 48aee1c..42b8dea 100644 --- a/src/gui/image/qmovie.cpp +++ b/src/gui/image/qmovie.cpp @@ -47,6 +47,10 @@ \ingroup painting + This class is used to show simple animations without sound. If you want + to display video and media content, use the \l{Phonon Module}{Phonon} + multimedia framework instead. + First, create a QMovie object by passing either the name of a file or a pointer to a QIODevice containing an animated image format to QMovie's constructor. You can call isValid() to check if the image data is valid, diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index a891637..d11bd03 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -270,7 +270,7 @@ private: friend class QWidgetPrivate; friend class QRasterPaintEngine; friend class QRasterBuffer; - friend class QDetachedPixmap; + friend class QPixmapCacheEntry; #if !defined(QT_NO_DATASTREAM) friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPixmap &); #endif diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index 2af2399..da0405e 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -88,7 +88,7 @@ protected: private: friend class QPixmap; friend class QBitmap; - friend class QDetachedPixmap; + friend class QPixmapCacheEntry; friend class QRasterPaintEngine; }; diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index cab6116..dccc691 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -64,13 +64,14 @@ const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; - /*! + \class QSymbianFbsClient \since 4.6 + \internal - Symbian Font And Bitmap server client that is - used to lock the global bitmap heap. Only used in - S60 v3.1 and S60 v3.2. + Symbian Font And Bitmap server client that is + used to lock the global bitmap heap. Only used in + S60 v3.1 and S60 v3.2. */ class QSymbianFbsClient { @@ -145,7 +146,9 @@ void QSymbianFbsHeapLock::relock() } /*! + \class QSymbianBitmapDataAccess \since 4.6 + \internal Data access class that is used to locks/unlocks pixel data when drawing or modifying CFbsBitmap pixel data. @@ -297,7 +300,7 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h) } /*! - \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() + \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const \since 4.6 Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this @@ -724,7 +727,7 @@ void QS60PixmapData::endDataAccess(bool readOnly) const /*! \since 4.6 - Returns a QPixmap that wraps given \c RSgImage \a graphics resource. + Returns a QPixmap that wraps given \a sgImage graphics resource. The data should be valid even when original RSgImage handle has been closed. diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 8029977..f12d397 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -167,7 +167,7 @@ QPixmapCache::Key &QPixmapCache::Key::operator =(const Key &other) return *this; } -class QPMCache : public QObject, public QCache<QPixmapCache::Key, QDetachedPixmap> +class QPMCache : public QObject, public QCache<QPixmapCache::Key, QPixmapCacheEntry> { Q_OBJECT public: @@ -215,7 +215,7 @@ uint qHash(const QPixmapCache::Key &k) QPMCache::QPMCache() : QObject(0), - QCache<QPixmapCache::Key, QDetachedPixmap>(cache_limit * 1024), + QCache<QPixmapCache::Key, QPixmapCacheEntry>(cache_limit * 1024), keyArray(0), theid(0), ps(0), keyArraySize(0), freeKey(0), t(false) { } @@ -238,7 +238,6 @@ void QPMCache::timerEvent(QTimerEvent *) { int mc = maxCost(); bool nt = totalCost() == ps; - QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); setMaxCost(nt ? totalCost() * 3 / 4 : totalCost() -1); setMaxCost(mc); ps = totalCost(); @@ -252,10 +251,6 @@ void QPMCache::timerEvent(QTimerEvent *) ++it; } } - for (int i = 0; i < keys.size(); ++i) { - if (!contains(keys.at(i))) - releaseKey(keys.at(i)); - } if (!size()) { killTimer(theid); @@ -274,11 +269,10 @@ QPixmap *QPMCache::object(const QString &key) const const_cast<QPMCache *>(this)->cacheKeys.remove(key); return 0; } - QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(cacheKey); + QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(cacheKey); //We didn't find the pixmap in the cache, the key is not valid anymore if (!ptr) { const_cast<QPMCache *>(this)->cacheKeys.remove(key); - const_cast<QPMCache *>(this)->releaseKey(cacheKey); } return ptr; } @@ -286,7 +280,7 @@ QPixmap *QPMCache::object(const QString &key) const QPixmap *QPMCache::object(const QPixmapCache::Key &key) const { Q_ASSERT(key.d->isValid); - QPixmap *ptr = QCache<QPixmapCache::Key, QDetachedPixmap>::object(key); + QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(key); //We didn't find the pixmap in the cache, the key is not valid anymore if (!ptr) const_cast<QPMCache *>(this)->releaseKey(key); @@ -299,13 +293,14 @@ bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost) QPixmapCache::Key oldCacheKey = cacheKeys.value(key); //If for the same key we add already a pixmap we should delete it if (oldCacheKey.d) { - QCache<QPixmapCache::Key, QDetachedPixmap>::remove(oldCacheKey); - cacheKey = oldCacheKey; - } else { - cacheKey = createKey(); - } + QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(oldCacheKey); + cacheKeys.remove(key); + } + + //we create a new key the old one has been removed + cacheKey = createKey(); - bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); + bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); if (success) { cacheKeys.insert(key, cacheKey); if (!theid) { @@ -322,7 +317,7 @@ bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost) QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost) { QPixmapCache::Key cacheKey = createKey(); - bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(cacheKey, new QDetachedPixmap(pixmap), cost); + bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); if (success) { if (!theid) { theid = startTimer(30000); @@ -338,13 +333,21 @@ QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost) bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost) { Q_ASSERT(key.d->isValid); - //If for the same key we add already a pixmap we should delete it - QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); + //If for the same key we had already an entry so we should delete the pixmap and use the new one + QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key); + + QPixmapCache::Key cacheKey = createKey(); - bool success = QCache<QPixmapCache::Key, QDetachedPixmap>::insert(key, new QDetachedPixmap(pixmap), cost); - if (success && !theid) { - theid = startTimer(30000); - t = false; + bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost); + if (success) { + if(!theid) { + theid = startTimer(30000); + t = false; + } + const_cast<QPixmapCache::Key&>(key) = cacheKey; + } else { + //Insertion failed we released the key + releaseKey(cacheKey); } return success; } @@ -356,16 +359,12 @@ bool QPMCache::remove(const QString &key) if (!cacheKey.d) return false; cacheKeys.remove(key); - releaseKey(cacheKey); - return QCache<QPixmapCache::Key, QDetachedPixmap>::remove(cacheKey); + return QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey); } bool QPMCache::remove(const QPixmapCache::Key &key) { - bool result = QCache<QPixmapCache::Key, QDetachedPixmap>::remove(key); - //We release the key after we removed it from the cache - releaseKey(key); - return result; + return QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key); } void QPMCache::resizeKeyArray(int size) @@ -409,10 +408,10 @@ void QPMCache::clear() freeKey = 0; keyArraySize = 0; //Mark all keys as invalid - QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QDetachedPixmap>::keys(); + QList<QPixmapCache::Key> keys = QCache<QPixmapCache::Key, QPixmapCacheEntry>::keys(); for (int i = 0; i < keys.size(); ++i) keys.at(i).d->isValid = false; - QCache<QPixmapCache::Key, QDetachedPixmap>::clear(); + QCache<QPixmapCache::Key, QPixmapCacheEntry>::clear(); } QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) @@ -424,6 +423,11 @@ QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) Q_GLOBAL_STATIC(QPMCache, pm_cache) +QPixmapCacheEntry::~QPixmapCacheEntry() +{ + pm_cache()->releaseKey(key); +} + /*! \obsolete \overload diff --git a/src/gui/image/qpixmapcache_p.h b/src/gui/image/qpixmapcache_p.h index 33f93bc..84e4a03 100644 --- a/src/gui/image/qpixmapcache_p.h +++ b/src/gui/image/qpixmapcache_p.h @@ -76,10 +76,10 @@ public: }; // XXX: hw: is this a general concept we need to abstract? -class QDetachedPixmap : public QPixmap +class QPixmapCacheEntry : public QPixmap { public: - QDetachedPixmap(const QPixmap &pix) : QPixmap(pix) + QPixmapCacheEntry(const QPixmapCache::Key &key, const QPixmap &pix) : QPixmap(pix), key(key) { if (data && data->classId() == QPixmapData::RasterClass) { QRasterPixmapData *d = static_cast<QRasterPixmapData*>(data.data()); @@ -91,6 +91,8 @@ public: } } } + ~QPixmapCacheEntry(); + QPixmapCache::Key key; }; QT_END_NAMESPACE diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp index 620880a..8ee417f 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -295,7 +295,7 @@ void QInputContext::sendEvent(const QInputMethodEvent &event) The \a event parameter is the event that was sent to the editor widget. The event type is QEvent::MouseButtonPress, QEvent::MouseButtonRelease, QEvent::MouseButtonDblClick or - QEvent::MouseButtonMove. The event's button and state indicate + QEvent::MouseMove. The event's button and state indicate the kind of operation that was performed. */ void QInputContext::mouseHandler(int /*x*/, QMouseEvent *event) @@ -469,6 +469,8 @@ bool QInputContext::x11FilterEvent(QWidget * /*keywidget*/, XEvent * /*event*/) #ifdef Q_WS_S60 /*! + \since 4.6 + This function may be overridden only if input method is depending on Symbian and you need raw TWsEvent. Otherwise, this function must not. diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 774ec23..df5097b 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -68,6 +68,9 @@ #include "private/qstylesheetstyle_p.h" #include "private/qstyle_p.h" #include "qmessagebox.h" +#include "qlineedit.h" +#include "qlistview.h" +#include "qtextedit.h" #include <QtGui/qgraphicsproxywidget.h> #include "qinputcontext.h" @@ -94,6 +97,10 @@ #include "qapplication.h" +#ifndef QT_NO_LIBRARY +#include "qlibrary.h" +#endif + #ifdef Q_WS_WINCE #include "qdatetime.h" #include "qguifunctions_wince.h" @@ -454,6 +461,7 @@ bool QApplicationPrivate::animate_tooltip = false; bool QApplicationPrivate::fade_tooltip = false; bool QApplicationPrivate::animate_toolbox = false; bool QApplicationPrivate::widgetCount = false; +bool QApplicationPrivate::load_testability = false; #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) bool QApplicationPrivate::inSizeMove = false; #endif @@ -560,6 +568,8 @@ void QApplicationPrivate::process_cmdline() QApplication::setLayoutDirection(Qt::RightToLeft); } else if (qstrcmp(arg, "-widgetcount") == 0) { widgetCount = true; + } else if (qstrcmp(arg, "-testability") == 0) { + load_testability = true; } else if (arg == "-graphicssystem" && i < argc-1) { graphics_system_name = QString::fromLocal8Bit(argv[++i]); } else { @@ -762,6 +772,23 @@ void QApplicationPrivate::construct( extern void qt_gui_eval_init(uint); qt_gui_eval_init(application_type); #endif + +#ifndef QT_NO_LIBRARY + if(load_testability) { + QLibrary testLib(QLatin1String("qttestability")); + if (testLib.load()) { + typedef void (*TasInitialize)(void); + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); + if (initFunction) { + initFunction(); + } else { + qCritical("Library qttestability resolve failed!"); + } + } else { + qCritical("Library qttestability load failed!"); + } + } +#endif } #if defined(Q_WS_X11) @@ -2487,8 +2514,6 @@ void QApplication::setActiveWindow(QWidget* act) */ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next) { - uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus; - QWidget *f = toplevel->focusWidget(); if (!f) f = toplevel; @@ -2496,11 +2521,22 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool QWidget *w = f; QWidget *test = f->d_func()->focus_next; while (test && test != f) { - if ((test->focusPolicy() & focus_flag) == focus_flag + if ((test->focusPolicy() & Qt::TabFocus) && !(test->d_func()->extra && test->d_func()->extra->focus_proxy) && test->isVisibleTo(toplevel) && test->isEnabled() && !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test)) - && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))) { + && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test)) + && (qt_tab_all_widgets +#ifndef QT_NO_LINEEDIT + || qobject_cast<QLineEdit*>(test) +#endif +#ifndef QT_NO_TEXTEDIT + || qobject_cast<QTextEdit*>(test) +#endif +#ifndef QT_NO_ITEMVIEWS + || qobject_cast<QListView*>(test) +#endif + )) { w = test; if (next) break; diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 7e8d96f..c294e62 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -960,7 +960,18 @@ struct QMacAppleEventTypeSpec { { kCoreEventClass, kAEQuitApplication }, { kCoreEventClass, kAEOpenDocuments } }; + #ifndef QT_MAC_USE_COCOA + +#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5) +enum +{ + kEventMouseScroll = 11, + kEventParamMouseWheelSmoothVerticalDelta = 'saxy', + kEventParamMouseWheelSmoothHorizontalDelta = 'saxx', +}; +#endif + /* watched events */ static EventTypeSpec app_events[] = { { kEventClassQt, kEventQtRequestWindowChange }, @@ -972,6 +983,7 @@ static EventTypeSpec app_events[] = { { kEventClassWindow, kEventWindowActivated }, { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassMouse, kEventMouseScroll }, { kEventClassMouse, kEventMouseWheelMoved }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, @@ -1639,6 +1651,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event case kEventMouseDown: edesc = "MouseButtonPress"; break; case kEventMouseUp: edesc = "MouseButtonRelease"; break; case kEventMouseDragged: case kEventMouseMoved: edesc = "MouseMove"; break; + case kEventMouseScroll: edesc = "MouseWheelScroll"; break; case kEventMouseWheelMoved: edesc = "MouseWheelMove"; break; } if(ekind == kEventMouseDown || ekind == kEventMouseUp) @@ -1659,12 +1672,43 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event sizeof(mac_buttons), 0, &mac_buttons); buttons = qt_mac_get_buttons(mac_buttons); } - int wheel_delta=0; - if(ekind == kEventMouseWheelMoved) { - int mdelt = 0; - GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, + + int wheel_deltaX = 0; + int wheel_deltaY = 0; + static EventRef compatibilityEvent = 0; + + if (ekind == kEventMouseScroll) { + // kEventMouseScroll is the new way of dealing with mouse wheel + // events (kEventMouseWheelMoved was the old). kEventMouseScroll results + // in much smoother scrolling when using Mighty Mouse or TrackPad. For + // compatibility with older applications, carbon will also send us + // kEventMouseWheelMoved events if we dont eat this event + // (actually two events; one for horizontal and one for vertical). + // As a results of this, and to make sure we dont't receive duplicate events, + // we try to detect when this happend by checking the 'compatibilityEvent'. + SInt32 mdelt = 0; + GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0, + sizeof(mdelt), 0, &mdelt); + wheel_deltaX = mdelt; + GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_delta = mdelt * 120; + wheel_deltaY = mdelt; + GetEventParameter(event, kEventParamEventRef, typeEventRef, 0, + sizeof(compatibilityEvent), 0, &compatibilityEvent); + } else if (ekind == kEventMouseWheelMoved) { + if (event != compatibilityEvent) { + compatibilityEvent = 0; + int mdelt = 0; + GetEventParameter(event, kEventParamMouseWheelDelta, typeSInt32, 0, + sizeof(mdelt), 0, &mdelt); + EventMouseWheelAxis axis; + GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, + sizeof(axis), 0, &axis); + if (axis == kEventMouseWheelAxisX) + wheel_deltaX = mdelt * 120; + else + wheel_deltaY = mdelt * 120; + } } Qt::MouseButton button = Qt::NoButton; @@ -2054,20 +2098,29 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event qt_mac_dblclick.last_button = button; qt_mac_dblclick.last_time = GetEventTime(event); } - if(wheel_delta) { - EventMouseWheelAxis axis; - GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, - sizeof(axis), 0, &axis); - QWheelEvent qwe(plocal, p, wheel_delta, buttons, modifiers, - axis == kEventMouseWheelAxisX ? Qt::Horizontal : Qt::Vertical); - QApplication::sendSpontaneousEvent(widget, &qwe); - if(!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { - QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, - wheel_delta, buttons, modifiers, - axis == kEventMouseWheelAxisX ? Qt::Horizontal : Qt::Vertical); - QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); - if(!qwe2.isAccepted()) - handled_event = false; + + if (wheel_deltaX || wheel_deltaY) { + if (wheel_deltaX) { + QWheelEvent qwe(plocal, p, wheel_deltaX, buttons, modifiers, Qt::Horizontal); + QApplication::sendSpontaneousEvent(widget, &qwe); + if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { + QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, + wheel_deltaX, buttons, modifiers, Qt::Horizontal); + QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); + if (!qwe2.isAccepted()) + handled_event = false; + } + } + if (wheel_deltaY) { + QWheelEvent qwe(plocal, p, wheel_deltaY, buttons, modifiers, Qt::Vertical); + QApplication::sendSpontaneousEvent(widget, &qwe); + if (!qwe.isAccepted() && QApplicationPrivate::focus_widget && QApplicationPrivate::focus_widget != widget) { + QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(p), p, + wheel_deltaY, buttons, modifiers, Qt::Vertical); + QApplication::sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2); + if (!qwe2.isAccepted()) + handled_event = false; + } } } else { #ifdef QMAC_SPEAK_TO_ME @@ -2130,7 +2183,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event plocal.x(), plocal.y(), event_desc, (QWidget*)widget, widget ? widget->objectName().toLocal8Bit().constData() : "*Unknown*", widget ? widget->metaObject()->className() : "*Unknown*", - button, (int)buttons, (int)modifiers, wheel_delta); + button, (int)buttons, (int)modifiers, wheel_deltaX); #endif } else { handled_event = false; diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index aec21fd..6036196 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -452,6 +452,7 @@ public: static bool fade_tooltip; static bool animate_toolbox; static bool widgetCount; // Coupled with -widgetcount switch + static bool load_testability; // Coupled with -testability switch #ifdef Q_WS_MAC static bool native_modal_dialog_active; #endif diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 2996bf3..71d0cd1 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -493,7 +493,7 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) alienWidget = qwidget; S60->mousePressTarget = alienWidget; } - + alienWidget = S60->mousePressTarget; if (alienWidget != S60->lastPointerEventTarget) @@ -613,7 +613,7 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod if (keyCode >= Qt::Key_Left && keyCode <= Qt::Key_Down || keyCode == Qt::Key_Select) { /*Explanation about virtualMouseAccel: Tapping an arrow key allows precise pixel positioning - Holding an arrow key down, acceleration is applied to allow cursor + Holding an arrow key down, acceleration is applied to allow cursor to be quickly moved to another part of the screen by key repeats. */ if (S60->virtualMouseLastKey == keyCode) { @@ -681,7 +681,7 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod } } #endif - + Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), @@ -1008,13 +1008,13 @@ void qt_init(QApplicationPrivate * /* priv */, int) S60->hasTouchscreen = true; S60->virtualMouseRequired = false; } - + if (touch) { QApplicationPrivate::navigationMode = Qt::NavigationModeNone; } else { QApplicationPrivate::navigationMode = Qt::NavigationModeKeypadDirectional; } - + #ifndef QT_NO_CURSOR //Check if window server pointer cursors are supported or not #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS @@ -1078,7 +1078,7 @@ void qt_cleanup() // it dies. delete QApplicationPrivate::inputContext; QApplicationPrivate::inputContext = 0; - + //Change mouse pointer back S60->wsSession().SetPointerCursorMode(EPointerCursorNone); @@ -1320,6 +1320,7 @@ void QApplication::beep() /*! \warning This function is only available on Symbian. + \since 4.6 This function processes an individual Symbian window server \a event. It returns 1 if the event was handled, 0 if @@ -1398,7 +1399,8 @@ int QApplication::s60ProcessEvent(TWsEvent *event) } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) && !w->d_func()->maybeBackingStore()) { w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); - w->update(); + w->d_func()->invalidateBuffer(w->rect()); + w->repaint(); } return 1; } @@ -1441,6 +1443,7 @@ int QApplication::s60ProcessEvent(TWsEvent *event) /*! \warning This virtual function is only available on Symbian. + \since 4.6 If you create an application that inherits QApplication and reimplement this function, you get direct access to events that the are received @@ -1458,6 +1461,7 @@ bool QApplication::s60EventFilter(TWsEvent * /* aEvent */) /*! \warning This function is only available on Symbian. + \since 4.6 Handles \a{command}s which are typically handled by CAknAppUi::HandleCommandL(). Qts Ui integration into Symbian is @@ -1469,11 +1473,17 @@ bool QApplication::s60EventFilter(TWsEvent * /* aEvent */) void QApplication::symbianHandleCommand(int command) { switch (command) { - case EEikCmdExit: #ifdef Q_WS_S60 - case EAknSoftkeyExit: + case EAknSoftkeyExit: { + QCloseEvent ev; + QApplication::sendSpontaneousEvent(this, &ev); + if (ev.isAccepted()) + quit(); + break; + } #endif - exit(); + case EEikCmdExit: + quit(); break; default: bool handled = QSoftKeyManager::handleCommand(command); @@ -1489,6 +1499,7 @@ void QApplication::symbianHandleCommand(int command) /*! \warning This function is only available on Symbian. + \since 4.6 Handles the resource change specified by \a type. @@ -1614,7 +1625,7 @@ void QApplicationPrivate::setNavigationMode(Qt::NavigationMode mode) const bool isCursorOn = (mode == Qt::NavigationModeCursorAuto && !S60->hasTouchscreen) || mode == Qt::NavigationModeCursorForceVisible; - + if (!wasCursorOn && isCursorOn) { //Show the cursor, when changing from another mode to cursor mode qt_symbian_set_cursor_visible(true); @@ -1644,7 +1655,7 @@ void QApplication::restoreOverrideCursor() if (qApp->d_func()->cursor_list.isEmpty()) return; qApp->d_func()->cursor_list.removeFirst(); - + if (!qApp->d_func()->cursor_list.isEmpty()) { qt_symbian_setGlobalCursor(qApp->d_func()->cursor_list.first()); } diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index 7693ca7..f482d1c 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -63,6 +63,11 @@ #include <qdebug.h> +@interface NSEvent (DeviceDelta) + - (CGFloat)deviceDeltaX; + - (CGFloat)deviceDeltaY; + - (CGFloat)deviceDeltaZ; +@end QT_BEGIN_NAMESPACE @@ -776,17 +781,27 @@ extern "C" { Qt::MouseButton buttons = cocoaButton2QtButton([theEvent buttonNumber]); bool wheelOK = false; Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]); - QWidget *widgetToGetMouse = qwidget; - - // Mouse wheel deltas seem to tick in at increments of 0.1. Qt widgets - // expect the delta to be a multiple of 120. - const int ScrollFactor = 10 * 120; - // The qMax(...) factor reduces the - // acceleration for large wheel deltas. - int deltaX = [theEvent deltaX] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaX])); - int deltaY = [theEvent deltaY] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaY])); - int deltaZ = [theEvent deltaZ] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaZ])); + int deltaX = 0; + int deltaY = 0; + int deltaZ = 0; + + const EventRef carbonEvent = (EventRef)[theEvent eventRef]; + const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; + if (carbonEventKind == kEventMouseScroll) { + // The mouse device containts pixel scroll + // wheel support (Mighty Mouse, Trackpad) + deltaX = (int)[theEvent deviceDeltaX] * 120; + deltaY = (int)[theEvent deviceDeltaY] * 120; + deltaZ = (int)[theEvent deviceDeltaZ] * 120; + } else { // carbonEventKind == kEventMouseWheelMoved + // Mouse wheel deltas seem to tick in at increments of 0.1. + // Qt widgets expect the delta to be a multiple of 120. + const int scrollFactor = 10 * 120; + deltaX = [theEvent deltaX] * scrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaX])); + deltaY = [theEvent deltaY] * scrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaY])); + deltaZ = [theEvent deltaZ] * scrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaZ])); + } if (deltaX != 0) { QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal); diff --git a/src/gui/kernel/qeventdispatcher_x11.cpp b/src/gui/kernel/qeventdispatcher_x11.cpp index ce1a11f..59977ec 100644 --- a/src/gui/kernel/qeventdispatcher_x11.cpp +++ b/src/gui/kernel/qeventdispatcher_x11.cpp @@ -105,7 +105,7 @@ bool QEventDispatcherX11::processEvents(QEventLoop::ProcessEventsFlags flags) // _qt_scrolldone protocols, queue all other // client messages if (event.xclient.format == 32) { - if (event.xclient.message_type == ATOM(WM_PROTOCOLS) || + if (event.xclient.message_type == ATOM(WM_PROTOCOLS) && (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) { break; } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) { diff --git a/src/gui/kernel/qguieventdispatcher_glib.cpp b/src/gui/kernel/qguieventdispatcher_glib.cpp index 6e98428..f8a638c 100644 --- a/src/gui/kernel/qguieventdispatcher_glib.cpp +++ b/src/gui/kernel/qguieventdispatcher_glib.cpp @@ -120,7 +120,7 @@ static gboolean x11EventSourceDispatch(GSource *s, GSourceFunc callback, gpointe // _qt_scrolldone protocols, queue all other // client messages if (event.xclient.format == 32) { - if (event.xclient.message_type == ATOM(WM_PROTOCOLS) || + if (event.xclient.message_type == ATOM(WM_PROTOCOLS) && (Atom) event.xclient.data.l[0] == ATOM(WM_TAKE_FOCUS)) { break; } else if (event.xclient.message_type == ATOM(_QT_SCROLL_DONE)) { diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 45ecb5a..91f4163 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -125,6 +125,7 @@ QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *act break; } action->setSoftKeyRole(softKeyRole); + action->setEnabled(actionWidget->isEnabled()); return action; } @@ -247,9 +248,17 @@ bool QSoftKeyManager::handleCommand(int command) if (command >= s60CommandStart && QSoftKeyManagerPrivate::softKeySource) { int index = command - s60CommandStart; const QList<QAction*>& softKeys = QSoftKeyManagerPrivate::softKeySource->actions(); - if (index < softKeys.count()) { - softKeys.at(index)->activate(QAction::Trigger); - return true; + for (int i = 0, j = 0; i < softKeys.count(); ++i) { + QAction *action = softKeys.at(i); + if (action->softKeyRole() != QAction::NoSoftKey) { + if (j == index) { + if (action->isEnabled()) { + action->activate(QAction::Trigger); + return true; + } + } + j++; + } } } diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 53ef682..08fe5b9 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -900,28 +900,30 @@ void QWidget::setAutoFillBackground(bool enabled) \sa QEvent, QPainter, QGridLayout, QBoxLayout - \section1 SoftKeys + \section1 Softkeys \since 4.6 - \preliminary - Softkeys API is a platform independent way of mapping actions to (hardware)keys - and toolbars provided by the underlying platform. + 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 + not correspond to any physical keys. Softkeys differ from other onscreen labels + in that they are contextual. - There are three major use cases supported. First one is a mobile device - with keypad navigation and no touch ui. Second use case is a mobile - device with touch ui. Third use case is desktop. For now the softkey API is - only implemented for Series60. + In Qt, contextual softkeys are added to a widget by calling addAction() and + passing a \c QAction with a softkey role set on it. When the widget + containing the softkey actions has focus, its softkeys should appear in + the user interface. Softkeys are discovered by traversing the widget + heirarchy so it is possible to define a single set of softkeys that are + present at all times by calling addAction() for a given top level widget. - QActions are set to widget(s) via softkey API. Actions in focused widget are - mapped to native toolbar or hardware keys. Even though the API allows to set - any amount of widgets there might be physical restrictions to amount of - softkeys that can be used by the device. + On some platforms, this concept overlaps with \c QMenuBar such that if no + other softkeys are found and the top level widget is a QMainWindow containing + a QMenuBar, the menubar actions may appear on one of the softkeys. - \e Series60: For series60 menu button is automatically mapped to left - soft key if there is QMainWindow with QMenuBar in widgets parent hierarchy. + Note: Currently softkeys are only supported on the Symbian Platform. - \sa softKeys() - \sa setSoftKey() + \sa addAction, QAction, QMenuBar */ @@ -10145,7 +10147,8 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) "QWidgetPrivate::high_attributes[] too small to contain all attributes in WidgetAttribute"); #ifdef Q_WS_WIN - if (attribute == Qt::WA_PaintOnScreen && on) { + // ### Don't use PaintOnScreen+paintEngine() to do native painting in 5.0 + if (attribute == Qt::WA_PaintOnScreen && on && !inherits("QGLWidget")) { // see qwidget_win.cpp, ::paintEngine for details paintEngine(); if (d->noPaintOnScreen) diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 5659aef..62e08f3 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -691,6 +691,8 @@ void QColor::setHsv(int h, int s, int v, int a) } /*! + \since 4.6 + Sets the contents pointed to by \a h, \a s, \a l, and \a a, to the hue, saturation, lightness, and alpha-channel (transparency) components of the color's HSL value. @@ -719,6 +721,8 @@ void QColor::getHslF(qreal *h, qreal *s, qreal *l, qreal *a) const } /*! + \since 4.6 + Sets the contents pointed to by \a h, \a s, \a l, and \a a, to the hue, saturation, lightness, and alpha-channel (transparency) components of the color's HSL value. @@ -747,6 +751,8 @@ void QColor::getHsl(int *h, int *s, int *l, int *a) const } /*! + \since 4.6 + Sets a HSL color lightness; \a h is the hue, \a s is the saturation, \a l is the lightness and \a a is the alpha component of the HSL color. @@ -773,6 +779,8 @@ void QColor::setHslF(qreal h, qreal s, qreal l, qreal a) } /*! + \since 4.6 + Sets a HSL color value; \a h is the hue, \a s is the saturation, \a l is the lightness and \a a is the alpha component of the HSL color. @@ -1332,6 +1340,8 @@ qreal QColor::valueF() const } /*! + \since 4.6 + Returns the hue color component of this color. \sa getHslF(), getHsl() @@ -1344,6 +1354,8 @@ int QColor::hslHue() const } /*! + \since 4.6 + Returns the saturation color component of this color. \sa saturationF(), getHsv(), {QColor#The HSV Color Model}{The HSV Color @@ -1357,6 +1369,8 @@ int QColor::hslSaturation() const } /*! + \since 4.6 + Returns the lightness color component of this color. \sa lightnessF(), getHsl() @@ -1369,6 +1383,8 @@ int QColor::lightness() const } /*! + \since 4.6 + Returns the hue color component of this color. \sa hue(), getHslF() @@ -1381,6 +1397,8 @@ qreal QColor::hslHueF() const } /*! + \since 4.6 + Returns the saturation color component of this color. \sa saturationF() getHslF() @@ -1393,6 +1411,8 @@ qreal QColor::hslSaturationF() const } /*! + \since 4.6 + Returns the lightness color component of this color. \sa value() getHslF() @@ -1979,6 +1999,8 @@ QColor QColor::fromHsvF(qreal h, qreal s, qreal v, qreal a) } /*! + \since 4.6 + Static convenience function that returns a QColor constructed from the HSV color values, \a h (hue), \a s (saturation), \a l (lightness), and \a a (alpha-channel, i.e. transparency). @@ -2010,6 +2032,7 @@ QColor QColor::fromHsl(int h, int s, int l, int a) /*! \overload + \since 4.6 Static convenience function that returns a QColor constructed from the HSV color values, \a h (hue), \a s (saturation), \a l (lightness), and \a a diff --git a/src/gui/painting/qdrawhelper_mmx.cpp b/src/gui/painting/qdrawhelper_mmx.cpp index 0dcc3dd..d81e2a9 100644 --- a/src/gui/painting/qdrawhelper_mmx.cpp +++ b/src/gui/painting/qdrawhelper_mmx.cpp @@ -128,7 +128,7 @@ void qt_blend_rgb32_on_rgb32_mmx(uchar *destPixels, int dbpl, } } +QT_END_NAMESPACE #endif // QT_HAVE_MMX -QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_mmx3dnow.cpp b/src/gui/painting/qdrawhelper_mmx3dnow.cpp index 0db89f0..2d40ae3 100644 --- a/src/gui/painting/qdrawhelper_mmx3dnow.cpp +++ b/src/gui/painting/qdrawhelper_mmx3dnow.cpp @@ -101,6 +101,7 @@ void qt_blend_color_argb_mmx3dnow(int count, const QSpan *spans, void *userData) (CompositionFunctionSolid*)qt_functionForModeSolid_MMX3DNOW); } +QT_END_NAMESPACE + #endif // QT_HAVE_3DNOW -QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index 1038f74..6b9d77c 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -44,11 +44,14 @@ //#include <private/qtextengine_p.h> #include <private/qfontengine_p.h> #include <private/qemulationpaintengine_p.h> +#include <private/qimage_p.h> #include <QDebug> //#define QPAINTBUFFER_DEBUG_DRAW +QT_BEGIN_NAMESPACE + extern int qt_defaultDpiX(); extern int qt_defaultDpiY(); extern void qt_format_text(const QFont &font, @@ -890,6 +893,12 @@ void QPaintBufferEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) buffer->updateBoundingRect(QRectF(pos, pm.size())); } +static inline QImage qpaintbuffer_storable_image(const QImage &src) +{ + QImageData *d = const_cast<QImage &>(src).data_ptr(); + return d->own_data ? src : src.copy(); +} + void QPaintBufferEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags /*flags */) { @@ -897,7 +906,8 @@ void QPaintBufferEngine::drawImage(const QRectF &r, const QImage &image, const Q qDebug() << "QPaintBufferEngine: drawImage: src/dest rects " << r << sr; #endif QPaintBufferCommand *cmd = - buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPixmapRect, QVariant(image)); + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImageRect, + QVariant(qpaintbuffer_storable_image(image))); cmd->extra = buffer->addData((qreal *) &r, 4); buffer->addData((qreal *) &sr, 4); // ### flags... @@ -911,7 +921,8 @@ void QPaintBufferEngine::drawImage(const QPointF &pos, const QImage &image) qDebug() << "QPaintBufferEngine: drawImage: pos:" << pos; #endif QPaintBufferCommand *cmd = - buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImagePos, QVariant(image)); + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawImagePos, + QVariant(qpaintbuffer_storable_image(image))); cmd->extra = buffer->addData((qreal *) &pos, 2); if (buffer->calculateBoundingRect) buffer->updateBoundingRect(QRectF(pos, image.size())); @@ -1740,7 +1751,9 @@ struct QPaintBufferCacheEntry QVariant::Type type; quint64 cacheKey; }; +QT_END_NAMESPACE Q_DECLARE_METATYPE(QPaintBufferCacheEntry) +QT_BEGIN_NAMESPACE QDataStream &operator<<(QDataStream &stream, const QPaintBufferCacheEntry &entry) { @@ -1832,3 +1845,4 @@ QDataStream &operator>>(QDataStream &stream, QPaintBuffer &buffer) return stream; } +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index a80fa8d..6a7ac73 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -59,6 +59,8 @@ #include <private/qtextengine_p.h> #include <QDebug> +QT_BEGIN_NAMESPACE + class QPaintBufferPrivate; class QPaintBufferPlayback; @@ -440,4 +442,6 @@ private: FreeFunc free; }; +QT_END_NAMESPACE + #endif // QPAINTBUFFER_P_H diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index ed1b5d1..f271af9 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1895,6 +1895,8 @@ QPaintEngine *QPainter::paintEngine() const } /*! + \since 4.6 + Flushes the painting pipeline and prepares for the user issuing commands directly to the underlying graphics context. Must be followed by a call to endNativePainting(). @@ -1919,6 +1921,8 @@ void QPainter::beginNativePainting() } /*! + \since 4.6 + Restores the painter after manually issuing native painting commands. Lets the painter restore any native state that it relies on before calling any other painter commands. diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index eb9b11b..5ff0b96 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -1275,7 +1275,7 @@ QPrinter::ColorMode QPrinter::colorMode() const buffering up the copies and in those cases the application must make an explicit call to the print code for each copy. - \sa setNumCopies() + \sa setNumCopies(), actualNumCopies() */ int QPrinter::numCopies() const @@ -1286,13 +1286,15 @@ int QPrinter::numCopies() const /*! + \since 4.6 + Returns the number of copies that will be printed. The default value is 1. This function always returns the actual value specified in the print dialog or using setNumCopies(). - \sa setNumCopies(), numCopies(); + \sa setNumCopies(), numCopies() */ int QPrinter::actualNumCopies() const { diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp index 825b2ec..dee3168 100644 --- a/src/gui/statemachine/qkeyeventtransition.cpp +++ b/src/gui/statemachine/qkeyeventtransition.cpp @@ -44,7 +44,7 @@ #ifndef QT_NO_STATEMACHINE #include "qbasickeyeventtransition_p.h" -#include <QtCore/qwrappedevent.h> +#include <QtCore/qstatemachine.h> #include <private/qeventtransition_p.h> QT_BEGIN_NAMESPACE @@ -160,7 +160,7 @@ bool QKeyEventTransition::eventTest(QEvent *event) Q_D(const QKeyEventTransition); if (!QEventTransition::eventTest(event)) return false; - QWrappedEvent *we = static_cast<QWrappedEvent*>(event); + QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(event); d->transition->setEventType(we->event()->type()); return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event()); } diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp index 564c8d2..86cacf7 100644 --- a/src/gui/statemachine/qmouseeventtransition.cpp +++ b/src/gui/statemachine/qmouseeventtransition.cpp @@ -44,7 +44,7 @@ #ifndef QT_NO_STATEMACHINE #include "qbasicmouseeventtransition_p.h" -#include <QtCore/qwrappedevent.h> +#include <QtCore/qstatemachine.h> #include <QtGui/qpainterpath.h> #include <private/qeventtransition_p.h> @@ -188,7 +188,7 @@ bool QMouseEventTransition::eventTest(QEvent *event) Q_D(const QMouseEventTransition); if (!QEventTransition::eventTest(event)) return false; - QWrappedEvent *we = static_cast<QWrappedEvent*>(event); + QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(event); d->transition->setEventType(we->event()->type()); return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event()); } diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index b6ff39f..d9438fd 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1370,7 +1370,7 @@ int QTextBlock::firstLineNumber() const Sets the line count to \a count. -/sa lineCount() +\sa lineCount() */ void QTextBlock::setLineCount(int count) { diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index b78e51b..fd06cf3 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -70,7 +70,6 @@ QT_BEGIN_NAMESPACE _LIT(KCacheSubDir, "Cache\\"); _LIT(KSysBin, "\\Sys\\Bin\\"); -_LIT(KTempDir, "\\System\\Temp\\"); _LIT(KBrowserPrefix, "4 " ); _LIT(KFontsDir, "z:\\resource\\Fonts\\"); const TUid KUidBrowser = { 0x10008D39 }; @@ -381,9 +380,7 @@ QString QDesktopServices::storageLocation(StandardLocation type) #endif break; case TempLocation: - path.Append(writableExeDrive().Name()); - path.Append(KTempDir); - //return QDir::tempPath(); break; + return QDir::tempPath(); break; case HomeLocation: path.Append(writableDataRoot()); diff --git a/src/gui/widgets/qcalendarwidget.cpp b/src/gui/widgets/qcalendarwidget.cpp index 71588c4..08ed7f6 100644 --- a/src/gui/widgets/qcalendarwidget.cpp +++ b/src/gui/widgets/qcalendarwidget.cpp @@ -3022,11 +3022,21 @@ bool QCalendarWidget::event(QEvent *event) bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event) { Q_D(QCalendarWidget); - if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus() && !QRect(d->yearEdit->mapToGlobal(QPoint(0, 0)), d->yearEdit->size()).contains(static_cast<QMouseEvent *>(event)->globalPos())) { - event->accept(); - d->_q_yearEditingFinished(); - setFocus(); - return true; + if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) { + QWidget *tlw = window(); + QWidget *widget = static_cast<QWidget*>(watched); + //as we have a event filter on the whole application we first make sure that the top level widget + //of both this and the watched widget are the same to decide if we should finish the year edition. + if (widget->window() == tlw) { + QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos()); + QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size()); + if (!geom.contains(mousePos)) { + event->accept(); + d->_q_yearEditingFinished(); + setFocus(); + return true; + } + } } return QWidget::eventFilter(watched, event); } diff --git a/src/gui/widgets/qdialogbuttonbox.cpp b/src/gui/widgets/qdialogbuttonbox.cpp index 39566ef..6cc720d 100644 --- a/src/gui/widgets/qdialogbuttonbox.cpp +++ b/src/gui/widgets/qdialogbuttonbox.cpp @@ -593,6 +593,7 @@ QAction* QDialogButtonBoxPrivate::createSoftKey(QAbstractButton *button, QDialog } QObject::connect(action, SIGNAL(triggered()), button, SIGNAL(clicked())); action->setSoftKeyRole(softkeyRole); + action->setEnabled(button->isEnabled()); return action; } #endif diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp index e682364..9eb07ac 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -61,8 +61,6 @@ QT_BEGIN_NAMESPACE # define QSBDEBUG if (false) qDebug #endif -static bool isIntermediateValueHelper(qint64 num, qint64 minimum, qint64 maximum, qint64 *match = 0); - class QSpinBoxPrivate : public QAbstractSpinBoxPrivate { Q_DECLARE_PUBLIC(QSpinBox) @@ -74,7 +72,6 @@ public: virtual QString textFromValue(const QVariant &n) const; QVariant validateAndInterpret(QString &input, int &pos, QValidator::State &state) const; - bool isIntermediateValue(const QString &str) const; QChar thousand; inline void init() { @@ -90,7 +87,6 @@ class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate public: QDoubleSpinBoxPrivate(QWidget *parent = 0); void emitSignals(EmitPolicy ep, const QVariant &); - bool isIntermediateValue(const QString &str) const; virtual QVariant valueFromText(const QString &n) const; virtual QString textFromValue(const QVariant &n) const; @@ -991,51 +987,6 @@ QVariant QSpinBoxPrivate::valueFromText(const QString &text) const /*! - \internal - - Return true if str can become a number which is between minimum and - maximum or false if this is not possible. -*/ - -bool QSpinBoxPrivate::isIntermediateValue(const QString &str) const -{ - const int num = locale.toInt(str, 0, 10); - const int min = minimum.toInt(); - const int max = maximum.toInt(); - - int numDigits = 0; - int digits[10]; - int tmp = num; - if (tmp == 0) { - numDigits = 1; - digits[0] = 0; - } else { - tmp = num; - for (int i=0; tmp != 0; ++i) { - digits[numDigits++] = qAbs(tmp % 10); - tmp /= 10; - } - } - - int failures = 0; - for (int number=min; /*number<=max*/; ++number) { - tmp = number; - for (int i=0; tmp != 0;) { - if (digits[i] == qAbs(tmp % 10)) { - if (++i == numDigits) - return true; - } - tmp /= 10; - } - if (failures++ == 500000) //upper bound - return true; - if (number == max) // needed for INT_MAX - break; - } - return false; -} - -/*! \internal Multi purpose function that parses input, sets state to the appropriate state and returns the value it will be interpreted as. @@ -1089,9 +1040,8 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { - state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to " - << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable"); + state = QValidator::Intermediate; + QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; } } } @@ -1151,105 +1101,6 @@ void QDoubleSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old) } -bool QDoubleSpinBoxPrivate::isIntermediateValue(const QString &str) const -{ - QSBDEBUG() << "input is" << str << minimum << maximum; - qint64 dec = 1; - for (int i=0; i<decimals; ++i) - dec *= 10; - - const QLatin1Char dot('.'); - - // I know QString::number() uses CLocale so I use dot - const QString minstr = QString::number(minimum.toDouble(), 'f', decimals); - bool ok; - qint64 min_left = minstr.left(minstr.indexOf(dot)).toLongLong(&ok); - if (!ok) - return false; - qint64 min_right = minstr.mid(minstr.indexOf(dot) + 1).toLongLong(); - - const QString maxstr = QString::number(maximum.toDouble(), 'f', decimals); - qint64 max_left = maxstr.left(maxstr.indexOf(dot)).toLongLong(&ok); - if (!ok) - return true; - qint64 max_right = maxstr.mid(maxstr.indexOf(dot) + 1).toLongLong(); - - const int dotindex = str.indexOf(delimiter); - const bool negative = maximum.toDouble() < 0; - qint64 left = 0, right = 0; - bool doleft = true; - bool doright = true; - if (dotindex == -1) { - left = str.toLongLong(); - doright = false; - } else if (dotindex == 0 || (dotindex == 1 && str.at(0) == QLatin1Char('+'))) { - if (negative) { - QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; - return false; - } - doleft = false; - right = str.mid(dotindex + 1).toLongLong(); - } else if (dotindex == 1 && str.at(0) == QLatin1Char('-')) { - if (!negative) { - QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; - return false; - } - doleft = false; - right = str.mid(dotindex + 1).toLongLong(); - } else { - left = str.left(dotindex).toLongLong(); - if (dotindex == str.size() - 1) { - doright = false; - } else { - right = str.mid(dotindex + 1).toLongLong(); - } - } - if ((left >= 0 && max_left < 0 && !str.startsWith(QLatin1Char('-'))) || (left < 0 && min_left >= 0)) { - QSBDEBUG("returns false 0"); - return false; - } - - qint64 match = min_left; - if (doleft && !isIntermediateValueHelper(left, min_left, max_left, &match)) { - QSBDEBUG() << __FILE__ << __LINE__ << "returns false"; - return false; - } - if (doright) { - QSBDEBUG() << "match" << match << "min_left" << min_left << "max_left" << max_left; - if (!doleft) { - if (min_left == max_left) { - const bool ret = isIntermediateValueHelper(qAbs(left), - negative ? max_right : min_right, - negative ? min_right : max_right); - QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; - return ret; - } else if (qAbs(max_left - min_left) == 1) { - const bool ret = isIntermediateValueHelper(qAbs(left), min_right, negative ? 0 : dec) - || isIntermediateValueHelper(qAbs(left), negative ? dec : 0, max_right); - QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; - return ret; - } else { - const bool ret = isIntermediateValueHelper(qAbs(left), 0, dec); - QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; - return ret; - } - } - if (match != min_left) { - min_right = negative ? dec : 0; - } - if (match != max_left) { - max_right = negative ? 0 : dec; - } - qint64 tmpl = negative ? max_right : min_right; - qint64 tmpr = negative ? min_right : max_right; - const bool ret = isIntermediateValueHelper(right, tmpl, tmpr); - QSBDEBUG() << __FILE__ << __LINE__ << "returns" << ret; - return ret; - } - QSBDEBUG() << __FILE__ << __LINE__ << "returns true"; - return true; -} - /*! \internal \reimp @@ -1415,9 +1266,8 @@ QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, state = QValidator::Invalid; QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid"; } else { - state = isIntermediateValue(copy) ? QValidator::Intermediate : QValidator::Invalid; - QSBDEBUG() << __FILE__ << __LINE__<< "state is set to " - << (state == QValidator::Intermediate ? "Intermediate" : "Acceptable"); + state = QValidator::Intermediate; + QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate"; } } } @@ -1475,62 +1325,6 @@ QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const Use minimum() instead. */ -/*! - \internal Returns whether \a str is a string which value cannot be - parsed but still might turn into something valid. -*/ - -static bool isIntermediateValueHelper(qint64 num, qint64 min, qint64 max, qint64 *match) -{ - QSBDEBUG() << num << min << max; - - if (num >= min && num <= max) { - if (match) - *match = num; - QSBDEBUG("returns true 0"); - return true; - } - qint64 tmp = num; - - int numDigits = 0; - int digits[10]; - if (tmp == 0) { - numDigits = 1; - digits[0] = 0; - } else { - tmp = qAbs(num); - for (int i=0; tmp > 0; ++i) { - digits[numDigits++] = tmp % 10; - tmp /= 10; - } - } - - int failures = 0; - qint64 number; - for (number=max; number>=min; --number) { - tmp = qAbs(number); - for (int i=0; tmp > 0;) { - if (digits[i] == (tmp % 10)) { - if (++i == numDigits) { - if (match) - *match = number; - QSBDEBUG("returns true 1"); - return true; - } - } - tmp /= 10; - } - if (failures++ == 500000) { //upper bound - if (match) - *match = num; - QSBDEBUG("returns true 2"); - return true; - } - } - QSBDEBUG("returns false"); - return false; -} - /*! \reimp */ bool QSpinBox::event(QEvent *event) { diff --git a/src/gui/widgets/qtabbar.cpp b/src/gui/widgets/qtabbar.cpp index 92e4eb4..6c9761c 100644 --- a/src/gui/widgets/qtabbar.cpp +++ b/src/gui/widgets/qtabbar.cpp @@ -1100,7 +1100,7 @@ QVariant QTabBar::tabData(int index) const } /*! - Returns the visual rectangle of the of the tab at position \a + Returns the visual rectangle of the tab at position \a index, or a null rectangle if \a index is out of range. */ QRect QTabBar::tabRect(int index) const diff --git a/src/gui/widgets/qwidgetanimator.cpp b/src/gui/widgets/qwidgetanimator.cpp index d4a61e3..f440961 100644 --- a/src/gui/widgets/qwidgetanimator.cpp +++ b/src/gui/widgets/qwidgetanimator.cpp @@ -60,7 +60,9 @@ void QWidgetAnimator::abort(QWidget *w) QPropertyAnimation *anim = *it; m_animation_map.erase(it); anim->stop(); +#ifndef QT_NO_MAINWINDOW m_mainWindowLayout->animationFinished(w); +#endif #else Q_UNUSED(w); //there is no animation to abort #endif //QT_NO_ANIMATION |