diff options
37 files changed, 1075 insertions, 208 deletions
diff --git a/mkspecs/features/resources.prf b/mkspecs/features/resources.prf index d8fae77c4b..cd00aba90f 100644 --- a/mkspecs/features/resources.prf +++ b/mkspecs/features/resources.prf @@ -3,15 +3,27 @@ qtPrepareTool(QMAKE_RCC, rcc, _DEP) isEmpty(RCC_DIR):RCC_DIR = . isEmpty(QMAKE_MOD_RCC):QMAKE_MOD_RCC = qrc -rcc.output = $$RCC_DIR/$${first(QMAKE_MOD_RCC)}_${QMAKE_FILE_BASE}$${first(QMAKE_EXT_CPP)} !contains(QMAKE_RESOURCE_FLAGS, -root):!isEmpty(QMAKE_RESOURCE_ROOT):QMAKE_RESOURCE_FLAGS += -root $$QMAKE_RESOURCE_ROOT !contains(QMAKE_RESOURCE_FLAGS, -name): QMAKE_RESOURCE_FLAGS += -name ${QMAKE_FILE_BASE} -rcc.commands = $$QMAKE_RCC $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} -rcc.depend_command = $$QMAKE_RCC_DEP -list $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} -rcc.CONFIG += add_inputs_as_makefile_deps +isEmpty(RCC_CXX):RCC_CXX = $$QMAKE_CXX $(CXXFLAGS) +RCC_OUT_BASE = $$RCC_DIR/$${first(QMAKE_MOD_RCC)}_${QMAKE_FILE_BASE} +RCC_CPP = $$RCC_OUT_BASE$${first(QMAKE_EXT_CPP)} +RCC_TMP = $${RCC_OUT_BASE}.tmp$${first(QMAKE_EXT_OBJ)} +RCC_OBJ = $$RCC_OUT_BASE$${first(QMAKE_EXT_OBJ)} + +msvc: RCC_CXX_O_FLAG = "-Fo" +else: RCC_CXX_O_FLAG = "-o " + rcc.input = RESOURCES -rcc.variable_out = SOURCES +rcc.CONFIG += add_inputs_as_makefile_deps rcc.name = RCC ${QMAKE_FILE_IN} +rcc.output = $$RCC_OBJ +rcc.depend_command = $$QMAKE_RCC_DEP -list $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} +rcc.commands = \ + $$QMAKE_RCC $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} -pass 1 -o $$RCC_CPP && \ + $$RCC_CXX -c $$RCC_CPP $$RCC_CXX_O_FLAG$$RCC_TMP && \ + $$QMAKE_RCC $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN} -pass 2 -temp $$RCC_TMP -o ${QMAKE_FILE_OUT} +rcc.clean += $$RCC_CPP $$RCC_TMP silent:rcc.commands = @echo rcc ${QMAKE_FILE_IN} && $$rcc.commands QMAKE_EXTRA_COMPILERS += rcc diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index 38eb9c4570..e6005b9a88 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1496,6 +1496,42 @@ public class ExtractStyle { } } + void extractCalendar(SimpleJsonWriter writer, String styleName, String qtClass) + { + JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1); + try { + Class<?> attrClass = Class.forName("android.R$attr"); + int styleId = attrClass.getDeclaredField(styleName).getInt(null); + + int[] styleAttrs = (int[]) styleableClass.getDeclaredField("CalendarView").get(null); + TypedArray a = m_theme.obtainStyledAttributes(null, styleAttrs, styleId, 0); + + Drawable d = a.getDrawable(getField(styleableClass,"CalendarView_selectedDateVerticalBar")); + if (d != null) + json.put("CalendarView_selectedDateVerticalBar", getDrawable(d, styleName + "_CalendarView_selectedDateVerticalBar")); + + int dateTextAppearance = a.getResourceId(styleableClass.getDeclaredField("CalendarView_dateTextAppearance").getInt(null), -1); + json.put("CalendarView_dateTextAppearance", extractTextAppearanceInformations(styleName, null, null, dateTextAppearance, styleId)); + + int weekDayTextAppearance = a.getResourceId(styleableClass.getDeclaredField("CalendarView_weekDayTextAppearance").getInt(null), -1); + json.put("CalendarView_weekDayTextAppearance", extractTextAppearanceInformations(styleName, null, null, weekDayTextAppearance, styleId)); + + json.put("CalendarView_firstDayOfWeek", a.getInt(getField(styleableClass, "CalendarView_firstDayOfWeek"), 0)); + json.put("CalendarView_focusedMonthDateColor", a.getColor(getField(styleableClass, "CalendarView_focusedMonthDateColor"), 0)); + json.put("CalendarView_selectedWeekBackgroundColor", a.getColor(getField(styleableClass, "CalendarView_selectedWeekBackgroundColor"), 0)); + json.put("CalendarView_showWeekNumber", a.getBoolean(getField(styleableClass, "CalendarView_showWeekNumber"), true)); + json.put("CalendarView_shownWeekCount", a.getInt(getField(styleableClass, "CalendarView_shownWeekCount"), 6)); + json.put("CalendarView_unfocusedMonthDateColor", a.getColor(getField(styleableClass, "CalendarView_unfocusedMonthDateColor"), 0)); + json.put("CalendarView_weekNumberColor", a.getColor(getField(styleableClass, "CalendarView_weekNumberColor"), 0)); + json.put("CalendarView_weekSeparatorLineColor", a.getColor(getField(styleableClass, "CalendarView_weekSeparatorLineColor"), 0)); + + a.recycle(); + writer.name(styleName).value(json); + } catch (Exception e) { + e.printStackTrace(); + } + } + void extractToolBar(SimpleJsonWriter writer, String styleName, String qtClass) { JSONObject json = extractTextAppearanceInformations(styleName, qtClass, null, -1); @@ -1570,6 +1606,7 @@ public class ExtractStyle { extractItemsStyle(jsonWriter); extractCompoundButton(jsonWriter, "buttonStyleToggle", null); if (Build.VERSION.SDK_INT > 10) { + extractCalendar(jsonWriter, "calendarViewStyle", "QCalendarWidget"); extractToolBar(jsonWriter, "actionBarStyle", "QToolBar"); jsonWriter.name("actionButtonStyle").value(extractTextAppearanceInformations("actionButtonStyle", "QToolButton", null, -1)); } diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index 4a602e4b2b..8bbf146e11 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -171,89 +171,15 @@ static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const cha } #endif -#if !defined(QT_NO_EXCEPTIONS) -/*! - \internal - Uses a local buffer to output the message. Not locale safe + cuts off - everything after character 255, but will work in out of memory situations. - Stop the execution afterwards. -*/ -static void qEmergencyOut(QtMsgType msgType, const char *msg, va_list ap) Q_DECL_NOEXCEPT -{ - char emergency_buf[256] = { '\0' }; - emergency_buf[sizeof emergency_buf - 1] = '\0'; -#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) && (defined(Q_OS_WINCE) || defined(Q_OS_WINRT)) \ - || defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) - wchar_t emergency_bufL[sizeof emergency_buf]; -#endif - - if (msg) - qvsnprintf(emergency_buf, sizeof emergency_buf - 1, msg, ap); - -#if defined(Q_OS_WIN) && defined(QT_BUILD_CORE_LIB) -# if defined(Q_OS_WINCE) || defined(Q_OS_WINRT) - convert_to_wchar_t_elided(emergency_bufL, sizeof emergency_buf, emergency_buf); - OutputDebugStringW(emergency_bufL); -# else - if (qWinLogToStderr()) { - fprintf(stderr, "%s\n", emergency_buf); - fflush(stderr); - } else { - OutputDebugStringA(emergency_buf); - } -# endif -#else - fprintf(stderr, "%s\n", emergency_buf); - fflush(stderr); -#endif - - if (isFatal(msgType)) { -#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) - // get the current report mode - int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); - _CrtSetReportMode(_CRT_ERROR, reportMode); -# ifndef Q_OS_WINCE // otherwise already converted to wchar_t above - convert_to_wchar_t_elided(emergency_bufL, sizeof emergency_buf, emergency_buf); -# endif - int ret = _CrtDbgReportW(_CRT_ERROR, _CRT_WIDE(__FILE__), __LINE__, - _CRT_WIDE(QT_VERSION_STR), - emergency_bufL); - if (ret == 1) - _CrtDbgBreak(); -#endif - -#if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW)) - abort(); // trap; generates core dump -#else - exit(1); // goodbye cruel world -#endif - } -} -#endif - /*! \internal */ static void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap, QString &buf) { -#if !defined(QT_NO_EXCEPTIONS) - if (std::uncaught_exception()) { - qEmergencyOut(msgType, msg, ap); - return; - } -#endif - if (msg) { - QT_TRY { - buf = QString().vsprintf(msg, ap); - } QT_CATCH(const std::bad_alloc &) { -#if !defined(QT_NO_EXCEPTIONS) - qEmergencyOut(msgType, msg, ap); - // don't rethrow - we use qWarning and friends in destructors. - return; -#endif - } - } + + if (msg) + buf = QString().vsprintf(msg, ap); qt_message_print(msgType, context, buf); } diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp index 09c155515e..96dde1ea3f 100644 --- a/src/gui/accessible/qaccessiblecache.cpp +++ b/src/gui/accessible/qaccessiblecache.cpp @@ -121,7 +121,7 @@ void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj) objectToId.remove(obj); delete iface; -#ifdef Q_OS_MACX +#ifdef Q_OS_MAC removeCocoaElement(id); #endif } diff --git a/src/gui/accessible/qaccessiblecache_mac.mm b/src/gui/accessible/qaccessiblecache_mac.mm index 861423af7d..bc6d0712d6 100644 --- a/src/gui/accessible/qaccessiblecache_mac.mm +++ b/src/gui/accessible/qaccessiblecache_mac.mm @@ -41,27 +41,23 @@ #include "qaccessiblecache_p.h" -#ifdef Q_OS_OSX - QT_BEGIN_NAMESPACE -void QAccessibleCache::insertElement(QAccessible::Id axid, QCocoaAccessibleElement *element) const +void QAccessibleCache::insertElement(QAccessible::Id axid, QMacAccessibilityElement *element) const { cocoaElements[axid] = element; } void QAccessibleCache::removeCocoaElement(QAccessible::Id axid) { - QCocoaAccessibleElement *element = elementForId(axid); + QMacAccessibilityElement *element = elementForId(axid); [element invalidate]; cocoaElements.remove(axid); } -QCocoaAccessibleElement *QAccessibleCache::elementForId(QAccessible::Id axid) const +QMacAccessibilityElement *QAccessibleCache::elementForId(QAccessible::Id axid) const { return cocoaElements.value(axid); } QT_END_NAMESPACE - -#endif diff --git a/src/gui/accessible/qaccessiblecache_p.h b/src/gui/accessible/qaccessiblecache_p.h index 30b023cfbd..3ca62709b1 100644 --- a/src/gui/accessible/qaccessiblecache_p.h +++ b/src/gui/accessible/qaccessiblecache_p.h @@ -59,7 +59,9 @@ #include "qaccessible.h" -Q_FORWARD_DECLARE_OBJC_CLASS(QCocoaAccessibleElement); +#ifdef Q_OS_MAC + Q_FORWARD_DECLARE_OBJC_CLASS(QMacAccessibilityElement); +#endif QT_BEGIN_NAMESPACE @@ -73,9 +75,9 @@ public: QAccessible::Id insert(QObject *object, QAccessibleInterface *iface) const; void deleteInterface(QAccessible::Id id, QObject *obj = 0); -#ifdef Q_OS_OSX - QCocoaAccessibleElement *elementForId(QAccessible::Id axid) const; - void insertElement(QAccessible::Id axid, QCocoaAccessibleElement *element) const; +#ifdef Q_OS_MAC + QMacAccessibilityElement *elementForId(QAccessible::Id axid) const; + void insertElement(QAccessible::Id axid, QMacAccessibilityElement *element) const; #endif private Q_SLOTS: @@ -87,9 +89,9 @@ private: mutable QHash<QAccessible::Id, QAccessibleInterface *> idToInterface; mutable QHash<QObject *, QAccessible::Id> objectToId; -#ifdef Q_OS_OSX +#ifdef Q_OS_MAC void removeCocoaElement(QAccessible::Id axid); - mutable QHash<QAccessible::Id, QCocoaAccessibleElement *> cocoaElements; + mutable QHash<QAccessible::Id, QMacAccessibilityElement *> cocoaElements; #endif friend class QAccessible; diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index a6feda8732..231e475111 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -1119,6 +1119,14 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, Will try to return a premultiplied ARBG32 or RGB32 image. Since 5.2 it will fall back to a premultiplied RGBA8888 or RGBx8888 image when reading to ARGB32 is not supported. + + For multisampled framebuffer objects the samples are resolved using the + \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents + of the returned image is undefined. + + For singlesampled framebuffers the contents is retrieved via \c glReadPixels. This is + a potentially expensive and inefficient operation. Therefore it is recommended that + this function is used as seldom as possible. */ QImage QOpenGLFramebufferObject::toImage() const { @@ -1126,6 +1134,19 @@ QImage QOpenGLFramebufferObject::toImage() const if (!d->valid) return QImage(); + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) { + qWarning("QOpenGLFramebufferObject::toImage() called without a current context"); + return QImage(); + } + + GLuint prevFbo = 0; + ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); + + if (prevFbo != d->fbo()) + const_cast<QOpenGLFramebufferObject *>(this)->bind(); + + QImage image; // qt_gl_read_framebuffer doesn't work on a multisample FBO if (format().samples() != 0) { QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat()); @@ -1133,15 +1154,13 @@ QImage QOpenGLFramebufferObject::toImage() const QRect rect(QPoint(0, 0), size()); blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect); - return temp.toImage(); + image = temp.toImage(); + } else { + image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true); } - bool wasBound = isBound(); - if (!wasBound) - const_cast<QOpenGLFramebufferObject *>(this)->bind(); - QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true); - if (!wasBound) - const_cast<QOpenGLFramebufferObject *>(this)->release(); + if (prevFbo != d->fbo()) + ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); return image; } @@ -1213,6 +1232,8 @@ QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() cons This can be used to free or reattach the depth and stencil buffer attachments as needed. + + \note This function alters the current framebuffer binding. */ void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment) { @@ -1296,6 +1317,9 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, If \a source or \a target is 0, the default framebuffer will be used instead of a framebuffer object as source or target respectively. + This function will have no effect unless hasOpenGLFramebufferBlit() returns + true. + The \a buffers parameter should be a mask consisting of any combination of \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both @@ -1312,10 +1336,7 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, have different sizes. The sizes must also be the same if any of the framebuffer objects are multisample framebuffers. - Note that the scissor test will restrict the blit area if enabled. - - This function will have no effect unless hasOpenGLFramebufferBlit() returns - true. + \note The scissor test will restrict the blit area if enabled. \sa hasOpenGLFramebufferBlit() */ @@ -1332,6 +1353,9 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) return; + GLuint prevFbo = 0; + ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); + const int sx0 = sourceRect.left(); const int sx1 = sourceRect.left() + sourceRect.width(); const int sy0 = sourceRect.top(); @@ -1348,6 +1372,8 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1, tx0, ty0, tx1, ty1, buffers, filter); + + ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW } QT_END_NAMESPACE diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json index bd46e07e54..14093ee471 100644 --- a/src/plugins/imageformats/ico/ico.json +++ b/src/plugins/imageformats/ico/ico.json @@ -1,4 +1,4 @@ { - "Keys": [ "ico" ], + "Keys": [ "ico", "cur" ], "MimeTypes": [ "image/vnd.microsoft.icon" ] } diff --git a/src/plugins/imageformats/ico/main.cpp b/src/plugins/imageformats/ico/main.cpp index 05e6e1885c..2ff2f36fdc 100644 --- a/src/plugins/imageformats/ico/main.cpp +++ b/src/plugins/imageformats/ico/main.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE QImageIOPlugin::Capabilities QICOPlugin::capabilities(QIODevice *device, const QByteArray &format) const { - if (format == "ico") + if (format == "ico" || format == "cur") return Capabilities(CanRead | CanWrite); if (!format.isEmpty()) return 0; diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 77bb727a51..b65bcdfacb 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -75,7 +75,7 @@ typedef struct typedef struct { quint16 idReserved; // Reserved - quint16 idType; // resource type (1 for icons) + quint16 idType; // resource type (1 for icons, 2 for cursors) quint16 idCount; // how many images? ICONDIRENTRY idEntries[1]; // the entries for each image } ICONDIR, *LPICONDIR; @@ -275,10 +275,10 @@ bool ICOReader::canRead(QIODevice *iodev) readBytes += ICONDIRENTRY_SIZE; // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file. if ( ikonDir.idReserved == 0 - && ikonDir.idType == 1 + && (ikonDir.idType == 1 || ikonDir.idType == 2) && ikonDir.idEntries[0].bReserved == 0 - && ikonDir.idEntries[0].wPlanes <= 1 - && ikonDir.idEntries[0].wBitCount <= 32 // Bits per pixel + && (ikonDir.idEntries[0].wPlanes <= 1 || ikonDir.idType == 2) + && (ikonDir.idEntries[0].wBitCount <= 32 || ikonDir.idType == 2) // Bits per pixel && ikonDir.idEntries[0].dwBytesInRes >= 40 // Must be over 40, since sizeof (infoheader) == 40 ) { isProbablyICO = true; @@ -339,7 +339,7 @@ bool ICOReader::readHeader() if (iod && !headerRead) { startpos = iod->pos(); if (readIconDir(iod, &iconDir)) { - if (iconDir.idReserved == 0 || iconDir.idType == 1) + if (iconDir.idReserved == 0 && (iconDir.idType == 1 || iconDir.idType == 2)) headerRead = true; } } diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h index 4c24e129c3..c51ebe879d 100644 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.h +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.h @@ -55,7 +55,7 @@ public: virtual QPaintDevice *paintDevice(); virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); virtual void resize(const QSize &size, const QRegion &staticContents); - const QImage image() { return m_image; } + QImage toImage() const { return m_image; } void setBackingStore(QWindow *window); protected: QImage m_image; diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 11472ce1da..e67a039ff4 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -323,7 +323,7 @@ void QAndroidPlatformScreen::doRedraw() QRect windowRect = targetRect.translated(-window->geometry().topLeft()); QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore(); if (backingStore) - compositePainter.drawImage(targetRect.topLeft(), backingStore->image(), windowRect); + compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect); } } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 72045a1bbb..ca660488b9 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -55,7 +55,7 @@ QCocoaAccessibility::~QCocoaAccessibility() void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: event->uniqueId()]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: event->uniqueId()]; if (!element) { qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element"; return; @@ -244,7 +244,7 @@ NSArray *unignoredChildren(QAccessibleInterface *interface) QAccessible::Id childId = QAccessible::uniqueId(child); //qDebug() << " kid: " << childId << child; - QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: childId]; + QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: childId]; if (element) [kids addObject: element]; else diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index babaab5ae2..ca34deceef 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -48,15 +48,15 @@ #import <qaccessible.h> -@class QCocoaAccessibleElement; +Q_FORWARD_DECLARE_OBJC_CLASS(QMacAccessibilityElement); -@interface QCocoaAccessibleElement : NSObject { +@interface QMacAccessibilityElement : NSObject { NSString *role; QAccessible::Id axid; } - (id)initWithId:(QAccessible::Id)anId; -+ (QCocoaAccessibleElement *)elementWithId:(QAccessible::Id)anId; ++ (QMacAccessibilityElement *)elementWithId:(QAccessible::Id)anId; @end diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 078dc67cad..b309df6242 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -48,7 +48,7 @@ #import <AppKit/NSAccessibility.h> -@implementation QCocoaAccessibleElement +@implementation QMacAccessibilityElement - (id)initWithId:(QAccessible::Id)anId { @@ -72,7 +72,7 @@ QAccessibleCache *cache = QAccessibleCache::instance(); - QCocoaAccessibleElement *element = cache->elementForId(anId); + QMacAccessibilityElement *element = cache->elementForId(anId); if (!element) { QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); Q_ASSERT(iface); @@ -95,8 +95,8 @@ } - (BOOL)isEqual:(id)object { - if ([object isKindOfClass:[QCocoaAccessibleElement class]]) { - QCocoaAccessibleElement *other = object; + if ([object isKindOfClass:[QMacAccessibilityElement class]]) { + QMacAccessibilityElement *other = object; return other->axid == axid; } else { return NO; @@ -196,7 +196,7 @@ } QAccessible::Id parentId = QAccessible::uniqueId(parent); - return [QCocoaAccessibleElement elementWithId: parentId]; + return [QMacAccessibilityElement elementWithId: parentId]; } @@ -345,7 +345,7 @@ } if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) { int index = [parameter intValue]; - NSNumber *ln = [QCocoaAccessibleElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; + NSNumber *ln = [QMacAccessibilityElement lineNumberForIndex: index forText: iface->text(QAccessible::Value)]; return ln; } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { @@ -504,7 +504,7 @@ QAccessible::Id childId = QAccessible::uniqueId(childInterface); // hit a child, forward to child accessible interface. - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childId]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId]; if (accessibleElement) return NSAccessibilityUnignoredAncestor(accessibleElement); return NSAccessibilityUnignoredAncestor(self); @@ -521,7 +521,7 @@ QAccessibleInterface *childInterface = iface->focusChild(); if (childInterface) { QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childAxid]; + QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid]; return NSAccessibilityUnignoredAncestor(accessibleElement); } diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index d18a01b11c..a02b074771 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -59,7 +59,7 @@ return nil; QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); - return [QCocoaAccessibleElement elementWithId: childId]; + return [QMacAccessibilityElement elementWithId: childId]; } // The QNSView is a container that the user does not interact directly with: diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index ffc4ff9b12..57d4ac1770 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -23,7 +23,9 @@ OBJECTIVE_SOURCES = \ qiostheme.mm \ qiosglobal.mm \ qiosservices.mm \ - qiosclipboard.mm + qiosclipboard.mm \ + quiaccessibilityelement.mm \ + qiosplatformaccessibility.mm \ HEADERS = \ qiosintegration.h \ @@ -40,7 +42,9 @@ HEADERS = \ qiosglobal.h \ qiosservices.h \ quiview.h \ - qiosclipboard.h + qiosclipboard.h \ + quiaccessibilityelement.h \ + qiosplatformaccessibility.h \ OTHER_FILES = \ quiview_textinput.mm diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h index 956c112399..733c8dc270 100644 --- a/src/plugins/platforms/ios/qiosintegration.h +++ b/src/plugins/platforms/ios/qiosintegration.h @@ -82,6 +82,8 @@ public: void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); QTouchDevice *touchDevice(); + QPlatformAccessibility *accessibility() const Q_DECL_OVERRIDE; + private: QPlatformFontDatabase *m_fontDatabase; QPlatformClipboard *m_clipboard; @@ -90,6 +92,7 @@ private: QTouchDevice *m_touchDevice; QIOSApplicationState m_applicationState; QIOSServices *m_platformServices; + mutable QPlatformAccessibility *m_accessibility; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 0fe7adff9f..3334e3a094 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -45,6 +45,7 @@ #include "qioswindow.h" #include "qiosbackingstore.h" #include "qiosscreen.h" +#include "qiosplatformaccessibility.h" #include "qioscontext.h" #include "qiosclipboard.h" #include "qiosinputcontext.h" @@ -67,6 +68,7 @@ QIOSIntegration::QIOSIntegration() , m_inputContext(new QIOSInputContext) , m_screen(new QIOSScreen(QIOSScreen::MainScreen)) , m_platformServices(new QIOSServices) + , m_accessibility(0) { if (![UIApplication sharedApplication]) { qWarning() @@ -106,6 +108,9 @@ QIOSIntegration::~QIOSIntegration() delete m_platformServices; m_platformServices = 0; + + delete m_accessibility; + m_accessibility = 0; } bool QIOSIntegration::hasCapability(Capability cap) const @@ -229,4 +234,11 @@ QTouchDevice *QIOSIntegration::touchDevice() return m_touchDevice; } +QPlatformAccessibility *QIOSIntegration::accessibility() const +{ + if (!m_accessibility) + m_accessibility = new QIOSPlatformAccessibility; + return m_accessibility; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.h b/src/plugins/platforms/ios/qiosplatformaccessibility.h new file mode 100644 index 0000000000..beb0d006e1 --- /dev/null +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QIOSPLATFORMACCESSIBILITY_H +#define QIOSPLATFORMACCESSIBILITY_H + +#include <qpa/qplatformaccessibility.h> + +QT_BEGIN_NAMESPACE + +class QIOSPlatformAccessibility: public QPlatformAccessibility +{ +public: + QIOSPlatformAccessibility(); + ~QIOSPlatformAccessibility(); + + virtual void notifyAccessibilityUpdate(QAccessibleEvent *event); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm new file mode 100644 index 0000000000..db579ba559 --- /dev/null +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiosplatformaccessibility.h" + +#include <QtGui/QtGui> +#include "qioswindow.h" + +QIOSPlatformAccessibility::QIOSPlatformAccessibility() +{} + +QIOSPlatformAccessibility::~QIOSPlatformAccessibility() +{} + + +void invalidateCache(QAccessibleInterface *iface) +{ + if (!iface || !iface->isValid()) { + qWarning() << "invalid accessible interface: " << iface; + return; + } + + QWindow *win = 0; + QAccessibleInterface *parent = iface; + do { + win = parent->window(); + parent = parent->parent(); + } while (!win && parent); + Q_ASSERT(win && win->handle()); + QIOSWindow *window = static_cast<QIOSWindow*>(win->handle()); + window->clearAccessibleCache(); +} + + +void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) +{ + switch (event->type()) { + case QAccessible::ObjectCreated: + case QAccessible::ObjectShow: + case QAccessible::ObjectHide: + case QAccessible::ObjectDestroyed: + invalidateCache(event->accessibleInterface()); + break; + default: + break; + } +} diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h index 6b6892e6e4..bcff3e202c 100644 --- a/src/plugins/platforms/ios/qioswindow.h +++ b/src/plugins/platforms/ios/qioswindow.h @@ -87,6 +87,8 @@ public: WId winId() const { return WId(m_view); }; + void clearAccessibleCache(); + private: void applicationStateChanged(Qt::ApplicationState state); void applyGeometry(const QRect &rect); diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 6f5c96cfc1..3ed2bbe1a1 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -52,6 +52,9 @@ #include <QtGui/private/qwindow_p.h> #include <qpa/qplatformintegration.h> +#include "qiosplatformaccessibility.h" +#import "quiaccessibilityelement.h" + #import <QuartzCore/CAEAGLLayer.h> #include <QtGui/QKeyEvent> @@ -82,9 +85,74 @@ if (self = [self initWithFrame:toCGRect(window->geometry())]) m_qioswindow = window; + m_accessibleElements = [[NSMutableArray alloc] init]; return self; } +- (void)createAccessibleElement:(QAccessibleInterface *)iface +{ + if (!iface || iface->state().invisible) + return; + QAccessible::Id accessibleId = QAccessible::uniqueId(iface); + UIAccessibilityElement *elem = [[QMacAccessibilityElement alloc] initWithId: accessibleId withAccessibilityContainer: self]; + [m_accessibleElements addObject: elem]; +} + +- (void)createAccessibleContainer:(QAccessibleInterface *)iface +{ + if (!iface) + return; + + if (iface->childCount() == 0) { + [self createAccessibleElement: iface]; + } else { + for (int i = 0; i < iface->childCount(); ++i) + [self createAccessibleContainer: iface->child(i)]; + } +} + +- (void)initAccessibility +{ + static bool init = false; + if (!init) + QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + init = true; + + if ([m_accessibleElements count]) + return; + + QWindow *win = m_qioswindow->window(); + QAccessibleInterface *iface = win->accessibleRoot(); + if (iface) + [self createAccessibleContainer: iface]; +} + +- (void)clearAccessibleCache +{ + [m_accessibleElements removeAllObjects]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @""); +} + +// this is a container, returning yes here means the functions below will never be called +- (BOOL)isAccessibilityElement { + return NO; +} + +- (NSInteger)accessibilityElementCount { + [self initAccessibility]; + return [m_accessibleElements count]; +} + +- (id)accessibilityElementAtIndex:(NSInteger)index { + [self initAccessibility]; + return m_accessibleElements[index]; +} + +- (NSInteger)indexOfAccessibilityElement:(id)element { + [self initAccessibility]; + return [m_accessibleElements indexOfObject:element]; +} + - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { @@ -634,6 +702,11 @@ qreal QIOSWindow::devicePixelRatio() const return m_view.contentScaleFactor; } +void QIOSWindow::clearAccessibleCache() +{ + [m_view clearAccessibleCache]; +} + #include "moc_qioswindow.cpp" QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h new file mode 100644 index 0000000000..7c5a930e86 --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUIACCESSIBILITYELEMENT_H +#define QUIACCESSIBILITYELEMENT_H + +#import <UIKit/UIKit.h> +#import <QtGui/QtGui> + +@interface QMacAccessibilityElement : UIAccessibilityElement +{} + +@property (readonly) QAccessible::Id axid; + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; ++ (QMacAccessibilityElement *) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; + +@end + +#endif diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm new file mode 100644 index 0000000000..c9e9e34cbd --- /dev/null +++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quiaccessibilityelement.h" + +#include "private/qaccessiblecache_p.h" + +@implementation QMacAccessibilityElement + +- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT((int)anId < 0); + self = [super initWithAccessibilityContainer: view]; + if (self) + _axid = anId; + + return self; +} + ++ (id) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +{ + Q_ASSERT(anId); + if (!anId) + return nil; + + QAccessibleCache *cache = QAccessibleCache::instance(); + + QMacAccessibilityElement *element = cache->elementForId(anId); + if (!element) { + QAccessibleInterface *iface = QAccessible::accessibleInterface(anId); + Q_ASSERT(iface); + element = [[self alloc] initWithId:anId withAccessibilityContainer: view]; + cache->insertElement(anId, element); + } + return element; +} + +- (void) invalidate +{ + [self release]; +} + +- (BOOL) isAccessibilityElement +{ + return YES; +} + +- (NSString*) accessibilityLabel +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + return iface->text(QAccessible::Name).toNSString(); +} + +- (NSString*) accessibilityHint +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + return iface->text(QAccessible::Description).toNSString(); +} + +- (NSString*) accessibilityValue +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return @""; + } + + QAccessible::State state = iface->state(); + + if (state.checkable) + return state.checked ? @"checked" : @"unchecked"; // FIXME: translation + + QAccessibleValueInterface *val = iface->valueInterface(); + if (val) { + return val->currentValue().toString().toNSString(); + } else if (QAccessibleTextInterface *text = iface->textInterface()) { + // FIXME doesn't work? + return text->text(0, text->characterCount() - 1).toNSString(); + } + + return [super accessibilityHint]; +} + +- (CGRect) accessibilityFrame +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return CGRect(); + } + + QRect rect = iface->rect(); + return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); +} + +- (UIAccessibilityTraits) accessibilityTraits +{ + UIAccessibilityTraits traits = UIAccessibilityTraitNone; + + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (!iface) { + qWarning() << "invalid accessible interface for: " << self.axid; + return traits; + } + QAccessible::State state = iface->state(); + if (state.disabled) + traits |= UIAccessibilityTraitNotEnabled; + + if (iface->role() == QAccessible::Button) + traits |= UIAccessibilityTraitButton; + + if (iface->valueInterface()) + traits |= UIAccessibilityTraitAdjustable; + + return traits; +} + +- (BOOL) accessibilityActivate +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) { + if (action->actionNames().contains(QAccessibleActionInterface::pressAction())) { + action->doAction(QAccessibleActionInterface::pressAction()); + return YES; + } else if (action->actionNames().contains(QAccessibleActionInterface::showMenuAction())) { + action->doAction(QAccessibleActionInterface::showMenuAction()); + return YES; + } + } + return NO; // fall back to sending mouse clicks +} + +- (void) accessibilityIncrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::increaseAction()); +} + +- (void) accessibilityDecrement +{ + QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); + if (QAccessibleActionInterface *action = iface->actionInterface()) + action->doAction(QAccessibleActionInterface::decreaseAction()); +} + +@end diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 575dedab89..91c4fc9dde 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -57,6 +57,8 @@ int m_nextTouchId; QString m_markedText; BOOL m_inSendEventToFocusObject; + + NSMutableArray *m_accessibleElements; } @property(nonatomic, assign) id<UITextInputDelegate> inputDelegate; diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp index 972c59ef2e..99833101d2 100644 --- a/src/tools/rcc/main.cpp +++ b/src/tools/rcc/main.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the tools applications of the Qt Toolkit. @@ -123,6 +123,11 @@ int runRcc(int argc, char *argv[]) outputOption.setValueName(QStringLiteral("file")); parser.addOption(outputOption); + QCommandLineOption tempOption(QStringList() << QStringLiteral("t") << QStringLiteral("temp")); + tempOption.setDescription(QStringLiteral("Use temporary <file> for big resources.")); + tempOption.setValueName(QStringLiteral("file")); + parser.addOption(tempOption); + QCommandLineOption nameOption(QStringLiteral("name"), QStringLiteral("Create an external initialization function with <name>."), QStringLiteral("name")); parser.addOption(nameOption); @@ -141,6 +146,9 @@ int runRcc(int argc, char *argv[]) QCommandLineOption binaryOption(QStringLiteral("binary"), QStringLiteral("Output a binary file for use as a dynamic resource.")); parser.addOption(binaryOption); + QCommandLineOption passOption(QStringLiteral("pass"), QStringLiteral("Pass number for big resources"), QStringLiteral("number")); + parser.addOption(passOption); + QCommandLineOption namespaceOption(QStringLiteral("namespace"), QStringLiteral("Turn off namespace macros.")); parser.addOption(namespaceOption); @@ -161,7 +169,6 @@ int runRcc(int argc, char *argv[]) QString errorMsg; RCCResourceLibrary library; - QString outFilename = parser.value(outputOption); if (parser.isSet(nameOption)) library.setInitName(parser.value(nameOption)); if (parser.isSet(rootOption)) { @@ -178,6 +185,14 @@ int runRcc(int argc, char *argv[]) library.setCompressThreshold(parser.value(thresholdOption).toInt()); if (parser.isSet(binaryOption)) library.setFormat(RCCResourceLibrary::Binary); + if (parser.isSet(passOption)) { + if (parser.value(passOption) == QStringLiteral("1")) + library.setFormat(RCCResourceLibrary::Pass1); + else if (parser.value(passOption) == QStringLiteral("2")) + library.setFormat(RCCResourceLibrary::Pass2); + else + errorMsg = QLatin1String("Pass number must be 1 or 2"); + } if (parser.isSet(namespaceOption)) library.setUseNameSpace(!library.useNameSpace()); if (parser.isSet(verboseOption)) @@ -194,6 +209,9 @@ int runRcc(int argc, char *argv[]) } } + QString outFilename = parser.value(outputOption); + QString tempFilename = parser.value(tempOption); + if (projectRequested) { return createProject(outFilename); } @@ -217,11 +235,21 @@ int runRcc(int argc, char *argv[]) if (!library.readFiles(list, errorDevice)) return 1; - // open output QFile out; - QIODevice::OpenMode mode = QIODevice::WriteOnly; - if (library.format() == RCCResourceLibrary::C_Code) - mode |= QIODevice::Text; + + // open output + QIODevice::OpenMode mode = QIODevice::NotOpen; + switch (library.format()) { + case RCCResourceLibrary::C_Code: + case RCCResourceLibrary::Pass1: + mode = QIODevice::WriteOnly | QIODevice::Text; + break; + case RCCResourceLibrary::Pass2: + case RCCResourceLibrary::Binary: + mode = QIODevice::WriteOnly; + break; + } + if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { // using this overload close() only flushes. @@ -245,7 +273,17 @@ int runRcc(int argc, char *argv[]) return 0; } - return library.output(out, errorDevice) ? 0 : 1; + QFile temp; + if (!tempFilename.isEmpty()) { + temp.setFileName(tempFilename); + if (!temp.open(QIODevice::ReadOnly)) { + const QString msg = QString::fromUtf8("Unable to open temporary file %1 for reading: %2\n") + .arg(outFilename).arg(out.errorString()); + errorDevice.write(msg.toUtf8()); + return 1; + } + } + return library.output(out, temp, errorDevice) ? 0 : 1; } Q_CORE_EXPORT extern QBasicAtomicInt qt_qhash_seed; // from qhash.cpp diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 0d0c4ea444..d460109a9b 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the tools applications of the Qt Toolkit. @@ -77,7 +77,11 @@ void RCCResourceLibrary::write(const char *str, int len) void RCCResourceLibrary::writeByteArray(const QByteArray &other) { - m_out.append(other); + if (m_format == Pass2) { + m_outDevice->write(other); + } else { + m_out.append(other); + } } static inline QString msgOpenReadFailed(const QString &fname, const QString &why) @@ -164,9 +168,10 @@ QString RCCFileInfo::resourceName() const void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) { - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); + const bool text = lib.m_format == RCCResourceLibrary::C_Code; + const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; //some info - if (text) { + if (text || pass1) { if (m_language != QLocale::C) { lib.writeString(" // "); lib.writeByteArray(resourceName().toLocal8Bit()); @@ -209,14 +214,17 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) //data offset lib.writeNumber4(m_dataOffset); } - if (text) + if (text || pass1) lib.writeChar('\n'); } qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage) { - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); + const bool text = lib.m_format == RCCResourceLibrary::C_Code; + const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; + const bool pass2 = lib.m_format == RCCResourceLibrary::Pass2; + const bool binary = lib.m_format == RCCResourceLibrary::Binary; //capture the offset m_dataOffset = offset; @@ -244,7 +252,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, #endif // QT_NO_COMPRESS // some info - if (text) { + if (text || pass1) { lib.writeString(" // "); lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit()); lib.writeString("\n "); @@ -252,8 +260,9 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, // write the length - lib.writeNumber4(data.size()); - if (text) + if (text || binary || pass2) + lib.writeNumber4(data.size()); + if (text || pass1) lib.writeString("\n "); offset += 4; @@ -267,27 +276,27 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, j = 16; } } - } else { - for (int i = data.size(); --i >= 0; ) - lib.writeChar(*p++); + } else if (binary || pass2) { + lib.writeByteArray(data); } offset += data.size(); // done - if (text) + if (text || pass1) lib.writeString("\n "); return offset; } qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) { - const bool text = (lib.m_format == RCCResourceLibrary::C_Code); + const bool text = lib.m_format == RCCResourceLibrary::C_Code; + const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; // capture the offset m_nameOffset = offset; // some info - if (text) { + if (text || pass1) { lib.writeString(" // "); lib.writeByteArray(m_name.toLocal8Bit()); lib.writeString("\n "); @@ -295,13 +304,13 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) // write the length lib.writeNumber2(m_name.length()); - if (text) + if (text || pass1) lib.writeString("\n "); offset += 2; // write the hash lib.writeNumber4(qt_hash(m_name)); - if (text) + if (text || pass1) lib.writeString("\n "); offset += 4; @@ -309,13 +318,13 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) const QChar *unicode = m_name.unicode(); for (int i = 0; i < m_name.length(); ++i) { lib.writeNumber2(unicode[i].unicode()); - if (text && i % 16 == 0) + if ((text || pass1) && i % 16 == 0) lib.writeString("\n "); } offset += m_name.length()*2; // done - if (text) + if (text || pass1) lib.writeString("\n "); return offset; } @@ -349,7 +358,8 @@ RCCResourceLibrary::RCCResourceLibrary() m_namesOffset(0), m_dataOffset(0), m_useNameSpace(CONSTANT_USENAMESPACE), - m_errorDevice(0) + m_errorDevice(0), + m_outDevice(0) { m_out.reserve(30 * 1000 * 1000); } @@ -717,9 +727,39 @@ RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap( return rc; } -bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice) +bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice) { m_errorDevice = &errorDevice; + + const char pattern[] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' }; + if (m_format == Pass2) { + char c; + for (int i = 0; i < 8; ) { + if (!tempDevice.getChar(&c)) { + m_errorDevice->write("No data signature found\n"); + return false; + } + if (c == pattern[i]) { + ++i; + } else { + for (int k = 0; k < i; ++k) + outDevice.putChar(pattern[k]); + outDevice.putChar(c); + i = 0; + } + } + + m_outDevice = &outDevice; + quint64 start = outDevice.pos(); + writeDataBlobs(); + quint64 len = outDevice.pos() - start; + + tempDevice.seek(tempDevice.pos() + len - 8); + outDevice.write(tempDevice.readAll()); + + return true; + } + //write out if (m_verbose) m_errorDevice->write("Outputting code\n"); @@ -776,7 +816,12 @@ void RCCResourceLibrary::writeNumber2(quint16 number) void RCCResourceLibrary::writeNumber4(quint32 number) { - if (m_format == RCCResourceLibrary::Binary) { + if (m_format == RCCResourceLibrary::Pass2) { + m_outDevice->putChar(char(number >> 24)); + m_outDevice->putChar(char(number >> 16)); + m_outDevice->putChar(char(number >> 8)); + m_outDevice->putChar(char(number)); + } else if (m_format == RCCResourceLibrary::Binary) { writeChar(number >> 24); writeChar(number >> 16); writeChar(number >> 8); @@ -791,7 +836,7 @@ void RCCResourceLibrary::writeNumber4(quint32 number) bool RCCResourceLibrary::writeHeader() { - if (m_format == C_Code) { + if (m_format == C_Code || m_format == Pass1) { writeString("/****************************************************************************\n"); writeString("** Resource object code\n"); writeString("**\n"); @@ -800,7 +845,6 @@ bool RCCResourceLibrary::writeHeader() writeString("\n**\n"); writeString("** WARNING! All changes made in this file will be lost!\n"); writeString( "*****************************************************************************/\n\n"); - writeString("#include <QtCore/qglobal.h>\n\n"); } else if (m_format == Binary) { writeString("qres"); writeNumber4(0); @@ -814,15 +858,16 @@ bool RCCResourceLibrary::writeHeader() bool RCCResourceLibrary::writeDataBlobs() { Q_ASSERT(m_errorDevice); - if (m_format == C_Code) + if (m_format == C_Code) { writeString("static const unsigned char qt_resource_data[] = {\n"); - else if (m_format == Binary) + } else if (m_format == Binary) { m_dataOffset = m_out.size(); - QStack<RCCFileInfo*> pending; + } if (!m_root) return false; + QStack<RCCFileInfo*> pending; pending.push(m_root); qint64 offset = 0; QString errorMessage; @@ -844,12 +889,17 @@ bool RCCResourceLibrary::writeDataBlobs() } if (m_format == C_Code) writeString("\n};\n\n"); + else if (m_format == Pass1) { + writeString("\nstatic const unsigned char qt_resource_data["); + writeByteArray(QByteArray::number(offset)); + writeString("] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' };\n\n"); + } return true; } bool RCCResourceLibrary::writeDataNames() { - if (m_format == C_Code) + if (m_format == C_Code || m_format == Pass1) writeString("static const unsigned char qt_resource_name[] = {\n"); else if (m_format == Binary) m_namesOffset = m_out.size(); @@ -877,7 +927,7 @@ bool RCCResourceLibrary::writeDataNames() } } } - if (m_format == C_Code) + if (m_format == C_Code || m_format == Pass1) writeString("\n};\n\n"); return true; } @@ -889,7 +939,7 @@ static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *righ bool RCCResourceLibrary::writeDataStructure() { - if (m_format == C_Code) + if (m_format == C_Code || m_format == Pass1) writeString("static const unsigned char qt_resource_struct[] = {\n"); else if (m_format == Binary) m_treeOffset = m_out.size(); @@ -936,7 +986,7 @@ bool RCCResourceLibrary::writeDataStructure() pending.push(child); } } - if (m_format == C_Code) + if (m_format == C_Code || m_format == Pass1) writeString("\n};\n\n"); return true; @@ -966,7 +1016,7 @@ void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name) bool RCCResourceLibrary::writeInitializer() { - if (m_format == C_Code) { + if (m_format == C_Code || m_format == Pass1) { //write("\nQT_BEGIN_NAMESPACE\n"); QString initNameStr = m_initName; if (!initNameStr.isEmpty()) { @@ -976,18 +1026,36 @@ bool RCCResourceLibrary::writeInitializer() QByteArray initName = initNameStr.toLatin1(); //init - if (m_useNameSpace) - writeString("QT_BEGIN_NAMESPACE\n\n"); + if (m_useNameSpace) { + writeString("#ifdef QT_NAMESPACE\n" + "# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name\n" + "# define QT_MANGLE_NAMESPACE0(x) x\n" + "# define QT_MANGLE_NAMESPACE1(a, b) a##_##b\n" + "# define QT_MANGLE_NAMESPACE2(a, b) QT_MANGLE_NAMESPACE1(a,b)\n" + "# define QT_MANGLE_NAMESPACE(name) QT_MANGLE_NAMESPACE2( \\\n" + " QT_MANGLE_NAMESPACE0(name), QT_MANGLE_NAMESPACE0(QT_NAMESPACE))\n" + "#else\n" + "# define QT_PREPEND_NAMESPACE(name) name\n" + "# define QT_MANGLE_NAMESPACE(name) name\n" + "#endif\n\n"); + + writeString("#ifdef QT_NAMESPACE\n" + "namespace QT_NAMESPACE {\n" + "#endif\n\n"); + } + if (m_root) { - writeString("extern Q_CORE_EXPORT bool qRegisterResourceData\n " + writeString("bool qRegisterResourceData" "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); - writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n " + writeString("bool qUnregisterResourceData" "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); } + if (m_useNameSpace) - writeString("QT_END_NAMESPACE\n\n\n"); + writeString("#ifdef QT_NAMESPACE\n}\n#endif\n\n"); + QByteArray initResources = "qInitResources"; initResources += initName; writeString("int "); @@ -1002,9 +1070,6 @@ bool RCCResourceLibrary::writeInitializer() } writeString(" return 1;\n"); writeString("}\n\n"); - writeString("Q_CONSTRUCTOR_FUNCTION("); - writeMangleNamespaceFunction(initResources); - writeString(")\n\n"); //cleanup QByteArray cleanResources = "qCleanupResources"; @@ -1020,9 +1085,15 @@ bool RCCResourceLibrary::writeInitializer() } writeString(" return 1;\n"); writeString("}\n\n"); - writeString("Q_DESTRUCTOR_FUNCTION("); - writeMangleNamespaceFunction(cleanResources); - writeString(")\n\n"); + + writeByteArray( + "namespace {\n" + " struct initializer {\n" + " initializer() { QT_MANGLE_NAMESPACE(" + initResources + ")(); }\n" + " ~initializer() { QT_MANGLE_NAMESPACE(" + cleanResources + ")(); }\n" + " } dummy;\n" + "}\n"); + } else if (m_format == Binary) { int i = 4; char *p = m_out.data(); diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h index 7e16fe038d..1b15c8bb87 100644 --- a/src/tools/rcc/rcc.h +++ b/src/tools/rcc/rcc.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the tools applications of the Qt Toolkit. @@ -64,11 +64,11 @@ public: RCCResourceLibrary(); ~RCCResourceLibrary(); - bool output(QIODevice &out, QIODevice &errorDevice); + bool output(QIODevice &outDevice, QIODevice &tempDevice, QIODevice &errorDevice); bool readFiles(bool ignoreErrors, QIODevice &errorDevice); - enum Format { Binary, C_Code }; + enum Format { Binary, C_Code, Pass1, Pass2 }; void setFormat(Format f) { m_format = f; } Format format() const { return m_format; } @@ -87,6 +87,9 @@ public: void setInitName(const QString &name) { m_initName = name; } QString initName() const { return m_initName; } + void setOutputName(const QString &name) { m_outputName = name; } + QString outputName() const { return m_outputName; } + void setCompressLevel(int c) { m_compressLevel = c; } int compressLevel() const { return m_compressLevel; } @@ -137,6 +140,7 @@ private: QStringList m_fileNames; QString m_resourceRoot; QString m_initName; + QString m_outputName; Format m_format; bool m_verbose; int m_compressLevel; @@ -147,6 +151,7 @@ private: bool m_useNameSpace; QStringList m_failedResources; QIODevice *m_errorDevice; + QIODevice *m_outDevice; QByteArray m_out; }; diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index a252428a81..2bf4c62593 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1821,8 +1821,15 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi return QModelIndex(); QModelIndex result = d->model->index(logicalRow, logicalColumn, d->root); - if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result)) + if (!d->isRowHidden(logicalRow) && !d->isColumnHidden(logicalColumn) && d->isIndexEnabled(result)) { + if (d->hasSpans()) { + QSpanCollection::Span span = d->span(result.row(), result.column()); + if (span.width() > 1 || span.height() > 1) { + result = d->model->sibling(span.top(), span.left(), result); + } + } return result; + } return QModelIndex(); } diff --git a/tests/auto/gui/image/qicoimageformat/icons/valid/yellow.cur b/tests/auto/gui/image/qicoimageformat/icons/valid/yellow.cur Binary files differnew file mode 100644 index 0000000000..0a649aa7f7 --- /dev/null +++ b/tests/auto/gui/image/qicoimageformat/icons/valid/yellow.cur diff --git a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp index cd9d4b448e..71adbabb84 100644 --- a/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp +++ b/tests/auto/gui/image/qicoimageformat/tst_qicoimageformat.cpp @@ -111,9 +111,17 @@ void tst_QIcoImageFormat::cleanupTestCase() void tst_QIcoImageFormat::format() { - QImageReader reader(m_IconPath + "/valid/35FLOPPY.ICO", "ico"); - QByteArray fmt = reader.format(); - QCOMPARE(const_cast<const char*>(fmt.data()), "ico" ); + { + QImageReader reader(m_IconPath + "/valid/35FLOPPY.ICO", "ico"); + QByteArray fmt = reader.format(); + QCOMPARE(const_cast<const char*>(fmt.data()), "ico" ); + } + + { + QImageReader reader(m_IconPath + "/valid/yellow.cur", "ico"); + QByteArray fmt = reader.format(); + QCOMPARE(const_cast<const char*>(fmt.data()), "ico" ); + } } void tst_QIcoImageFormat::canRead_data() @@ -133,6 +141,7 @@ void tst_QIcoImageFormat::canRead_data() QTest::newRow("103x16px, 24BPP") << "valid/trolltechlogo_tiny.ico" << 1; QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 1; QTest::newRow("PNG compression") << "valid/Qt.ico" << 1; + QTest::newRow("CUR file") << "valid/yellow.cur" << 1; } void tst_QIcoImageFormat::canRead() @@ -203,7 +212,7 @@ void tst_QIcoImageFormat::imageCount_data() QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << 0; QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; - + QTest::newRow("CUR file") << "valid/yellow.cur" << 1; } void tst_QIcoImageFormat::imageCount() @@ -231,6 +240,7 @@ void tst_QIcoImageFormat::jumpToNextImage_data() QTest::newRow("16px16c, 32px32c, 32px256c 2") << "valid/WORLDH.ico" << 3; QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; + QTest::newRow("CUR file") << "valid/yellow.cur" << 1; } void tst_QIcoImageFormat::jumpToNextImage() @@ -281,6 +291,7 @@ void tst_QIcoImageFormat::nextImageDelay_data() QTest::newRow("invalid floppy (first 8 bytes = 0xff)") << "invalid/35floppy.ico" << -1; QTest::newRow("includes 32BPP w/alpha") << "valid/semitransparent.ico" << 9; QTest::newRow("PNG compression") << "valid/Qt.ico" << 4; + QTest::newRow("CUR file") << "valid/yellow.cur" << 1; } void tst_QIcoImageFormat::nextImageDelay() diff --git a/tests/auto/tools/rcc/data/images/images.expected b/tests/auto/tools/rcc/data/images/images.expected index 9334443ccc..2577b6319b 100644 --- a/tests/auto/tools/rcc/data/images/images.expected +++ b/tests/auto/tools/rcc/data/images/images.expected @@ -1,13 +1,11 @@ /**************************************************************************** ** Resource object code ** -IGNORE: ** Created by: The Resource Compiler for Qt version 5.0.0 +IGNORE: ** Created by: The Resource Compiler for Qt version 5.3.1 ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ -#include <QtCore/qglobal.h> - static const unsigned char qt_resource_data[] = { IGNORE: // /dev/qt5/qtbase/tests/auto/tools/rcc/data/images/images/circle.png 0x0,0x0,0x0,0xa5, @@ -94,16 +92,29 @@ static const unsigned char qt_resource_struct[] = { }; -QT_BEGIN_NAMESPACE +#ifdef QT_NAMESPACE +# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name +# define QT_MANGLE_NAMESPACE0(x) x +# define QT_MANGLE_NAMESPACE1(a, b) a##_##b +# define QT_MANGLE_NAMESPACE2(a, b) QT_MANGLE_NAMESPACE1(a,b) +# define QT_MANGLE_NAMESPACE(name) QT_MANGLE_NAMESPACE2( \ + QT_MANGLE_NAMESPACE0(name), QT_MANGLE_NAMESPACE0(QT_NAMESPACE)) +#else +# define QT_PREPEND_NAMESPACE(name) name +# define QT_MANGLE_NAMESPACE(name) name +#endif -extern Q_CORE_EXPORT bool qRegisterResourceData - (int, const unsigned char *, const unsigned char *, const unsigned char *); +#ifdef QT_NAMESPACE +namespace QT_NAMESPACE { +#endif -extern Q_CORE_EXPORT bool qUnregisterResourceData - (int, const unsigned char *, const unsigned char *, const unsigned char *); +bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); -QT_END_NAMESPACE +bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); +#ifdef QT_NAMESPACE +} +#endif int QT_MANGLE_NAMESPACE(qInitResources)() { @@ -112,8 +123,6 @@ int QT_MANGLE_NAMESPACE(qInitResources)() return 1; } -Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources)) - int QT_MANGLE_NAMESPACE(qCleanupResources)() { QT_PREPEND_NAMESPACE(qUnregisterResourceData) @@ -121,5 +130,9 @@ int QT_MANGLE_NAMESPACE(qCleanupResources)() return 1; } -Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources)) - +namespace { + struct initializer { + initializer() { QT_MANGLE_NAMESPACE(qInitResources)(); } + ~initializer() { QT_MANGLE_NAMESPACE(qCleanupResources)(); } + } dummy; +} diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp index 38367fb4ee..33af273284 100644 --- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp +++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp @@ -178,6 +178,8 @@ private slots: void spansAfterColumnInsertion(); void spansAfterRowRemoval(); void spansAfterColumnRemoval(); + void editSpanFromDirections_data(); + void editSpanFromDirections(); void checkHeaderReset(); void checkHeaderMinSize(); @@ -1240,28 +1242,28 @@ void tst_QTableView::moveCursorStrikesBack_data() << IntList() << QRect(1, 2, 2, 3) << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext)) - << 2 << 2; + << 2 << 1; QTest::newRow("Span, anchor column disabled") << -1 << -1 << IntList() << (IntList() << 1) << QRect(1, 2, 2, 3) << 2 << 0 << (IntList() << int(QtTestTableView::MoveNext)) - << 2 << 2; + << 2 << 1; QTest::newRow("Span, anchor row hidden") << 2 << -1 << IntList() << IntList() << QRect(1, 2, 2, 3) << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown)) - << 3 << 2; + << 2 << 1; QTest::newRow("Span, anchor row disabled") << -1 << -1 << (IntList() << 2) << IntList() << QRect(1, 2, 2, 3) << 1 << 2 << (IntList() << int(QtTestTableView::MoveDown)) - << 3 << 2; + << 2 << 1; QTest::newRow("Move through span right") << -1 << -1 << IntList() @@ -3278,6 +3280,159 @@ void tst_QTableView::spansAfterColumnRemoval() VERIFY_SPANS_CONSISTENCY(&view); } +Q_DECLARE_METATYPE(Qt::Key) + +void tst_QTableView::editSpanFromDirections_data() +{ + QTest::addColumn<QList<Qt::Key> >("keyPresses"); + QTest::addColumn<QSharedPointer<QStandardItemModel> >("model"); + QTest::addColumn<int>("row"); + QTest::addColumn<int>("column"); + QTest::addColumn<int>("rowSpan"); + QTest::addColumn<int>("columnSpan"); + QTest::addColumn<QModelIndex>("expectedVisualCursorIndex"); + QTest::addColumn<QModelIndex>("expectedEditedIndex"); + + /* x = the cell that should be edited + c = the cell that should actually be the current index + +---+---+ + | | | + +---+---+ + | | x | + +---+ + + | | c | + +---+---+ + | | ^ | + +---+---+ */ + QList<Qt::Key> keyPresses; + keyPresses << Qt::Key_Right << Qt::Key_PageDown << Qt::Key_Up; + QSharedPointer<QStandardItemModel> model(new QStandardItemModel(4, 2)); + QTest::newRow("row span, bottom up") + << keyPresses << model << 1 << 1 << 2 << 1 << model->index(2, 1) << model->index(1, 1); + + /* +---+---+ + | | v | + +---+---+ + | |x,c| + +---+ + + | | | + +---+---+ + | | | + +---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_Right << Qt::Key_Down; + model.reset(new QStandardItemModel(4, 2)); + QTest::newRow("row span, top down") + << keyPresses << model << 1 << 1 << 2 << 1 << model->index(1, 1) << model->index(1, 1); + + /* +---+---+---+ + | | | | + +---+---+---+ + | |x,c| < | + +---+ +---+ + | | | | + +---+---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_End << Qt::Key_Down << Qt::Key_Left; + model.reset(new QStandardItemModel(3, 3)); + QTest::newRow("row span, right to left") + << keyPresses << model << 1 << 1 << 2 << 1 << model->index(1, 1) << model->index(1, 1); + + /* +---+---+---+ + | | | | + +---+---+---+ + | | x | | + +---+ +---+ + | > | c | | + +---+---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_PageDown << Qt::Key_Right; + model.reset(new QStandardItemModel(3, 3)); + QTest::newRow("row span, left to right") + << keyPresses << model << 1 << 1 << 2 << 1 << model->index(2, 1) << model->index(1, 1); + + /* +---+---+---+ + | | | | + +---+---+---+ + |x,c | + +---+---+---+ + | ^ | | | + +---+---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_PageDown << Qt::Key_Up; + model.reset(new QStandardItemModel(3, 3)); + QTest::newRow("col span, bottom up") + << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 0) << model->index(1, 0); + + /* +---+---+---+ + | | | | + +---+---+---+ + | x c | + +---+---+---+ + | | ^ | | + +---+---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_PageDown << Qt::Key_Right << Qt::Key_Up; + model.reset(new QStandardItemModel(3, 3)); + QTest::newRow("col span, bottom up #2") + << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 1) << model->index(1, 0); + + /* +---+---+---+ + | | | v | + +---+---+---+ + | x c | + +---+---+---+ + | | | | + +---+---+---+ */ + keyPresses.clear(); + keyPresses << Qt::Key_End << Qt::Key_Down; + model.reset(new QStandardItemModel(3, 3)); + QTest::newRow("col span, top down") + << keyPresses << model << 1 << 0 << 1 << 3 << model->index(1, 2) << model->index(1, 0); +} + +class TableViewWithCursorExposed : public QTableView +{ +public: + TableViewWithCursorExposed() : + QTableView() { + } + +public: + QModelIndex visualCursorIndex() { + QTableViewPrivate *d = static_cast<QTableViewPrivate*>(qt_widget_private(this)); + return d->model->index(d->visualCursor.y(), d->visualCursor.x()); + } +}; + +void tst_QTableView::editSpanFromDirections() +{ + QFETCH(QList<Qt::Key>, keyPresses); + QFETCH(QSharedPointer<QStandardItemModel>, model); + QFETCH(int, row); + QFETCH(int, column); + QFETCH(int, rowSpan); + QFETCH(int, columnSpan); + QFETCH(QModelIndex, expectedVisualCursorIndex); + QFETCH(QModelIndex, expectedEditedIndex); + + TableViewWithCursorExposed view; + view.setModel(model.data()); + view.setSpan(row, column, rowSpan, columnSpan); + view.show(); + QVERIFY(QTest::qWaitForWindowActive(&view)); + + foreach (Qt::Key key, keyPresses) { + QTest::keyClick(&view, key); + } + QCOMPARE(view.visualCursorIndex(), expectedVisualCursorIndex); + QCOMPARE(view.selectionModel()->currentIndex(), expectedEditedIndex); + + QTest::keyClick(&view, Qt::Key_X); + QTest::keyClick(QApplication::focusWidget(), Qt::Key_Enter); + QTRY_COMPARE(view.model()->data(expectedEditedIndex).toString(), QLatin1String("x")); +} + class Model : public QAbstractTableModel { Q_OBJECT diff --git a/tests/manual/widgets/itemviews/itemviews.pro b/tests/manual/widgets/itemviews/itemviews.pro index 6b91531a87..53f658d54d 100644 --- a/tests/manual/widgets/itemviews/itemviews.pro +++ b/tests/manual/widgets/itemviews/itemviews.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = delegate qheaderview qtreeview qtreewidget +SUBDIRS = delegate qheaderview qtreeview qtreewidget tableview-span-navigation diff --git a/tests/manual/widgets/itemviews/tableview-span-navigation/main.cpp b/tests/manual/widgets/itemviews/tableview-span-navigation/main.cpp new file mode 100644 index 0000000000..8421d0661b --- /dev/null +++ b/tests/manual/widgets/itemviews/tableview-span-navigation/main.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly <stephen.kelly@kdab.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include <QStandardItemModel> +#include <QTableView> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QStandardItemModel model(4, 4); + QTableView tableView; + tableView.setSizeAdjustPolicy(QTableView::AdjustToContents); + tableView.setModel(&model); + + for (int row = 0; row < model.rowCount(); ++row) { + for (int column = 0; column < model.columnCount(); ++column) { + QModelIndex index = model.index(row, column, QModelIndex()); + model.setData(index, QVariant(QString("%1,%2").arg(row).arg(column))); + } + } + + tableView.setSpan(1, 1, 2, 2); + + tableView.show(); + + return app.exec(); +} diff --git a/tests/manual/widgets/itemviews/tableview-span-navigation/tableview-span-navigation.pro b/tests/manual/widgets/itemviews/tableview-span-navigation/tableview-span-navigation.pro new file mode 100644 index 0000000000..ffa006a2d8 --- /dev/null +++ b/tests/manual/widgets/itemviews/tableview-span-navigation/tableview-span-navigation.pro @@ -0,0 +1,8 @@ + +TEMPLATE = app +TARGET = tableview-span-navigation +INCLUDEPATH += . + +QT += widgets + +SOURCES += main.cpp |