diff --git a/dist/changes-5.1.1 b/dist/changes-5.1.1 new file mode 100644 index 0000000000..85309074ed --- /dev/null +++ b/dist/changes-5.1.1 @@ -0,0 +1,206 @@ +Qt 5.1.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.1.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://qt-project.org/doc/qt-5.1/ + +The Qt version 5.1 series is binary compatible with the 5.0.x series. +Applications compiled for 5.0 will continue to run with 5.1. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt-project.org/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + + +**************************************************************************** +* General * +**************************************************************************** + + - Add support for Visual Studio 2013 + - Remove obsolete 'register' C keyword + - Speed up font database loading with fontconfig + - [QTBUG-32284] Fix incomplete override of QIODevice::open in QProcess and QLocalSocket + +**************************************************************************** +* Library * +**************************************************************************** + +QtCore +------ + + - Add basic conversion functions from QVariant(QJsonValue) + - Fix crash when re-creating QThreadData after initially destroying it + - Fix the host_bins variable in the QtCore pkg-config file + - QUrl stringprep: fix handling of U+0080: it's prohibited + - QUrl stringprep: avoid recalculating the surrogates we already know + - QUrl stringprep: fix handling of prohibited characters + - QUrl stringprep: fix case folding from non-BMP to BMP + - QUrl stringprep: recalculate the current position if the size changes + - [QTBUG-24345] Prevent negative size in QBitArray, QVector and QVarLengthArray ctors + - [QTBUG-25732] Mention QRect's int min/max constraints in detailed description + - [QTBUG-29391] fix infinite loop in QProcessPrivate::drainOutputPipes + - [QTBUG-29391] QWinOverlappedIoNotifier: fix race condition + - [QTBUG-31341] Fix watch of files/folders with special characters + - [QTBUG-31606] Fix dead lock in the Qt event handling + - [QTBUG-31926] Fix the number precision in QJsonDocument.toJson() again + - [QTBUG-32100] Remove default argument from declarations of qHash as friend + - [QTBUG-32314] QDir::mkpath shouldn't fail if parent directory denies access + - [QTBUG-32354] fix endless loop in QProcess/Win drainOutputPipes + - [QTBUG-32500] Ensure that the user codecs are listed in QTextCodec::availableCodecs + +QtDBus +------ + + - [QTBUG-27973] Fix disconnectFrom{Peer,Bus} when the connection failed + - [QTBUG-31932] Don't crash if the relayed signal was emitted from the wrong thread + - [QTBUG-32374] Fix QDBusAbstractInterface::isValid() for peer connections + +QtGui +----- + + - Restore smooth-scaled drawing of 0.5x-2.0x scaled glyphs in the GL engine + - QIcon: Avoid fetching twice the same pixmap + - Fix FBO restoring in QOpenGLTextureGlyphCache + - [QTBUG-28284] Set projection matrix for systems with OpenGL 3.1 + - [QTBUG-31443] QPdfWriter: Fix setting of paper size + - [QTBUG-32193] REG: Fix crash when mixing projected/unprojected text painting + - [QTBUG-32433] Detect popup window correctly in modal window blocked handling + +QtNetwork +--------- + + - Correct algorithm for digest auth when using the CONNECT verb + - Add reconnect attempts in more cases in QHttpNetworkConnectionChannel + - [QTBUG-32404] HTTP internals: do not access reply that was deleted already + - [QTBUG-32534] QHttpMultiPart: fix data corruption in readData method + +QtPrintSupport +-------------- + + - [QTBUG-31790] Initialize UI of widget-based dialog. + +QtWidgets +--------- + + - Display sizegrip on QMdiSubWindows, even on OS X 10.7 and later + - Check if widget inherits from QTextEdit when drawing the frame + - Fix QWidget::isActiveWindow for window containers + - Hide placeholder text when QLineEdit has preedit text + - [QTBUG-19036] Make *ItemBoundingRect modes work with custom shapes. + - [QTBUG-29945] Fix dropshadow and blur graphics effects + - [QTBUG-31044] QDockWidget: Keep position when undocking + - [QTBUG-31569] If a QWidget is ignored for auto-quit, ignore its corresponding QWindow + - [QTBUG-31664] Recognize separator item in QMenu + - [QTBUG-31904] Fix rotation of text in vertical QDockWidget titlebars in QFusionStyle + - [QTBUG-32054] Set correct cell when selecting custom color cell with arrow keys + - [QTBUG-32061] Fix the cursor position of an empty QLineEdit with a placeholder text + - [QTBUG-32177] Search toplevel when setting the active window from focus window + - [QTBUG-32260] Consider virtual screen when determining dock widget visibility + + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Qt for Linux +------------ + + - XCB: Don't use Xlib's XBell() function + - XCB: Append 0-character to atom name string + - Resolve modifier mask conflicts on X11 + - Fix system tray icon on X11 + - [QTBUG-31418] Fix for when we don't have XSettings + - [QTBUG-32274] Fix handling of non-latin1 shortcuts + +Qt for Mac +---------- + + - Disable window restoration for the Mac font panel + - Simplify qt_mac_cgimage_to_nsimage code + - QMacStyle: fix auto-default button animation + - Make the macx-xcode spec a wrapper around the default spec + - Scope cached Mac SDK tool values by mkspec + - Further followup to Q_OS_MACX changes + - Fix QSpinBox clipping issue on Mac when frame=false + - QMacStyle: enable scroll style changes for non-QScrollBars + - Support Mac key equivalent Cmd+Period + - Re-establish platform menu QObject hierarchy + - [QTBUG-28336] Fixed broken prl files in debug-and-release framework builds of qt + - [QTBUG-31477] Let Cocoa pick the right pixmap for menu item icons + - [QTBUG-31532] Don't update the menubar when popups are shown + - [QTBUG-31619] Cocoa save file dialog behavior fix + - [QTBUG-31819] Fix shared color panel usage + - [QTBUG-31562] Fix for OS X QFileDialog showing bundle as directory + - [QTBUG-32440] Avoid a potential crash in unignoredChildren + - [QTBUG-32831] Don't release the printer after using it to change a property + +Qt for Windows +-------------- + + - Clear window under mouse in destruction of platform window + - Prevent activation of windows with Qt::WindowDoesNotAcceptFocus + - Better errorhandling for the fontengine on WINCE + - Windows: Synthesize expose event for shrinking windows + - Windows font database: Resolve aliases for extra fonts + - Bugfix QDesktopServices on Windows + - ActiveQt: Pass native parent handle property from widget to widget window + - REG: Fix character size when exporting PDF on Windows + - Fix crash caused by ~QWindowsWindow flushing the event queue + - Show native file dialog on Windows XP Professional x64 Edition + - Fix detection of synthesized mouse events for MSVC / 64bit + - Display a message box if platform plugin cannot be found + - Fix auto-enabling of windows style + - Fixes QKeyEvent::count() on Windows + +Qt for BlackBerry +----------------- + + - Disable xkbcommon when building for QNX from Windows + - [QTBUG-32385] Handle Qt::WindowDoesNotAcceptFocus correctly + +Qt for Android +-------------- + + - Get SSL root certificates from TrustManager + - Adjust to new SDK layout on Windows + - Make PCRE's JIT work on Android devices + +Qt for iOS +---------- + + - iOS: Make sure we're deleting framebuffers in the right context + +**************************************************************************** +* Tools * +**************************************************************************** + +- configure + + * [QTBUG-5366] Complain about bad arguments to -make/-nomake + * [QTBUG-21778] Catch accidental use of -no-make + * [QTBUG-28763] Don't enable EGL support if OpenGL is disabled + +- cmake config files + + * Use absolute path in the /usr move workaround if -libdir is specified + * Always use forward slashes in paths passed to cmake + * Make clients use the QT_NO_DEBUG flag when using QtCore in release mode + * [QTBUG-32134] Add path to the headers in frameworks to the include dirs + * [QTBUG-32466] Don't check for the existence of private include directories + +- qmake + + * [QTBUG-5301] basic manifest tool support in vc(x)proj generator + * [QTBUG-19352] Resolve output of .depend_command relative to $$OUT_PWD + * [QTBUG-29826] Only add the res_file to the generated files if there is no rc_file + * [QTBUG-29988] VPATH resolution: don't crash when $(FOO) expands to nothing + * [QTBUG-30993] Changed project dependencies for solution files + * [QTBUG-31877] Make $$list() more backwards-compatible regarding backslashes + * [QTBUG-31975] MANIFEST:NO is not written to vcproj + * [QTBUG-32326] Escape paths coming from prl files diff --git a/examples/widgets/richtext/textedit/textedit.cpp b/examples/widgets/richtext/textedit/textedit.cpp index ae2bdedf13..873a29eb0e 100644 --- a/examples/widgets/richtext/textedit/textedit.cpp +++ b/examples/widgets/richtext/textedit/textedit.cpp @@ -436,8 +436,7 @@ bool TextEdit::maybeSave() { if (!textEdit->document()->isModified()) return true; - if (fileName.startsWith(QLatin1String(":/"))) - return true; + QMessageBox::StandardButton ret; ret = QMessageBox::warning(this, tr("Application"), tr("The document has been modified.\n" @@ -485,6 +484,8 @@ bool TextEdit::fileSave() { if (fileName.isEmpty()) return fileSaveAs(); + if (fileName.startsWith(QStringLiteral(":/"))) + return fileSaveAs(); QTextDocumentWriter writer(fileName); bool success = writer.write(textEdit->document()); diff --git a/mkspecs/android-g++/qmake.conf b/mkspecs/android-g++/qmake.conf index 8c0e8c91f6..4ff5341837 100644 --- a/mkspecs/android-g++/qmake.conf +++ b/mkspecs/android-g++/qmake.conf @@ -37,7 +37,6 @@ contains(QMAKE_HOST.os,Windows) { NDK_ROOT = $$(ANDROID_NDK_ROOT) !exists($$NDK_ROOT) { NDK_ROOT = $$DEFAULT_ANDROID_NDK_ROOT - !exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") } NDK_HOST = $$(ANDROID_NDK_HOST) @@ -187,4 +186,6 @@ QMAKE_LIBS_OPENGL = QMAKE_LIBS_OPENGL_ES1 = -lGLESv1_CM QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 +!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.") + load(qt_config) diff --git a/mkspecs/features/create_cmake.prf b/mkspecs/features/create_cmake.prf index 04ec747307..5bc7cc81b1 100644 --- a/mkspecs/features/create_cmake.prf +++ b/mkspecs/features/create_cmake.prf @@ -24,6 +24,19 @@ load(cmake_functions) CMAKE_INSTALL_LIBS_DIR = $$cmakeTargetPath($$[QT_INSTALL_LIBS]) contains(CMAKE_INSTALL_LIBS_DIR, ^(/usr)?/lib(64)?.*): CMAKE_USR_MOVE_WORKAROUND = $$CMAKE_INSTALL_LIBS_DIR +CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE}) + +split_incpath { + CMAKE_ADD_SOURCE_INCLUDE_DIRS = true + CMAKE_NO_PRIVATE_INCLUDES = true # Don't add private includes in the build dir which don't exist + CMAKE_SOURCE_INCLUDES = \ + $$cmakeTargetPath($$QT_MODULE_INCLUDE_BASE) \ + $$cmakeTargetPath($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}) + CMAKE_SOURCE_PRIVATE_INCLUDES = \ + $$cmakeTargetPath($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION)) \ + $$cmakeTargetPath($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION)/Qt$${CMAKE_MODULE_NAME}) +} + CMAKE_INCLUDE_DIR = $$cmakeRelativePath($$[QT_INSTALL_HEADERS], $$[QT_INSTALL_PREFIX]) contains(CMAKE_INCLUDE_DIR, "^\\.\\./.*") { CMAKE_INCLUDE_DIR = $$[QT_INSTALL_HEADERS]/ @@ -37,10 +50,10 @@ contains(CMAKE_LIB_DIR,"^\\.\\./.*") { CMAKE_LIB_DIR = $$[QT_INSTALL_LIBS]/ CMAKE_LIB_DIR_IS_ABSOLUTE = True } else { - CMAKE_RELATIVE_INSTALL_DIR = $$cmakeRelativePath($$[QT_INSTALL_PREFIX], $$[QT_INSTALL_LIBS]) + CMAKE_RELATIVE_INSTALL_LIBS_DIR = $$cmakeRelativePath($$[QT_INSTALL_PREFIX], $$[QT_INSTALL_LIBS]) # We need to go up another two levels because the CMake files are # installed in $${CMAKE_LIB_DIR}/cmake/Qt5$${CMAKE_MODULE_NAME} - CMAKE_RELATIVE_INSTALL_DIR = "$${CMAKE_RELATIVE_INSTALL_DIR}../../" + CMAKE_RELATIVE_INSTALL_DIR = "$${CMAKE_RELATIVE_INSTALL_LIBS_DIR}../../" } CMAKE_BIN_DIR = $$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX]) @@ -135,8 +148,6 @@ unix:contains(QT_CONFIG, reduce_relocations):CMAKE_ADD_FPIE_FLAGS = "true" CMAKE_MKSPEC = $$[QMAKE_XSPEC] -CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE}) - CMAKE_MODULE_DEPS = $$cmakeModuleList($$sort_depends(QT.$${MODULE}.depends, QT.)) CMAKE_PARTIAL_MODULE_DEPS = $$replace(CMAKE_MODULE_DEPS, ";", ";Qt5::") !isEmpty(CMAKE_PARTIAL_MODULE_DEPS):CMAKE_QT5_MODULE_DEPS = "Qt5::$${CMAKE_PARTIAL_MODULE_DEPS}" diff --git a/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in b/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in index 9ac5c0282e..245c0ae768 100644 --- a/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in +++ b/mkspecs/features/data/cmake/Qt5BasicConfig.cmake.in @@ -13,7 +13,7 @@ get_filename_component(_IMPORT_PREFIX \"${CMAKE_CURRENT_LIST_FILE}\" PATH) get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH) get_filename_component(_realOrig \"$$CMAKE_INSTALL_LIBS_DIR/cmake/Qt5$${CMAKE_MODULE_NAME}\" REALPATH) if(_realCurr STREQUAL _realOrig) - get_filename_component(_qt5$${CMAKE_MODULE_NAME}_install_prefix \"$$CMAKE_INSTALL_LIBS_DIR\" PATH) + get_filename_component(_qt5$${CMAKE_MODULE_NAME}_install_prefix \"$$CMAKE_INSTALL_LIBS_DIR/$${CMAKE_RELATIVE_INSTALL_LIBS_DIR}\" ABSOLUTE) else() get_filename_component(_qt5$${CMAKE_MODULE_NAME}_install_prefix \"${CMAKE_CURRENT_LIST_DIR}/$${CMAKE_RELATIVE_INSTALL_DIR}\" ABSOLUTE) endif() @@ -120,6 +120,14 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME}) !!ENDIF !!ENDIF !!ENDIF +!!IF !isEmpty(CMAKE_ADD_SOURCE_INCLUDE_DIRS) + list(APPEND _Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS + $$CMAKE_SOURCE_INCLUDES + ) + set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS + $$CMAKE_SOURCE_PRIVATE_INCLUDES + ) +!!ENDIF !!ELSE set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS) set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index c8d151ce4d..7bedf6f760 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -205,6 +205,7 @@ defineTest(qtPrepareTool) { } } } + QT_TOOL_ENV += $$eval(QT_TOOL.$${2}.envvars) !isEmpty(3) { $$1$$3 = $$system_path($$eval($$1)) qtAddTargetEnv($$1$$3, QT_TOOL.$${2}.depends, system) diff --git a/mkspecs/features/qt_tool.prf b/mkspecs/features/qt_tool.prf index 9a6b9634e0..f0f0fe567b 100644 --- a/mkspecs/features/qt_tool.prf +++ b/mkspecs/features/qt_tool.prf @@ -27,9 +27,28 @@ CONFIG += console TOOL_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_tool_$${MODULE}.pri + vars = binary depends + !isEmpty(QT_TOOL_ENV) { + vars += envvars + module_var_names = + module_var_sets = + for(var, QT_TOOL_ENV) { + vars += env.$${var}.name env.$${var}.value + module_var_names += QT_TOOL.$${MODULE}.env.$${var} + module_var_sets += \ + "QT_TOOL.$${MODULE}.env.$${var}.name = $$val_escape($${var}.name)" \ + "QT_TOOL.$${MODULE}.env.$${var}.value = $$val_escape($${var}.value)" + } + module_envvars = \ + "QT_TOOL.$${MODULE}.envvars = $$module_var_names" \ + $$module_var_sets + } else { + module_envvars = + } TOOL_PRI_CONT = \ "QT_TOOL.$${MODULE}.binary = $$QMAKE_RESOLVED_TARGET" \ - "QT_TOOL.$${MODULE}.depends =$$join(MODULE_DEPENDS, " ", " ")" + "QT_TOOL.$${MODULE}.depends =$$join(MODULE_DEPENDS, " ", " ")" \ + $$module_envvars write_file($$TOOL_PRI, TOOL_PRI_CONT)|error("Aborting.") # Then, inject the new tool into the current cache state @@ -39,7 +58,7 @@ CONFIG += console unset(added) } include($$TOOL_PRI) - for(var, $$list(binary depends)): \ + for(var, vars): \ cache(QT_TOOL.$${MODULE}.$$var, transient) } diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 03eb3115f6..74f8db0012 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -4006,8 +4006,10 @@ include the precompiled header file in \c HEADERS, as qmake will do this if the configuration supports precompiled headers. - All platforms that support precompiled headers have the configuration - option \c precompile_header set. Using this option, you may trigger + The MSVC and g++ specs targeting Windows (and Windows CE) enable + \c precompile_header by default. + + Using this option, you may trigger conditional blocks in your project file to add settings when using precompiled headers. For example: diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index a8ae84a4e2..766904cd60 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2202,6 +2202,24 @@ MakefileGenerator::writeExtraVariables(QTextStream &t) } } +bool +MakefileGenerator::writeDummyMakefile(QTextStream &t) +{ + if (project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) + return false; + t << "QMAKE = " << var("QMAKE_QMAKE") << endl; + const ProStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); + for (ProStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it) + t << *it << " "; + t << "first all clean install distclean uninstall qmake_all:\n\t" + << "@echo \"Some of the required modules (" + << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"\n\t" + << "@echo \"Skipped.\"\n\n"; + writeMakeQmake(t); + t << "FORCE:\n\n"; + return true; +} + bool MakefileGenerator::writeStubMakefile(QTextStream &t) { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 47acc8098f..09327c599c 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -104,6 +104,7 @@ protected: void writeExtraTargets(QTextStream &t); void writeExtraCompilerTargets(QTextStream &t); void writeExtraCompilerVariables(QTextStream &t); + bool writeDummyMakefile(QTextStream &t); virtual bool writeStubMakefile(QTextStream &t); virtual bool writeMakefile(QTextStream &t); diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index cd6f441472..2373059f79 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -80,19 +80,8 @@ UnixMakefileGenerator::writeMakefile(QTextStream &t) { writeHeader(t); - if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) { - t << "QMAKE = " << var("QMAKE_QMAKE") << endl; - const ProStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); - for (ProStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it) - t << *it << " "; - t << "first all clean install distclean uninstall qmake_all:\n\t" - << "@echo \"Some of the required modules (" - << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"\n\t" - << "@echo \"Skipped.\"\n\n"; - writeMakeQmake(t); - t << "FORCE:\n\n"; + if (writeDummyMakefile(t)) return true; - } if (project->values("TEMPLATE").first() == "app" || project->values("TEMPLATE").first() == "lib" || diff --git a/qmake/generators/win32/mingw_make.cpp b/qmake/generators/win32/mingw_make.cpp index 38e6c56bb5..29b27cb7d7 100644 --- a/qmake/generators/win32/mingw_make.cpp +++ b/qmake/generators/win32/mingw_make.cpp @@ -114,14 +114,8 @@ bool MingwMakefileGenerator::findLibraries() bool MingwMakefileGenerator::writeMakefile(QTextStream &t) { writeHeader(t); - if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) { - t << "all clean:\n\t" - << "@echo \"Some of the required modules (" - << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"\n\t" - << "@echo \"Skipped.\"\n\n"; - writeMakeQmake(t); + if (writeDummyMakefile(t)) return true; - } if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib" || diff --git a/qmake/generators/win32/msvc_nmake.cpp b/qmake/generators/win32/msvc_nmake.cpp index 8af80e572e..f7b85d3621 100644 --- a/qmake/generators/win32/msvc_nmake.cpp +++ b/qmake/generators/win32/msvc_nmake.cpp @@ -58,17 +58,8 @@ bool NmakeMakefileGenerator::writeMakefile(QTextStream &t) { writeHeader(t); - if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) { - const ProStringList &qut = project->values("QMAKE_EXTRA_TARGETS"); - for (ProStringList::ConstIterator it = qut.begin(); it != qut.end(); ++it) - t << *it << " "; - t << "all first clean:\n\t" - << "@echo \"Some of the required modules (" - << var("QMAKE_FAILED_REQUIREMENTS") << ") are not available.\"\n\t" - << "@echo \"Skipped.\"\n\n"; - writeMakeQmake(t); + if (writeDummyMakefile(t)) return true; - } if(project->first("TEMPLATE") == "app" || project->first("TEMPLATE") == "lib" || diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 8c25ab6f9b..d6d40bcc68 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2311,7 +2311,7 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) inputs += Option::fixPathToTargetOS(file, false); } } - deps += inputs; // input files themselves too.. + deps = inputs + deps; // input files themselves too.. // Replace variables for command w/all input files // ### join gives path issues with directories containing spaces! @@ -2319,7 +2319,7 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) inputs.join(' '), out); } else { - deps += inFile; // input file itself too.. + deps.prepend(inFile); // input file itself too.. cmd = Project->replaceExtraCompilerVariables(tmp_cmd, inFile, out); @@ -2356,14 +2356,14 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) deps += CustomBuildTool.AdditionalDependencies; // Make sure that all deps are only once - QHash uniqDeps; + QStringList uniqDeps; for (int c = 0; c < deps.count(); ++c) { QString aDep = deps.at(c).trimmed(); if (!aDep.isEmpty()) - uniqDeps[aDep] = false; + uniqDeps << aDep; } - CustomBuildTool.AdditionalDependencies = uniqDeps.keys(); - CustomBuildTool.AdditionalDependencies.sort(); + uniqDeps.removeDuplicates(); + CustomBuildTool.AdditionalDependencies = uniqDeps; } // Ensure that none of the output files are also dependencies. Or else, the custom buildstep diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index e8904b0ab7..57231b57a9 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -573,9 +573,12 @@ typedef enum { Q_FileIdInfo = 18 } Q_FILE_INFO_BY_HANDLE_CLASS; # if defined(Q_CC_MINGW) || (defined(Q_CC_MSVC) && _MSC_VER < 1700) +// MinGW-64 defines FILE_ID_128 as of gcc-4.8.1 along with FILE_SUPPORTS_INTEGRITY_STREAMS +# if !(defined(Q_CC_MINGW) && defined(FILE_SUPPORTS_INTEGRITY_STREAMS)) typedef struct _FILE_ID_128 { BYTE Identifier[16]; } FILE_ID_128, *PFILE_ID_128; +# endif // !(Q_CC_MINGW && FILE_SUPPORTS_INTEGRITY_STREAMS) typedef struct _FILE_ID_INFO { ULONGLONG VolumeSerialNumber; @@ -614,7 +617,8 @@ QByteArray fileIdWin8(HANDLE handle) &infoEx, sizeof(FILE_ID_INFO))) { result = QByteArray::number(infoEx.VolumeSerialNumber, 16); result += ':'; - result += QByteArray((char *)infoEx.FileId.Identifier, sizeof(infoEx.FileId.Identifier)).toHex(); + // Note: MinGW-64's definition of FILE_ID_128 differs from the MSVC one. + result += QByteArray((char *)&infoEx.FileId, sizeof(infoEx.FileId)).toHex(); } } return result; diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 4dc766ecc5..8d6cf5beb5 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -42,6 +42,7 @@ #include "qmetaobject.h" #include "qmetatype.h" #include "qobject.h" +#include "qmetaobject_p.h" #include #include @@ -2098,8 +2099,12 @@ bool QMetaMethod::invoke(QObject *object, if (qstrcmp(returnValue.name(), retType) != 0) { // normalize the return value as well QByteArray normalized = QMetaObject::normalizedType(returnValue.name()); - if (qstrcmp(normalized.constData(), retType) != 0) - return false; + if (qstrcmp(normalized.constData(), retType) != 0) { + // String comparison failed, try compare the metatype. + int t = returnType(); + if (t == QMetaType::UnknownType || t != QMetaType::type(normalized)) + return false; + } } } diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 20d4339a19..a2d3891f00 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -646,8 +646,6 @@ static inline char qToLower(char c) store raw binary data, and when memory conservation is critical (e.g., with Qt for Embedded Linux). - The maximum array size of a QByteArray is under 2^30. - One way to initialize a QByteArray is simply to pass a \c{const char *} to its constructor. For example, the following code creates a byte array of size 5 containing the data "Hello": diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 288404f3c2..0f2acd6986 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -642,7 +642,7 @@ typename QVector::iterator QVector::erase(iterator abegin, iterator aend) iterator moveEnd = d->end(); while (moveBegin != moveEnd) { if (QTypeInfo::isComplex) - abegin->~T(); + static_cast(abegin)->~T(); new (abegin++) T(*moveBegin++); } if (abegin < d->end()) { diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index e43ac666c7..7838b7df8e 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -591,14 +591,14 @@ bool Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngImage(QImage *outImage) if (doScaledRead) { read_image_scaled(outImage, png_ptr, info_ptr, amp, scaledSize); } else { - png_uint_32 width; - png_uint_32 height; - png_int_32 offset_x; - png_int_32 offset_y; + png_uint_32 width = 0; + png_uint_32 height = 0; + png_int_32 offset_x = 0; + png_int_32 offset_y = 0; - int bit_depth; - int color_type; - int unit_type; + int bit_depth = 0; + int color_type = 0; + int unit_type = PNG_OFFSET_PIXEL; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type); uchar *data = outImage->bits(); diff --git a/src/platformsupport/glxconvenience/glxconvenience.pri b/src/platformsupport/glxconvenience/glxconvenience.pri index d325f5adf9..cc5b198f6c 100644 --- a/src/platformsupport/glxconvenience/glxconvenience.pri +++ b/src/platformsupport/glxconvenience/glxconvenience.pri @@ -1,6 +1,7 @@ -contains(QT_CONFIG,xlib):contains(QT_CONFIG,xrender) { +contains(QT_CONFIG, xlib) { contains(QT_CONFIG,opengl):!contains(QT_CONFIG,opengles2) { - LIBS_PRIVATE += $$QMAKE_LIBS_X11 -lXrender + contains(QT_CONFIG, xrender): LIBS_PRIVATE += -lXrender + LIBS_PRIVATE += $$QMAKE_LIBS_X11 HEADERS += $$PWD/qglxconvenience_p.h SOURCES += $$PWD/qglxconvenience.cpp } diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp index 023cce30ec..b426839f3d 100644 --- a/src/plugins/platforms/android/src/androidjnimain.cpp +++ b/src/plugins/platforms/android/src/androidjnimain.cpp @@ -565,33 +565,37 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jobject jSurface) m_nativeWindow = nativeWindow; if (m_waitForWindow) m_waitForWindowSemaphore.release(); - if (m_androidPlatformIntegration && !sameNativeWindow) { - m_surfaceMutex.unlock(); - m_androidPlatformIntegration->surfaceChanged(); - } else if (m_androidPlatformIntegration && sameNativeWindow) { - QPlatformScreen *screen = m_androidPlatformIntegration->screen(); + + if (m_androidPlatformIntegration) { QSize size = QtAndroid::nativeWindowSize(); + QPlatformScreen *screen = m_androidPlatformIntegration->screen(); QRect geometry(QPoint(0, 0), size); QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry); QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry); - // Resize all top level windows, since they share the same surface - foreach (QWindow *w, QGuiApplication::topLevelWindows()) { - QAndroidOpenGLPlatformWindow *window = - static_cast(w->handle()); + if (!sameNativeWindow) { + m_surfaceMutex.unlock(); + m_androidPlatformIntegration->surfaceChanged(); + } else { + // Resize all top level windows, since they share the same surface + foreach (QWindow *w, QGuiApplication::topLevelWindows()) { + QAndroidOpenGLPlatformWindow *window = + static_cast(w->handle()); - if (window != 0) { - window->lock(); - window->scheduleResize(size); + if (window != 0) { + window->lock(); + window->scheduleResize(size); - QWindowSystemInterface::handleExposeEvent(window->window(), - QRegion(window->window()->geometry())); - window->unlock(); + QWindowSystemInterface::handleExposeEvent(window->window(), + QRegion(window->window()->geometry())); + window->unlock(); + } } + + m_surfaceMutex.unlock(); } - m_surfaceMutex.unlock(); } else { m_surfaceMutex.unlock(); } diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp index f9262c69f6..4934047af9 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp +++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp @@ -84,9 +84,19 @@ void QAndroidOpenGLPlatformWindow::invalidateSurface() } } +void QAndroidOpenGLPlatformWindow::updateStaticNativeWindow() +{ + QWriteLocker locker(&m_staticSurfaceLock); + m_staticNativeWindow = QtAndroid::nativeWindow(false); +} + void QAndroidOpenGLPlatformWindow::resetSurface() { - m_referenceCount.ref(); + // Only add a reference if we're not already holding one, otherwise we're just updating + // the native window pointer + if (m_window == 0) + m_referenceCount.ref(); + if (m_staticSurface == 0) { QWriteLocker locker(&m_staticSurfaceLock); QEglFSWindow::resetSurface(); @@ -94,12 +104,17 @@ void QAndroidOpenGLPlatformWindow::resetSurface() m_staticNativeWindow = m_window; } else { QReadLocker locker(&m_staticSurfaceLock); - Q_ASSERT(m_staticSurface != m_surface); m_window = m_staticNativeWindow; m_surface = m_staticSurface; } - QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event + { + lock(); + scheduleResize(QtAndroid::nativeWindowSize()); + QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event + unlock(); + } + QWindowSystemInterface::flushWindowSystemEvents(); } diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h index 36a110e1a8..9a25957ccd 100644 --- a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h +++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h @@ -71,6 +71,8 @@ public: void destroy(); + static void updateStaticNativeWindow(); + private: QSize m_scheduledResize; QMutex m_lock; diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp index 7cd93e7a16..d7ed3499af 100644 --- a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp @@ -174,6 +174,7 @@ void QAndroidPlatformIntegration::invalidateNativeSurface() void QAndroidPlatformIntegration::surfaceChanged() { + QAndroidOpenGLPlatformWindow::updateStaticNativeWindow(); foreach (QWindow *w, QGuiApplication::topLevelWindows()) { QAndroidOpenGLPlatformWindow *window = static_cast(w->handle()); diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 3ac48df09e..14b8dee101 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -457,7 +457,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatf // Else, we need to transform 'pos' to window or screen coordinates. NSPoint nsPos = NSMakePoint(pos.x() - 1, pos.y()); if (view) { + // Flip y-coordinate first, the convert to content view space. nsPos.y = view.frame.size.height - nsPos.y; + nsPos = [view convertPoint:nsPos toView:view.window.contentView]; } else if (!QGuiApplication::screens().isEmpty()) { QScreen *screen = QGuiApplication::screens().at(0); nsPos.y = screen->availableVirtualSize().height() - nsPos.y; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 46d3b7329e..5fc2975a9d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -795,6 +795,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) QRect rect = window()->geometry(); NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); [m_contentView setFrame:frame]; + [m_contentView setHidden: YES]; } const qreal opacity = qt_window_private(window())->opacity; @@ -913,7 +914,8 @@ void QCocoaWindow::clearNSWindow(NSWindow *window) [window setContentView:nil]; [window setDelegate:nil]; [window clearPlatformWindow]; - [[NSNotificationCenter defaultCenter] removeObserver:m_contentView]; + [[NSNotificationCenter defaultCenter] removeObserver:m_contentView + name:nil object:window]; } // Returns the current global screen geometry for the nswindow associated with this window. @@ -1025,7 +1027,7 @@ qreal QCocoaWindow::devicePixelRatio() const void QCocoaWindow::exposeWindow() { - if (!m_isExposed) { + if (!m_isExposed && ![[m_contentView superview] isHidden]) { m_isExposed = true; QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); } diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 51c3953af1..b8a31329fe 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -107,12 +107,9 @@ static QTouchDevice *touchDevice = 0; m_maskImage = 0; m_maskData = 0; m_window = 0; - if (m_subscribesForGlobalFrameNotifications) { - m_subscribesForGlobalFrameNotifications = false; - [[NSNotificationCenter defaultCenter] removeObserver:self - name:NSViewGlobalFrameDidChangeNotification - object:self]; -} + m_subscribesForGlobalFrameNotifications = false; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + delete currentCustomDragTypes; [super dealloc]; @@ -603,6 +600,7 @@ static QTouchDevice *touchDevice = 0; QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow); QWindowSystemInterface::flushWindowSystemEvents(); m_platformWindow->m_activePopupWindow = 0; + return; } if ([self hasMarkedText]) { NSInputManager* inputManager = [NSInputManager currentInputManager]; diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index f9c5bd2165..5db5e32e65 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -17,7 +17,7 @@ HEADERS = qoffscreenintegration.h \ OTHER_FILES += offscreen.json -contains(QT_CONFIG, xcb):contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2) { +contains(QT_CONFIG, xlib):contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2) { SOURCES += qoffscreenintegration_x11.cpp HEADERS += qoffscreenintegration_x11.h system(echo "Using X11 offscreen integration with GLX") diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 9f00412b4c..b46b7a1d23 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1808,8 +1808,8 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow QString defaultSuffix = m_options->defaultSuffix(); if (defaultSuffix.startsWith(QLatin1Char('.'))) defaultSuffix.remove(0, 1); - if (!defaultSuffix.isEmpty()) - ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix); + // QTBUG-33156, also create empty strings to trigger the appending mechanism. + ofn->lpstrDefExt = qStringToWCharArray(defaultSuffix); } // Flags. ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 770838d7b8..eb1bbd1ab0 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -39,6 +39,12 @@ ** ****************************************************************************/ +// SHSTOCKICONINFO is only available since Vista +#if _WIN32_WINNT < 0x0600 +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +#endif + #include "qwindowstheme.h" #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" diff --git a/src/tools/qdoc/doc/qdoc-minimum-qdocconf.qdoc b/src/tools/qdoc/doc/qdoc-minimum-qdocconf.qdoc index 4289f357e9..20e0b86b6c 100644 --- a/src/tools/qdoc/doc/qdoc-minimum-qdocconf.qdoc +++ b/src/tools/qdoc/doc/qdoc-minimum-qdocconf.qdoc @@ -26,12 +26,15 @@ ****************************************************************************/ /*! \page qdoc-minimum-qdocconf.html -\title A minimal qdocconf file with comments +\title A minimal qdocconf file with Comments \brief Describes a minimal .qdocconf file -Below you will find the full contents of qtgui.qdocconf. The subsequent section will discuss -every statement in the qdocconf file. +Below you will find the full contents of qtgui.qdocconf. The subsequent section +will discuss every statement in the qdocconf file. + +Each line from the qdocconf file is first quoted. Below each statement you will +find the meaning. \code #include(compat.qdocconf) @@ -83,4 +86,6 @@ The source code of the example files can be found in the current directory. The image files can be found in the underlying directory "images". +\note Please take care with this minimal qdocconf file. Using it in the wrong directory +could cause qdoc to include a large number of files. */ diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp index 846858ab31..a39c084798 100644 --- a/src/widgets/graphicsview/qgraphicsview.cpp +++ b/src/widgets/graphicsview/qgraphicsview.cpp @@ -3221,6 +3221,13 @@ void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) qt_sendSpontaneousEvent(d->scene, &mouseEvent); else QApplication::sendEvent(d->scene, &mouseEvent); + + // Update the original mouse event accepted state. + const bool isAccepted = mouseEvent.isAccepted(); + event->setAccepted(isAccepted); + + // Update the last mouse event accepted state. + d->lastMouseEvent.setAccepted(isAccepted); } /*! diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 8dbbd16f62..331748eedc 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1456,7 +1456,7 @@ void QListView::doItemsLayout() void QListView::updateGeometries() { Q_D(QListView); - if (d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) { + if (geometry().isEmpty() || d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) { horizontalScrollBar()->setRange(0, 0); verticalScrollBar()->setRange(0, 0); } else { @@ -1471,15 +1471,15 @@ void QListView::updateGeometries() // if the scroll bars are turned off, we resize the contents to the viewport if (d->movement == Static && !d->isWrapping()) { - const QSize maxSize = maximumViewportSize(); + d->layoutChildren(); // we need the viewport size to be updated if (d->flow == TopToBottom) { if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) { - d->setContentsSize(maxSize.width(), contentsSize().height()); + d->setContentsSize(viewport()->width(), contentsSize().height()); horizontalScrollBar()->setRange(0, 0); // we see all the contents anyway } } else { // LeftToRight if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) { - d->setContentsSize(contentsSize().width(), maxSize.height()); + d->setContentsSize(contentsSize().width(), viewport()->height()); verticalScrollBar()->setRange(0, 0); // we see all the contents anyway } } diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp index 471b054a99..678e6f25d1 100644 --- a/src/widgets/kernel/qshortcut.cpp +++ b/src/widgets/kernel/qshortcut.cpp @@ -158,7 +158,7 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge if (context == Qt::WidgetWithChildrenShortcut) { const QWidget *tw = QApplication::focusWidget(); - while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup)) + while (tw && tw != w && (tw->windowType() == Qt::Widget || tw->windowType() == Qt::Popup || tw->windowType() == Qt::SubWindow)) tw = tw->parentWidget(); return tw == w; } diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp index a8b6b1a10c..adf70fde66 100644 --- a/src/widgets/widgets/qlineedit.cpp +++ b/src/widgets/widgets/qlineedit.cpp @@ -333,8 +333,7 @@ void QLineEdit::setText(const QString& text) \brief the line edit's placeholder text Setting this property makes the line edit display a grayed-out - placeholder text as long as the text() is empty and the widget doesn't - have focus. + placeholder text as long as the text() is empty. By default, this property contains an empty string. diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 4df89a5ede..c305748c7d 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2864,8 +2864,15 @@ void QMenu::mouseMoveEvent(QMouseEvent *e) d->mouseDown = this; } if (d->sloppyRegion.contains(e->pos())) { - d->sloppyAction = action; - QMenuPrivate::sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)*6); + // If the timer is already running then don't start a new one unless the action is the same + if (d->sloppyAction != action && QMenuPrivate::sloppyDelayTimer != 0) { + killTimer(QMenuPrivate::sloppyDelayTimer); + QMenuPrivate::sloppyDelayTimer = 0; + } + if (QMenuPrivate::sloppyDelayTimer == 0) { + d->sloppyAction = action; + QMenuPrivate::sloppyDelayTimer = startTimer(style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this) * 6); + } } else if (action != d->currentAction) { d->setCurrentAction(action, style()->styleHint(QStyle::SH_Menu_SubMenuPopupDelay, 0, this)); } diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index f22c48b26f..a7cad28df3 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1054,6 +1054,7 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) if(QMenu *menu = d->activeMenu) { d->activeMenu = 0; menu->hide(); + d->closePopupMode = 1; } } else { d->setCurrentAction(action, true); diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index ca80c8926f..4f1320e375 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -328,6 +328,7 @@ public slots: QObject *sl11(); const char *sl12(); QList sl13(QList l1); + qint64 sl14(); void testSender(); void testReference(QString &str); @@ -395,6 +396,9 @@ const char *QtTestObject::sl12() { slotResult = "sl12"; return "foo"; } QList QtTestObject::sl13(QList l1) { slotResult = "sl13"; return l1; } +qint64 QtTestObject::sl14() +{ slotResult = "sl14"; return Q_INT64_C(123456789)*123456789; } + void QtTestObject::testReference(QString &str) { slotResult = "testReference:" + str; str = "gotcha"; } @@ -513,6 +517,13 @@ void tst_QMetaObject::invokeMetaMember() QCOMPARE(returnValue, argument); QCOMPARE(obj.slotResult, QString("sl13")); + // return qint64 + qint64 return64; + QVERIFY(QMetaObject::invokeMethod(&obj, "sl14", + Q_RETURN_ARG(qint64, return64))); + QCOMPARE(return64, Q_INT64_C(123456789)*123456789); + QCOMPARE(obj.slotResult, QString("sl14")); + //test signals QVERIFY(QMetaObject::invokeMethod(&obj, "sig0")); QCOMPARE(obj.slotResult, QString("sl0")); diff --git a/tests/auto/network-settings.h b/tests/auto/network-settings.h index 2ffb89241c..ad51df9090 100644 --- a/tests/auto/network-settings.h +++ b/tests/auto/network-settings.h @@ -103,20 +103,9 @@ public: static bool compareReplyFtp(QByteArray const& actual) { - QList expected; - - // A few different vsFTPd versions. - // Feel free to add more as needed - expected << QByteArray( "220 (vsFTPd 2.0.5)\r\n221 Goodbye.\r\n" ); - expected << QByteArray( "220 (vsFTPd 2.2.2)\r\n221 Goodbye.\r\n" ); - - Q_FOREACH (QByteArray const& ba, expected) { - if (ba == actual) { - return true; - } - } - - return false; + // output would be e.g. "220 (vsFTPd 2.3.5)\r\n221 Goodbye.\r\n" + QRegExp ftpVersion(QStringLiteral("220 \\(vsFTPd \\d+\\.\\d+.\\d+\\)\\r\\n221 Goodbye.\\r\\n")); + return ftpVersion.exactMatch(actual); } static bool hasIPv6() diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index ea547ffae5..3d57345d2d 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -4389,6 +4389,10 @@ void tst_QNetworkReply::ioPostToHttpFromSocket_data() void tst_QNetworkReply::ioPostToHttpFromSocket() { + if (QTest::currentDataTag() == QByteArray("128k+1+proxyauth") + || QTest::currentDataTag() == QByteArray("128k+1+auth+proxyauth")) + QSKIP("Squid cannot handle authentication with POST data >= 64K (QTBUG-33180)"); + QFETCH(QByteArray, data); QFETCH(QUrl, url); QFETCH(QNetworkProxy, proxy); diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index cb19712818..b6df536b98 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -1578,7 +1578,7 @@ void tst_QTcpSocket::recursiveReadyRead() QSignalSpy spy(testSocket, SIGNAL(readyRead())); - testSocket->connectToHost(QtNetworkSettings::serverName(), 25); + testSocket->connectToHost(QtNetworkSettings::serverName(), 143); enterLoop(30); QVERIFY2(!timeout(), "Timed out when connecting to QtNetworkSettings::serverName()."); diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp index 9e06435ca7..7a0ba50ff0 100644 --- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp +++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp @@ -221,6 +221,9 @@ private slots: void scrollBarRanges_data(); void scrollBarRanges(); void acceptMousePressEvent(); + void acceptMouseDoubleClickEvent(); + void forwardMousePress(); + void forwardMouseDoubleClick(); void replayMouseMove(); void itemsUnderMouse(); void embeddedViews(); @@ -2832,16 +2835,22 @@ class TestView : public QGraphicsView { public: TestView(QGraphicsScene *scene) - : QGraphicsView(scene), accepted(false) + : QGraphicsView(scene), pressAccepted(false), doubleClickAccepted(false) { } - bool accepted; + bool pressAccepted; + bool doubleClickAccepted; protected: void mousePressEvent(QMouseEvent *event) { QGraphicsView::mousePressEvent(event); - accepted = event->isAccepted(); + pressAccepted = event->isAccepted(); + } + void mouseDoubleClickEvent(QMouseEvent *event) + { + QGraphicsView::mouseDoubleClickEvent(event); + doubleClickAccepted = event->isAccepted(); } }; @@ -2859,14 +2868,109 @@ void tst_QGraphicsView::acceptMousePressEvent() Qt::LeftButton, 0, 0); event.setAccepted(false); QApplication::sendEvent(view.viewport(), &event); - QVERIFY(!view.accepted); + QVERIFY(!view.pressAccepted); scene.addRect(0, 0, 2000, 2000)->setFlag(QGraphicsItem::ItemIsMovable); qApp->processEvents(); // ensure scene rect is updated QApplication::sendEvent(view.viewport(), &event); - QVERIFY(view.accepted); + QVERIFY(view.pressAccepted); +} + +void tst_QGraphicsView::acceptMouseDoubleClickEvent() +{ + QGraphicsScene scene; + + TestView view(&scene); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QMouseEvent event(QEvent::MouseButtonDblClick, + view.viewport()->rect().center(), + view.viewport()->mapToGlobal(view.viewport()->rect().center()), + Qt::LeftButton, 0, 0); + event.setAccepted(false); + QApplication::sendEvent(view.viewport(), &event); + QVERIFY(!view.doubleClickAccepted); + + scene.addRect(0, 0, 2000, 2000)->setFlag(QGraphicsItem::ItemIsMovable); + + qApp->processEvents(); // ensure scene rect is updated + + QApplication::sendEvent(view.viewport(), &event); + QVERIFY(view.doubleClickAccepted); +} + +class TestWidget : public QWidget +{ +public: + TestWidget() + : QWidget(), pressForwarded(false), doubleClickForwarded(false) + { } + + bool pressForwarded; + bool doubleClickForwarded; + +protected: + void mousePressEvent(QMouseEvent *event) + { + QWidget::mousePressEvent(event); + pressForwarded = true; + } + void mouseDoubleClickEvent(QMouseEvent *event) + { + QWidget::mouseDoubleClickEvent(event); + doubleClickForwarded = true; + } +}; + +void tst_QGraphicsView::forwardMousePress() +{ + TestWidget widget; + QGraphicsScene scene; + QGraphicsView view(&scene); + QHBoxLayout layout; + widget.setLayout(&layout); + layout.addWidget(&view); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + widget.pressForwarded = false; + QTest::mouseClick(view.viewport(), Qt::LeftButton); + QVERIFY(widget.pressForwarded); + + scene.addRect(0, 0, 2000, 2000); + + qApp->processEvents(); // ensure scene rect is updated + + widget.pressForwarded = false; + QTest::mouseClick(view.viewport(), Qt::LeftButton); + QVERIFY(widget.pressForwarded); +} + +void tst_QGraphicsView::forwardMouseDoubleClick() +{ + TestWidget widget; + QGraphicsScene scene; + QGraphicsView view(&scene); + QHBoxLayout layout; + widget.setLayout(&layout); + layout.addWidget(&view); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + widget.doubleClickForwarded = false; + QTest::mouseDClick(view.viewport(), Qt::LeftButton); + QVERIFY(widget.doubleClickForwarded); + + scene.addRect(0, 0, 2000, 2000); + + qApp->processEvents(); // ensure scene rect is updated + + widget.doubleClickForwarded = false; + QTest::mouseDClick(view.viewport(), Qt::LeftButton); + QVERIFY(widget.doubleClickForwarded); } void tst_QGraphicsView::replayMouseMove() diff --git a/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp b/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp index d3191b2206..6c04e5b39a 100644 --- a/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp +++ b/tests/auto/widgets/itemviews/qcolumnview/tst_qcolumnview.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #define ANIMATION_DELAY 300 @@ -387,6 +388,12 @@ void tst_QColumnView::scrollTo_data() QTest::newRow("reverse") << true << false; } +static inline void centerOnScreen(QWidget *w) +{ + const QPoint offset = QPoint(w->width() / 2, w->height() / 2); + w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset); +} + void tst_QColumnView::scrollTo() { QFETCH(bool, reverse); @@ -397,6 +404,7 @@ void tst_QColumnView::scrollTo() ColumnView view(&topLevel); view.resize(200, 200); topLevel.show(); + centerOnScreen(&topLevel); view.scrollTo(QModelIndex(), QAbstractItemView::EnsureVisible); QCOMPARE(view.HorizontalOffset(), 0); diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index 0085b75299..227f61b0a3 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -164,6 +164,12 @@ static inline void setFrameless(QWidget *w) w->setWindowFlags(flags); } +static inline void centerOnScreen(QWidget *w) +{ + const QPoint offset = QPoint(w->width() / 2, w->height() / 2); + w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset); +} + class tst_QWidget : public QObject { Q_OBJECT @@ -4004,7 +4010,8 @@ void tst_QWidget::update() Q_CHECK_PAINTEVENTS UpdateWidget w; - w.setGeometry(50, 50, 100, 100); + w.resize(100, 100); + centerOnScreen(&w); w.show(); QVERIFY(QTest::qWaitForWindowExposed(&w)); @@ -7647,6 +7654,7 @@ void tst_QWidget::doubleRepaint() QSKIP("QTBUG-30566 - Unstable auto-test"); #endif UpdateWidget widget; + centerOnScreen(&widget); widget.setFocusPolicy(Qt::StrongFocus); // Filter out activation change and focus events to avoid update() calls in QWidget. widget.updateOnActivationChangeAndFocusIn = false; @@ -7774,6 +7782,7 @@ void tst_QWidget::setMaskInResizeEvent() UpdateWidget w; w.reset(); w.resize(200, 200); + centerOnScreen(&w); w.setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); w.raise(); @@ -7851,6 +7860,7 @@ void tst_QWidget::immediateRepaintAfterShow() QSKIP("We don't support immediate repaint right after show on other platforms."); UpdateWidget widget; + centerOnScreen(&widget); widget.show(); qApp->processEvents(); // On X11 in particular, we are now waiting for a MapNotify event before @@ -7867,6 +7877,7 @@ void tst_QWidget::immediateRepaintAfterInvalidateBuffer() QSKIP("We don't support immediate repaint right after show on other platforms."); QScopedPointer widget(new UpdateWidget); + centerOnScreen(widget.data()); widget->show(); QVERIFY(QTest::qWaitForWindowExposed(widget.data())); QTest::qWait(200); @@ -8282,6 +8293,7 @@ void tst_QWidget::setClearAndResizeMask() { UpdateWidget topLevel; topLevel.resize(160, 160); + centerOnScreen(&topLevel); topLevel.show(); qApp->setActiveWindow(&topLevel); QVERIFY(QTest::qWaitForWindowActive(&topLevel)); @@ -8434,6 +8446,7 @@ void tst_QWidget::maskedUpdate() { UpdateWidget topLevel; topLevel.resize(200, 200); + centerOnScreen(&topLevel); const QRegion topLevelMask(50, 50, 70, 70); topLevel.setMask(topLevelMask); @@ -8859,6 +8872,7 @@ void tst_QWidget::focusWidget_task254563() void tst_QWidget::destroyBackingStore() { UpdateWidget w; + centerOnScreen(&w); w.reset(); w.show(); diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp index e7450fdd2c..2b8e735a0e 100644 --- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp +++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -57,23 +58,6 @@ QT_FORWARD_DECLARE_CLASS(QMainWindow) #include -class QtTestSlot : public QObject -{ - Q_OBJECT - -public: - QtTestSlot( QObject* parent = 0 ): QObject( parent ) { clear(); }; - virtual ~QtTestSlot() {}; - - void clear() { sel_count = 0; }; - uint selCount() { return sel_count; }; - -public slots: - void selected() { sel_count++; }; - -private: - uint sel_count; -}; class Menu : public QMenu { @@ -87,20 +71,24 @@ class Menu : public QMenu } }; +static inline void centerOnScreen(QWidget *w) +{ + const QPoint offset = QPoint(w->width() / 2, w->height() / 2); + w->move(QGuiApplication::primaryScreen()->availableGeometry().center() - offset); +} + +struct TestMenu +{ + QList menus; + QList actions; +}; + class tst_QMenuBar : public QObject { Q_OBJECT public: tst_QMenuBar(); - virtual ~tst_QMenuBar(); - void initSimpleMenubar(); - void initComplexMenubar(); - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); private slots: void getSetCheck(); @@ -145,39 +133,23 @@ private slots: void taskQTBUG4965_escapeEaten(); #endif void taskQTBUG11823_crashwithInvisibleActions(); + void closeOnSecondClick(); protected slots: - void onActivated( QAction*); + void onSimpleActivated( QAction*); + void onComplexActionTriggered(); private: - QtTestSlot *menu1; - QtTestSlot *menu2; - QtTestSlot *menu3; - QtTestSlot *menu4; + TestMenu initSimpleMenuBar(QMenuBar *mb); + TestMenu initWindowWithSimpleMenuBar(QMainWindow &w); + QAction *createCharacterAction(QMenu *menu, char lowerAscii); + QMenu *addNumberedMenu(QMenuBar *mb, int n); + TestMenu initComplexMenuBar(QMenuBar *mb); + TestMenu initWindowWithComplexMenuBar(QMainWindow &w); - QtTestSlot *item1_A; - QtTestSlot *item1_B; - QtTestSlot *item2_C; - QtTestSlot *item2_D; - QtTestSlot *item2_E; - QtTestSlot *item2_F; - QtTestSlot *item2_G; - QtTestSlot *item2_H; - - void resetSlots(); - void resetCount(); - - void reset() { resetSlots(); resetCount(); }; - - QAction* last_accel_id; - int activated_count; - - QAction *action; - QAction *action1; - QMainWindow *mw; - QMenuBar *mb; - QMenu *pm1; - QMenu *pm2; + QAction* m_lastSimpleAcceleratorId; + int m_simpleActivatedCount; + int m_complexTriggerCount['k']; }; // Testing get/set functions @@ -220,116 +192,119 @@ const int RESET = 0; */ -tst_QMenuBar::tst_QMenuBar() - +tst_QMenuBar::tst_QMenuBar() : m_lastSimpleAcceleratorId(0), m_simpleActivatedCount(0) { QApplication::setEffectEnabled(Qt::UI_AnimateMenu, false); - - - activated_count = 0; - mb = 0; - pm1 = 0; - pm2 = 0; - last_accel_id = 0; } -tst_QMenuBar::~tst_QMenuBar() +void tst_QMenuBar::onSimpleActivated( QAction* action ) { - //delete mw; //#### cannot do that AFTER qapplication was destroyed! - mw = 0; + m_lastSimpleAcceleratorId = action; + m_simpleActivatedCount++; } -void tst_QMenuBar::initTestCase() +// Create a simple menu bar and connect its actions to onSimpleActivated(). + +TestMenu tst_QMenuBar::initSimpleMenuBar(QMenuBar *mb) { - // create a default mainwindow - // If you run a widget test, this will be replaced in the testcase by the - // widget under test - mw = new QMainWindow(0, Qt::X11BypassWindowManagerHint); - mb = new QMenuBar( mw ); - connect( mb, SIGNAL(triggered(QAction*)), this, SLOT(onActivated(QAction*)) ); + TestMenu result; + connect(mb, SIGNAL(triggered(QAction*)), this, SLOT(onSimpleActivated(QAction*))); + QMenu *menu = mb->addMenu(QStringLiteral("&accel")); + QAction *action = menu->addAction(QStringLiteral("menu1") ); + action->setShortcut(QKeySequence(Qt::ALT + Qt::Key_A)); + action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A)); + connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(onSimpleActivated(QAction*))); + result.menus << menu; + result.actions << action; - initSimpleMenubar(); - mw->show(); - mw->activateWindow(); - QVERIFY(QTest::qWaitForWindowActive(mw)); + menu = mb->addMenu(QStringLiteral("accel1")); + action = menu->addAction(QStringLiteral("&Open...") ); + action->setShortcut(Qt::Key_O); + result.menus << menu; + connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(onSimpleActivated(QAction*))); + result.actions << action; - menu1 = new QtTestSlot( mw ); - menu2 = new QtTestSlot( mw ); - menu3 = new QtTestSlot( mw ); - menu4 = new QtTestSlot( mw ); - item1_A = new QtTestSlot( mw ); - item1_B = new QtTestSlot( mw ); - item2_C = new QtTestSlot( mw ); - item2_D = new QtTestSlot( mw ); - item2_E = new QtTestSlot( mw ); - item2_F = new QtTestSlot( mw ); - item2_G = new QtTestSlot( mw ); - item2_H = new QtTestSlot( mw ); + m_lastSimpleAcceleratorId = 0; + m_simpleActivatedCount = 0; + + return result; } - -void tst_QMenuBar::cleanupTestCase() +inline TestMenu tst_QMenuBar::initWindowWithSimpleMenuBar(QMainWindow &w) { - delete mw; + w.resize(200, 200); + centerOnScreen(&w); + return initSimpleMenuBar(w.menuBar()); } -void tst_QMenuBar::initSimpleMenubar() +// add a menu with number n, set number as data. +QMenu *tst_QMenuBar::addNumberedMenu(QMenuBar *mb, int n) { - mb->hide(); - mb->clear(); - - delete pm1; - pm1 = mb->addMenu("&accel"); - action = pm1->addAction( "menu1" ); - action->setShortcut(QKeySequence("ALT+A")); - action->setShortcut(QKeySequence("CTRL+A")); - - connect( pm1, SIGNAL(triggered(QAction*)), this, SLOT(onActivated(QAction*))); - - delete pm2; - pm2 = mb->addMenu("accel1"); - - action1 = pm2->addAction( "&Open..." ); - action1->setShortcut(Qt::Key_O); - connect(pm2, SIGNAL(triggered(QAction*)), this, SLOT(onActivated(QAction*))); - - mb->show(); - qApp->processEvents(); + const QString text = QStringLiteral("Menu &") + QString::number(n); + QMenu *menu = mb->addMenu(text); + menu->setObjectName(text); + QAction *action = menu->menuAction(); + action->setObjectName(text + QStringLiteral("Action")); + action->setData(QVariant(n)); + connect(action, SIGNAL(triggered()), this, SLOT(onComplexActionTriggered())); + return menu; } -void tst_QMenuBar::init() +// Create an action triggering on Ctrl+character, set number as data. +QAction *tst_QMenuBar::createCharacterAction(QMenu *menu, char lowerAscii) { - resetSlots(); - resetCount(); + const QString text = QStringLiteral("Item ") + QChar(QLatin1Char(lowerAscii)).toUpper(); + QAction *action = menu->addAction(text); + action->setObjectName(text); + action->setData(QVariant(int(lowerAscii))); + action->setShortcut(Qt::CTRL + (lowerAscii - 'a' + Qt::Key_A)); + connect(action, SIGNAL(triggered()), this, SLOT(onComplexActionTriggered())); + return action; } -void tst_QMenuBar::resetSlots() +void tst_QMenuBar::onComplexActionTriggered() { - menu1->clear(); - menu2->clear(); - menu3->clear(); - menu4->clear(); - item1_A->clear(); - item1_B->clear(); - item2_C->clear(); - item2_D->clear(); - item2_E->clear(); - item2_F->clear(); - item2_G->clear(); - item2_H->clear(); + if (QAction *a = qobject_cast(sender())) + m_complexTriggerCount[a->data().toInt()]++; } -void tst_QMenuBar::resetCount() +// Create a complex menu bar and connect its actions to onComplexActionTriggered() +// for their invocations to be counted in m_complexTriggerCount. The index is the +// menu number (1..n) for the menu bar actions and the ASCII-code of the shortcut +// character for the actions in the menus. +TestMenu tst_QMenuBar::initComplexMenuBar(QMenuBar *mb) { - last_accel_id = 0; - activated_count = 0; + TestMenu result; + QMenu *menu = addNumberedMenu(mb, 1); + result.menus << menu; + for (char c = 'a'; c < 'c'; ++c) + result.actions << createCharacterAction(menu, c); + + menu = addNumberedMenu(mb, 2); + menu->menuAction()->setData(QVariant(2)); + result.menus << menu; + for (char c = 'c'; c < 'g'; ++c) + result.actions << createCharacterAction(menu, c); + menu->addSeparator(); + for (char c = 'g'; c < 'i'; ++c) + result.actions << createCharacterAction(menu, c); + + QAction *action = mb->addAction(QStringLiteral("M&enu 3")); + action->setData(QVariant(3)); + action->setShortcut(Qt::ALT + Qt::Key_J); + connect(action, SIGNAL(triggered()), this, SLOT(onComplexActionTriggered())); + result.actions << action; + + qFill(m_complexTriggerCount, m_complexTriggerCount + sizeof(m_complexTriggerCount) / sizeof(int), 0); + + return result; } -void tst_QMenuBar::onActivated( QAction* action ) +inline TestMenu tst_QMenuBar::initWindowWithComplexMenuBar(QMainWindow &w) { - last_accel_id = action; - activated_count++; -// printf( QString("acceleratorId: %1, count: %1\n").arg( i ).arg(activated_count) ); + w.resize(400, 200); + centerOnScreen(&w); + return initComplexMenuBar(w.menuBar()); } // On Mac/WinCE, native key events are needed to test menu action activation @@ -337,15 +312,16 @@ void tst_QMenuBar::onActivated( QAction* action ) void tst_QMenuBar::accel() { // create a popup menu with menu items set the accelerators later... - initSimpleMenubar(); - + QMainWindow w; + const TestMenu menu = initWindowWithSimpleMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // shortcuts won't work unless the window is active - QTRY_VERIFY( QApplication::activeWindow() ); -// QTest::keyClick(static_cast(0), Qt::Key_A, AltKey ); QTest::keyClick(static_cast(0), Qt::Key_A, Qt::ControlModifier ); QTest::qWait(300); - QCOMPARE( last_accel_id, action ); + QCOMPARE( m_lastSimpleAcceleratorId, menu.actions.front() ); } #endif @@ -354,40 +330,45 @@ void tst_QMenuBar::accel() void tst_QMenuBar::activatedCount() { // create a popup menu with menu items set the accelerators later... - initSimpleMenubar(); + QMainWindow w; + initWindowWithSimpleMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); QTest::keyClick(static_cast(0), Qt::Key_A, Qt::ControlModifier ); //wait(5000); - QCOMPARE( activated_count, 2 ); //1 from the popupmenu and 1 from the menubar + QCOMPARE( m_simpleActivatedCount, 2 ); //1 from the popupmenu and 1 from the menubar } #endif void tst_QMenuBar::clear() { - mb->clear(); - QVERIFY( (uint) mb->actions().size() == 0 ); + QMenuBar menuBar; + initSimpleMenuBar(&menuBar); + menuBar.clear(); + QCOMPARE( menuBar.actions().size(), 0 ); - mb->clear(); - for (uint i=0; i<10; i++) { - QMenu *menu = mb->addMenu( QString("Menu %1")); - for (uint k=0; kaddAction( QString("Item %1")); - QCOMPARE( (uint) mb->actions().size(), (uint)i+1 ); + menuBar.clear(); + for (int i = 0; i < 10; i++) { + QMenu *menu = menuBar.addMenu( QStringLiteral("Menu ") + QString::number(i)); + for (int k = 0; k < i; k++) + menu->addAction( QStringLiteral("Item ") + QString::number(k)); + QCOMPARE( menuBar.actions().size(), i + 1 ); } - QCOMPARE( (uint) mb->actions().size(), 10u ); - - mb->clear(); - QVERIFY( (uint) mb->actions().size() == 0 ); + QCOMPARE( menuBar.actions().size(), 10 ); + menuBar.clear(); + QCOMPARE( menuBar.actions().size(), 0 ); } void tst_QMenuBar::count() { - mb->clear(); - QVERIFY( mb->actions().size() == 0 ); + QMenuBar menuBar; + QCOMPARE( menuBar.actions().size(), 0 ); - for (uint i=0; i<10; i++) { - mb->addAction( QString("Menu %1")); - QCOMPARE( (uint) mb->actions().size(), (uint) i+1 ); + for (int i = 0; i < 10; i++) { + menuBar.addAction( QStringLiteral("Menu ") + QString::number(i)); + QCOMPARE( menuBar.actions().size(), i + 1 ); } } @@ -402,27 +383,26 @@ void tst_QMenuBar::removeItem_data() // Basically the same test as removeItemAt, except that we remember and remove id's. void tst_QMenuBar::removeItem() { - mb->clear(); + QMenuBar menuBar; - QMenu *pm; - pm = new QMenu( "stuff", mb ); + QMenu *pm = new QMenu( "stuff", &menuBar ); pm->setTitle("Menu 1"); pm->addAction( QString("Item 10") ); - QAction* action1 = mb->addMenu( pm ); + QAction* action1 = menuBar.addMenu( pm ); - pm = new QMenu( mb ); + pm = new QMenu( &menuBar ); pm->setTitle("Menu 2"); pm->addAction( QString("Item 20") ); pm->addAction( QString("Item 21") ); - QAction *action2 = mb->addMenu( pm ); + QAction *action2 = menuBar.addMenu( pm ); - pm = new QMenu( "Menu 3", mb ); + pm = new QMenu( "Menu 3", &menuBar ); pm->addAction( QString("Item 30") ); pm->addAction( QString("Item 31") ); pm->addAction( QString("Item 32") ); - QAction *action3 = mb->addMenu( pm ); + QAction *action3 = menuBar.addMenu( pm ); - QList menuBarActions = mb->actions(); + const QList menuBarActions = menuBar.actions(); QCOMPARE( action1->text(), QString("Menu 1") ); QCOMPARE( action2->text(), QString("Menu 2") ); @@ -437,28 +417,28 @@ void tst_QMenuBar::removeItem() switch (removeIndex ) { case 0: { - mb->removeAction(action1); - QList menuBarActions2 = mb->actions(); + menuBar.removeAction(action1); + const QList menuBarActions2 = menuBar.actions(); QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 2") ); QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") ); } break; case 1: { - mb->removeAction(action2); - QList menuBarActions2 = mb->actions(); + menuBar.removeAction(action2); + const QList menuBarActions2 = menuBar.actions(); QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") ); QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 3") ); } break; case 2: { - mb->removeAction(action3); - QList menuBarActions2 = mb->actions(); + menuBar.removeAction(action3); + const QList menuBarActions2 = menuBar.actions(); QCOMPARE( menuBarActions2.at(0)->text(), QString("Menu 1") ); QCOMPARE( menuBarActions2.at(1)->text(), QString("Menu 2") ); } break; } - QList menuBarActions2 = mb->actions(); + QList menuBarActions2 = menuBar.actions(); QVERIFY( menuBarActions2.size() == 2 ); } @@ -472,25 +452,23 @@ void tst_QMenuBar::removeItemAt_data() void tst_QMenuBar::removeItemAt() { - mb->clear(); - - QMenu *pm; - pm = new QMenu("Menu 1", mb); + QMenuBar menuBar; + QMenu *pm = new QMenu("Menu 1", &menuBar); pm->addAction( QString("Item 10") ); - mb->addMenu( pm ); + menuBar.addMenu( pm ); - pm = new QMenu( "Menu 2", mb ); + pm = new QMenu( "Menu 2", &menuBar); pm->addAction( QString("Item 20") ); pm->addAction( QString("Item 21") ); - mb->addMenu( pm ); + menuBar.addMenu( pm ); - pm = new QMenu( "Menu 3", mb ); + pm = new QMenu( "Menu 3", &menuBar); pm->addAction( QString("Item 30") ); pm->addAction( QString("Item 31") ); pm->addAction( QString("Item 32") ); - mb->addMenu( pm ); + menuBar.addMenu( pm ); - QList menuBarActions = mb->actions(); + QList menuBarActions = menuBar.actions(); QCOMPARE( menuBarActions.at(0)->text(), QString("Menu 1") ); QCOMPARE( menuBarActions.at(1)->text(), QString("Menu 2") ); @@ -498,8 +476,8 @@ void tst_QMenuBar::removeItemAt() // Ok, now that we know we have created the menu we expect, lets remove an item... QFETCH( int, removeIndex ); - mb->removeAction(menuBarActions.at(removeIndex)); - QList menuBarActions2 = mb->actions(); + menuBar.removeAction(menuBarActions.at(removeIndex)); + const QList menuBarActions2 = menuBar.actions(); switch (removeIndex ) { case 0: @@ -519,32 +497,6 @@ void tst_QMenuBar::removeItemAt() QVERIFY( menuBarActions2.size() == 2 ); } -void tst_QMenuBar::initComplexMenubar() // well, complex.... -{ - mb->hide(); - mb->clear(); - - delete pm1; - pm1 = mb->addMenu("Menu &1"); - pm1->addAction( QString("Item A"), item1_A, SLOT(selected()), Qt::CTRL+Qt::Key_A ); - pm1->addAction( QString("Item B"), item1_B, SLOT(selected()), Qt::CTRL+Qt::Key_B ); - - delete pm2; - pm2 = mb->addMenu("Menu &2"); - pm2->addAction( QString("Item C"), item2_C, SLOT(selected()), Qt::CTRL+Qt::Key_C ); - pm2->addAction( QString("Item D"), item2_D, SLOT(selected()), Qt::CTRL+Qt::Key_D ); - pm2->addAction( QString("Item E"), item2_E, SLOT(selected()), Qt::CTRL+Qt::Key_E ); - pm2->addAction( QString("Item F"), item2_F, SLOT(selected()), Qt::CTRL+Qt::Key_F ); - pm2->addSeparator(); - pm2->addAction( QString("Item G"), item2_G, SLOT(selected()), Qt::CTRL+Qt::Key_G ); - pm2->addAction( QString("Item H"), item2_H, SLOT(selected()), Qt::CTRL+Qt::Key_H ); - - QAction *ac = mb->addAction( QString("M&enu 3"), menu3, SLOT(selected())); - ac->setShortcut(Qt::ALT+Qt::Key_J); - mb->show(); -} - - /* Check the insert functions that create menu items. For the moment i only check the strings and pixmaps. The rest are special cases which are @@ -553,9 +505,10 @@ void tst_QMenuBar::initComplexMenubar() // well, complex.... void tst_QMenuBar::insertItem_QString_QObject() { - initComplexMenubar(); + QMenuBar menuBar; + initComplexMenuBar(&menuBar); - QList actions = mb->actions(); + const QList actions = menuBar.actions(); QCOMPARE(actions.at(0)->text(), QString("Menu &1") ); QCOMPARE(actions.at(1)->text(), QString("Menu &2") ); @@ -567,68 +520,72 @@ void tst_QMenuBar::insertItem_QString_QObject() #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_accelKeys() { - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // start with a bogus key that shouldn't trigger anything QTest::keyClick(static_cast(0), Qt::Key_I, Qt::ControlModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); QTest::keyClick(static_cast(0), Qt::Key_A, Qt::ControlModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 1u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 1); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); QTest::keyClick(static_cast(0), Qt::Key_C, Qt::ControlModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 1u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_C->selCount(), 1u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 1); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['c'], 1); + QCOMPARE(m_complexTriggerCount['d'], 0); QTest::keyClick(static_cast(0), Qt::Key_B, Qt::ControlModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 1u); - QCOMPARE(item1_B->selCount(), 1u); - QCOMPARE(item2_C->selCount(), 1u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 1); + QCOMPARE(m_complexTriggerCount['b'], 1); + QCOMPARE(m_complexTriggerCount['c'], 1); + QCOMPARE(m_complexTriggerCount['d'], 0); QTest::keyClick(static_cast(0), Qt::Key_D, Qt::ControlModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 1u); - QCOMPARE(item1_B->selCount(), 1u); - QCOMPARE(item2_C->selCount(), 1u); - QCOMPARE(item2_D->selCount(), 1u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 1); + QCOMPARE(m_complexTriggerCount['b'], 1); + QCOMPARE(m_complexTriggerCount['c'], 1); + QCOMPARE(m_complexTriggerCount['d'], 1); QTest::keyClick(static_cast(0), Qt::Key_J, Qt::AltModifier); - QCOMPARE(menu1->selCount(), 0u); - QCOMPARE(menu2->selCount(), 0u); - QCOMPARE(menu3->selCount(), 1u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 1u); - QCOMPARE(item1_B->selCount(), 1u); - QCOMPARE(item2_C->selCount(), 1u); - QCOMPARE(item2_D->selCount(), 1u); + QCOMPARE(m_complexTriggerCount[1], 0); + QCOMPARE(m_complexTriggerCount[2], 0); + QCOMPARE(m_complexTriggerCount[3], 1); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 1); + QCOMPARE(m_complexTriggerCount['b'], 1); + QCOMPARE(m_complexTriggerCount['c'], 1); + QCOMPARE(m_complexTriggerCount['d'], 1); } #endif @@ -636,29 +593,33 @@ void tst_QMenuBar::check_accelKeys() #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_cursorKeys1() { - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // start with a ALT + 1 that activates the first popupmenu QTest::keyClick(static_cast(0), Qt::Key_1, Qt::AltModifier ); // the Popupmenu should be visible now - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); // Simulate a cursor key down click QTest::keyClick(static_cast(0), Qt::Key_Down ); // and an Enter key QTest::keyClick(static_cast(0), Qt::Key_Enter ); // Let's see if the correct slot is called... - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); // this shouldn't have been called - QCOMPARE(item1_B->selCount(), 1u); // and this should have been called by a signal now - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); // this shouldn't have been called + QCOMPARE(m_complexTriggerCount['b'], 1); // and this should have been called by a signal now + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); } #endif @@ -666,7 +627,11 @@ void tst_QMenuBar::check_cursorKeys1() #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_cursorKeys2() { - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // select popupmenu2 QTest::keyClick(static_cast(0), Qt::Key_2, Qt::AltModifier ); @@ -679,12 +644,12 @@ void tst_QMenuBar::check_cursorKeys2() // and an Enter key QTest::keyClick(static_cast(0), Qt::Key_Enter ); // Let's see if the correct slot is called... - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); // this shouldn't have been caled - QCOMPARE(item1_B->selCount(), 0u); // and this should have been called by a signal ow - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 1u); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); // this shouldn't have been caled + QCOMPARE(m_complexTriggerCount['b'], 0); // and this should have been called by a signal ow + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 1); } #endif @@ -695,7 +660,11 @@ void tst_QMenuBar::check_cursorKeys2() #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_cursorKeys3() { - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // select Popupmenu 2 QTest::keyClick(static_cast(0), Qt::Key_2, Qt::AltModifier ); @@ -706,12 +675,12 @@ void tst_QMenuBar::check_cursorKeys3() // and press ENTER QTest::keyClick(static_cast(0), Qt::Key_Enter ); // Let's see if the correct slot is called... - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); // this shouldn't have been called - QCOMPARE(item1_B->selCount(), 1u); // and this should have been called by a signal now - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); // this shouldn't have been called + QCOMPARE(m_complexTriggerCount['b'], 1); // and this should have been called by a signal now + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); } #endif @@ -727,7 +696,11 @@ void tst_QMenuBar::check_homeKey() QEXPECT_FAIL( "0", "Popupmenu should respond to a Home key", Abort ); - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // select Popupmenu 2 QTest::keyClick(static_cast(0), Qt::Key_2, Qt::AltModifier ); @@ -740,17 +713,17 @@ void tst_QMenuBar::check_homeKey() // and press ENTER QTest::keyClick(static_cast(0), Qt::Key_Enter ); // Let's see if the correct slot is called... -// QVERIFY2( item2_C->selCount() == 1, "Popupmenu should respond to a Home key" ); - QCOMPARE(item2_C->selCount(), 1u); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); - QCOMPARE(item2_E->selCount(), 0u); - QCOMPARE(item2_F->selCount(), 0u); - QCOMPARE(item2_G->selCount(), 0u); - QCOMPARE(item2_H->selCount(), 0u); +// QVERIFY2( m_complexActionTriggerCount['c'] == 1, "Popupmenu should respond to a Home key" ); + QCOMPARE(m_complexTriggerCount['c'], 1); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); + QCOMPARE(m_complexTriggerCount['e'], 0); + QCOMPARE(m_complexTriggerCount['f'], 0); + QCOMPARE(m_complexTriggerCount['g'], 0); + QCOMPARE(m_complexTriggerCount['h'], 0); } /*! @@ -765,7 +738,11 @@ void tst_QMenuBar::check_endKey() QEXPECT_FAIL( "0", "Popupmenu should respond to an End key", Abort ); - initComplexMenubar(); + QMainWindow w; + initWindowWithComplexMenuBar(w); + w.show(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); // select Popupmenu 2 QTest::keyClick(static_cast(0), Qt::Key_2, Qt::AltModifier ); @@ -775,17 +752,17 @@ void tst_QMenuBar::check_endKey() // and press ENTER QTest::keyClick(static_cast(0), Qt::Key_Enter ); // Let's see if the correct slot is called... -// QVERIFY2( item2_H->selCount() == 1, "Popupmenu should respond to an End key" ); - QCOMPARE(item2_H->selCount(), 1u);//, "Popupmenu should respond to an End key"); - QCOMPARE(menu3->selCount(), 0u); - QCOMPARE(menu4->selCount(), 0u); - QCOMPARE(item1_A->selCount(), 0u); - QCOMPARE(item1_B->selCount(), 0u); - QCOMPARE(item2_C->selCount(), 0u); - QCOMPARE(item2_D->selCount(), 0u); - QCOMPARE(item2_E->selCount(), 0u); - QCOMPARE(item2_F->selCount(), 0u); - QCOMPARE(item2_G->selCount(), 0u); +// QVERIFY2( m_complexActionTriggerCount['h'] == 1, "Popupmenu should respond to an End key" ); + QCOMPARE(m_complexTriggerCount['h'], 1);//, "Popupmenu should respond to an End key"); + QCOMPARE(m_complexTriggerCount[3], 0); + QCOMPARE(m_complexTriggerCount[4], 0); + QCOMPARE(m_complexTriggerCount['a'], 0); + QCOMPARE(m_complexTriggerCount['b'], 0); + QCOMPARE(m_complexTriggerCount['c'], 0); + QCOMPARE(m_complexTriggerCount['d'], 0); + QCOMPARE(m_complexTriggerCount['e'], 0); + QCOMPARE(m_complexTriggerCount['f'], 0); + QCOMPARE(m_complexTriggerCount['g'], 0); } /*! @@ -798,33 +775,38 @@ void tst_QMenuBar::check_endKey() #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_escKey() { - initComplexMenubar(); + QMainWindow w; + const TestMenu menu = initWindowWithComplexMenuBar(w); + w.show(); + w.setFocus(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); - QVERIFY( !pm1->isActiveWindow() ); - QVERIFY( !pm2->isActiveWindow() ); + QVERIFY( !menu.menus.at(0)->isActiveWindow() ); + QVERIFY( !menu.menus.at(1)->isActiveWindow() ); // select Popupmenu 2 QTest::keyClick(static_cast(0), Qt::Key_2, Qt::AltModifier ); - QVERIFY( !pm1->isActiveWindow() ); - QVERIFY( pm2->isActiveWindow() ); + QVERIFY( !menu.menus.at(0)->isActiveWindow() ); + QVERIFY( menu.menus.at(1)->isActiveWindow() ); // If we press ESC, the popup should disappear QTest::keyClick(static_cast(0), Qt::Key_Escape ); - QVERIFY( !pm1->isActiveWindow() ); - QVERIFY( !pm2->isActiveWindow() ); + QVERIFY( !menu.menus.at(0)->isActiveWindow() ); + QVERIFY( !menu.menus.at(1)->isActiveWindow() ); if (!QApplication::style()->inherits("QWindowsStyle")) return; // If we press Down the popupmenu should be active again QTest::keyClick(static_cast(0), Qt::Key_Down ); - QVERIFY( !pm1->isActiveWindow() ); - QVERIFY( pm2->isActiveWindow() ); + QVERIFY( !menu.menus.at(0)->isActiveWindow() ); + QVERIFY( menu.menus.at(1)->isActiveWindow() ); // and press ENTER - QTest::keyClick( pm2, Qt::Key_Enter ); + QTest::keyClick( menu.menus.at(1), Qt::Key_Enter ); // Let's see if the correct slot is called... - QVERIFY2( item2_C->selCount() == 1, "Expected item 2C to be selected" ); + QVERIFY2( m_complexTriggerCount['c'] == 1, "Expected item 2C to be selected" ); } #endif @@ -850,7 +832,7 @@ void tst_QMenuBar::check_escKey() // QFETCH( int, itemA_count ); // QFETCH( int, itemB_count ); -// initComplexMenubar(); +// // initComplexMenubar(); // QVERIFY( !pm1->isActiveWindow() ); // QVERIFY( !pm2->isActiveWindow() ); @@ -864,15 +846,15 @@ void tst_QMenuBar::check_escKey() // QTest::qWait(1000); // mouse.mouseEvent( QtTestMouse::MouseClick, pm1, popup_item, Qt::LeftButton ); -// QCOMPARE(menu3->selCount(), 0u); -// QCOMPARE(menu4->selCount(), 0u); -// QCOMPARE(item1_A->selCount(), (uint)itemA_count); // this option should have fired -// QCOMPARE(item1_B->selCount(), (uint)itemB_count); -// QCOMPARE(item2_C->selCount(), 0u); -// QCOMPARE(item2_D->selCount(), 0u); -// QCOMPARE(item2_E->selCount(), 0u); -// QCOMPARE(item2_F->selCount(), 0u); -// QCOMPARE(item2_G->selCount(), 0u); +// QCOMPARE(m_complexActionTriggerCount[3], 0); +// QCOMPARE(m_complexActionTriggerCount[4], 0); +// QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count); // this option should have fired +// QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count); +// QCOMPARE(m_complexActionTriggerCount['c'], 0); +// QCOMPARE(m_complexActionTriggerCount['d'], 0); +// QCOMPARE(m_complexActionTriggerCount['e'], 0); +// QCOMPARE(m_complexActionTriggerCount['f'], 0); +// QCOMPARE(m_complexActionTriggerCount['g'], 0); // } // void tst_QMenuBar::check_mouse2_data() @@ -918,28 +900,27 @@ void tst_QMenuBar::check_escKey() // QFETCH( int, itemH_count ); // QFETCH( int, menu3_count ); -// initComplexMenubar(); +// // initComplexMenubar(); // QtTestMouse mouse; // mouse.click( QtTestMouse::Menu, label, Qt::LeftButton ); // // check if the correct signals have fired -// QCOMPARE(menu3->selCount(), (uint)menu3_count); -// QCOMPARE(menu4->selCount(), 0u); -// QCOMPARE(item1_A->selCount(), (uint)itemA_count); -// QCOMPARE(item1_B->selCount(), (uint)itemB_count); -// QCOMPARE(item2_C->selCount(), (uint)itemC_count); -// QCOMPARE(item2_D->selCount(), (uint)itemD_count); -// QCOMPARE(item2_E->selCount(), (uint)itemE_count); -// QCOMPARE(item2_F->selCount(), (uint)itemF_count); -// QCOMPARE(item2_G->selCount(), (uint)itemG_count); -// QCOMPARE(item2_H->selCount(), (uint)itemH_count); +// QCOMPARE(m_complexActionTriggerCount[3], (uint)menu3_count); +// QCOMPARE(m_complexActionTriggerCount[4], 0); +// QCOMPARE(m_complexActionTriggerCount['a'], (uint)itemA_count); +// QCOMPARE(m_complexActionTriggerCount['b'], (uint)itemB_count); +// QCOMPARE(m_complexActionTriggerCount['c'], (uint)itemC_count); +// QCOMPARE(m_complexActionTriggerCount['d'], (uint)itemD_count); +// QCOMPARE(m_complexActionTriggerCount['e'], (uint)itemE_count); +// QCOMPARE(m_complexActionTriggerCount['f'], (uint)itemF_count); +// QCOMPARE(m_complexActionTriggerCount['g'], (uint)itemG_count); +// QCOMPARE(m_complexActionTriggerCount['h'], (uint)itemH_count); // } #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::allowActiveAndDisabled() { - mb->hide(); - mb->clear(); + QMenuBar menuBar; // Task 241043 : check that second menu is activated if only // disabled menu items are added @@ -950,31 +931,30 @@ void tst_QMenuBar::allowActiveAndDisabled() QAction *act = fileMenu.addAction("Disabled"); act->setEnabled(false); - mb->addMenu(&fileMenu); + menuBar.addMenu(&fileMenu); QMenu disabledMenu("Disabled"); disabledMenu.setEnabled(false); QMenu activeMenu("Active"); - mb->addMenu(&disabledMenu); - mb->addMenu(&activeMenu); - mb->show(); - + menuBar.addMenu(&disabledMenu); + menuBar.addMenu(&activeMenu); + centerOnScreen(&menuBar); + menuBar.show(); + QVERIFY(QTest::qWaitForWindowExposed(&menuBar)); // Here we verify that AllowActiveAndDisabled correctly skips // the disabled menu entry - QTest::keyClick(mb, Qt::Key_F, Qt::AltModifier ); + QTest::keyClick(&menuBar, Qt::Key_F, Qt::AltModifier ); QTest::keyClick(&fileMenu, (Qt::Key_Right)); if (qApp->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled)) - QCOMPARE(mb->activeAction()->text(), disabledMenu.title()); + QCOMPARE(menuBar.activeAction()->text(), disabledMenu.title()); else - QCOMPARE(mb->activeAction()->text(), activeMenu.title()); + QCOMPARE(menuBar.activeAction()->text(), activeMenu.title()); - QTest::keyClick(mb, (Qt::Key_Left)); + QTest::keyClick(&menuBar, (Qt::Key_Left)); if (qApp->style()->styleHint(QStyle::SH_Menu_AllowActiveAndDisabled)) - QCOMPARE(mb->activeAction()->text(), fileMenu.title()); + QCOMPARE(menuBar.activeAction()->text(), fileMenu.title()); else - QCOMPARE(mb->activeAction()->text(), fileMenu.title()); - - mb->hide(); + QCOMPARE(menuBar.activeAction()->text(), fileMenu.title()); } #endif @@ -985,33 +965,38 @@ void tst_QMenuBar::check_altPress() arg( qApp->style()->objectName() ).toLatin1()); } - initSimpleMenubar(); + QMainWindow w; + initWindowWithSimpleMenuBar(w); + w.show(); + w.setFocus(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); - qApp->setActiveWindow(mw); - mw->setFocus(); - - QTest::keyClick( mw, Qt::Key_Alt ); - - QVERIFY( ::qobject_cast(qApp->focusWidget()) ); + QTest::keyClick( &w, Qt::Key_Alt ); + QTRY_VERIFY( ::qobject_cast(qApp->focusWidget()) ); } // Qt/Mac,WinCE does not use the native popups/menubar #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_shortcutPress() { - initComplexMenubar(); + QMainWindow w; + const TestMenu menu = initWindowWithComplexMenuBar(w); + w.show(); + w.setFocus(); + QApplication::setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); - qApp->setActiveWindow(mw); - QCOMPARE(menu3->selCount(), 0u); - QTest::keyClick(mw, Qt::Key_E, Qt::AltModifier); + QCOMPARE(m_complexTriggerCount[3], 0); + QTest::keyClick(&w, Qt::Key_E, Qt::AltModifier); QTest::qWait(200); - QCOMPARE(menu3->selCount(), 1u); - QVERIFY(!mb->activeAction()); + QCOMPARE(m_complexTriggerCount[3], 1); + QVERIFY(!w.menuBar()->activeAction()); - QTest::keyClick(mw, Qt::Key_1, Qt::AltModifier ); - QVERIFY(pm1->isActiveWindow()); - QTest::keyClick(mb, Qt::Key_2); - QVERIFY(pm1->isActiveWindow()); + QTest::keyClick(&w, Qt::Key_1, Qt::AltModifier ); + QVERIFY(menu.menus.at(0)->isActiveWindow()); + QTest::keyClick(&w, Qt::Key_2); + QVERIFY(menu.menus.at(0)->isActiveWindow()); } #endif @@ -1038,27 +1023,29 @@ private: #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE) void tst_QMenuBar::check_menuPosition() { + QMainWindow w; + Menu menu; - initComplexMenubar(); menu.setTitle("&menu"); - QRect availRect = QApplication::desktop()->availableGeometry(mw); - QRect screenRect = QApplication::desktop()->screenGeometry(mw); + QRect availRect = QApplication::desktop()->availableGeometry(&w); + QRect screenRect = QApplication::desktop()->screenGeometry(&w); while(menu.sizeHint().height() < (screenRect.height()*2/3)) { menu.addAction("item"); } - QAction *menu_action = mw->menuBar()->addMenu(&menu); - - qApp->setActiveWindow(mw); - qApp->processEvents(); + QAction *menu_action = w.menuBar()->addMenu(&menu); + centerOnScreen(&w); + w.show(); + qApp->setActiveWindow(&w); + QVERIFY(QTest::qWaitForWindowActive(&w)); //the menu should be below the menubar item { - mw->move(availRect.topLeft()); - QRect mbItemRect = mw->menuBar()->actionGeometry(menu_action); - mbItemRect.moveTo(mw->menuBar()->mapToGlobal(mbItemRect.topLeft())); - QTest::keyClick(mw, Qt::Key_M, Qt::AltModifier ); + w.move(availRect.topLeft()); + QRect mbItemRect = w.menuBar()->actionGeometry(menu_action); + mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft())); + QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier ); QVERIFY(menu.isActiveWindow()); QCOMPARE(menu.pos(), QPoint(mbItemRect.x(), mbItemRect.bottom() + 1)); menu.close(); @@ -1066,10 +1053,10 @@ void tst_QMenuBar::check_menuPosition() //the menu should be above the menubar item { - mw->move(0,screenRect.bottom() - screenRect.height()/4); //just leave some place for the menubar - QRect mbItemRect = mw->menuBar()->actionGeometry(menu_action); - mbItemRect.moveTo(mw->menuBar()->mapToGlobal(mbItemRect.topLeft())); - QTest::keyClick(mw, Qt::Key_M, Qt::AltModifier ); + w.move(0,screenRect.bottom() - screenRect.height()/4); //just leave some place for the menubar + QRect mbItemRect = w.menuBar()->actionGeometry(menu_action); + mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft())); + QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier ); QVERIFY(menu.isActiveWindow()); QCOMPARE(menu.pos(), QPoint(mbItemRect.x(), mbItemRect.top() - menu.height())); menu.close(); @@ -1077,10 +1064,10 @@ void tst_QMenuBar::check_menuPosition() //the menu should be on the side of the menubar item and should be "stuck" to the bottom of the screen { - mw->move(0,screenRect.y() + screenRect.height()/2); //put it in the middle - QRect mbItemRect = mw->menuBar()->actionGeometry(menu_action); - mbItemRect.moveTo(mw->menuBar()->mapToGlobal(mbItemRect.topLeft())); - QTest::keyClick(mw, Qt::Key_M, Qt::AltModifier ); + w.move(0,screenRect.y() + screenRect.height()/2); //put it in the middle + QRect mbItemRect = w.menuBar()->actionGeometry(menu_action); + mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft())); + QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier ); QVERIFY(menu.isActiveWindow()); QPoint firstPoint = QPoint(mbItemRect.right()+1, screenRect.bottom() - menu.height() + 1); QPoint secondPoint = QPoint(mbItemRect.right()+1, availRect.bottom() - menu.height() + 1); @@ -1093,9 +1080,9 @@ void tst_QMenuBar::check_menuPosition() LayoutDirectionSaver directionSaver(Qt::RightToLeft); menu.clear(); QObject::connect(&menu, SIGNAL(aboutToShow()), &menu, SLOT(addActions())); - QRect mbItemRect = mw->menuBar()->actionGeometry(menu_action); - mbItemRect.moveTo(mw->menuBar()->mapToGlobal(mbItemRect.topLeft())); - QTest::keyClick(mw, Qt::Key_M, Qt::AltModifier ); + QRect mbItemRect = w.menuBar()->actionGeometry(menu_action); + mbItemRect.moveTo(w.menuBar()->mapToGlobal(mbItemRect.topLeft())); + QTest::keyClick(&w, Qt::Key_M, Qt::AltModifier ); QVERIFY(menu.isActiveWindow()); QCOMPARE(menu.geometry().right(), mbItemRect.right()); menu.close(); @@ -1104,9 +1091,9 @@ void tst_QMenuBar::check_menuPosition() # ifndef QTEST_NO_CURSOR // QTBUG-28031: Click at bottom-right corner. { - mw->move(400, 200); + w.move(400, 200); LayoutDirectionSaver directionSaver(Qt::RightToLeft); - QMenuBar *mb = mw->menuBar(); + QMenuBar *mb = w.menuBar(); const QPoint localPos = mb->actionGeometry(menu.menuAction()).bottomRight() - QPoint(1, 1); const QPoint globalPos = mb->mapToGlobal(localPos); QCursor::setPos(globalPos); @@ -1123,6 +1110,7 @@ void tst_QMenuBar::task223138_triggered() { //we create a window with submenus and we check that both menubar and menus get the triggered signal QMainWindow win; + centerOnScreen(&win); QMenu *menu = win.menuBar()->addMenu("test"); QAction *top = menu->addAction("toplevelaction"); QMenu *submenu = menu->addMenu("nested menu"); @@ -1162,8 +1150,10 @@ void tst_QMenuBar::task256322_highlight() file2->setText("file2"); QAction *nothing = win.menuBar()->addAction("nothing"); + centerOnScreen(&win); win.show(); - QTest::qWait(200); + QApplication::setActiveWindow(&win); + QVERIFY(QTest::qWaitForWindowActive(&win)); QTest::mousePress(win.menuBar(), Qt::LeftButton, 0, win.menuBar()->actionGeometry(file).center()); QTest::mouseMove(win.menuBar(), win.menuBar()->actionGeometry(file).center()); @@ -1184,12 +1174,11 @@ void tst_QMenuBar::task256322_highlight() QTest::mouseMove(win.menuBar(), nothingCenter); QTRY_VERIFY(!menu2.isVisible()); QVERIFY(!menu.isVisible()); - QAction *activeAction = win.menuBar()->activeAction(); #ifdef Q_OS_MAC - if ((QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) && (activeAction != nothing)) + if ((QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) && (win.menuBar()->activeAction() != nothing)) QEXPECT_FAIL("", "QTBUG-30565: Unstable test", Continue); #endif - QCOMPARE(activeAction, nothing); + QTRY_COMPARE(win.menuBar()->activeAction(), nothing); QTest::mouseRelease(win.menuBar(), Qt::LeftButton, 0, nothingCenter); } @@ -1232,6 +1221,7 @@ void tst_QMenuBar::menubarSizeHint() const int vmargin = style.pixelMetric(QStyle::PM_MenuBarVMargin); const int spacing = style.pixelMetric(QStyle::PM_MenuBarItemSpacing); + centerOnScreen(&mb); mb.show(); QRect result; foreach(QAction *action, mb.actions()) { @@ -1272,6 +1262,7 @@ void tst_QMenuBar::taskQTBUG4965_escapeEaten() QMenu menu("menu1"); QAction *first = menubar.addMenu(&menu); menu.addAction("quit", &menubar, SLOT(close()), QKeySequence("ESC")); + centerOnScreen(&menubar); menubar.show(); QApplication::setActiveWindow(&menubar); QVERIFY(QTest::qWaitForWindowExposed(&menubar)); @@ -1299,6 +1290,7 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions() QAction * m = menubar.addAction( "&m" ); QAction * a = menubar.addAction( "&a" ); + centerOnScreen(&menubar); menubar.show(); QApplication::setActiveWindow(&menubar); QVERIFY(QTest::qWaitForWindowActive(&menubar)); @@ -1318,5 +1310,28 @@ void tst_QMenuBar::taskQTBUG11823_crashwithInvisibleActions() QCOMPARE(menubar.activeAction(), m); //the active action shouldn't have changed } +void tst_QMenuBar::closeOnSecondClick() // QTBUG-32807, menu should close on 2nd click. +{ + QMainWindow mainWindow; + mainWindow.resize(300, 200); + centerOnScreen(&mainWindow); +#ifndef QT_NO_CURSOR + QCursor::setPos(mainWindow.geometry().topLeft() - QPoint(100, 0)); +#endif + QMenuBar *menuBar = mainWindow.menuBar(); + menuBar->setNativeMenuBar(false); + QMenu *fileMenu = menuBar->addMenu(QStringLiteral("closeOnSecondClick")); + fileMenu->addAction(QStringLiteral("Quit")); + mainWindow.show(); + QApplication::setActiveWindow(&mainWindow); + QVERIFY(QTest::qWaitForWindowActive(&mainWindow)); + const QPoint center = menuBar->actionGeometry(fileMenu->menuAction()).center(); + QTest::mouseMove(menuBar, center); + QTest::mouseClick(menuBar, Qt::LeftButton, 0, center); + QTRY_VERIFY(fileMenu->isVisible()); + QTest::mouseClick(menuBar, Qt::LeftButton, 0, center); + QTRY_VERIFY(!fileMenu->isVisible()); +} + QTEST_MAIN(tst_QMenuBar) #include "tst_qmenubar.moc"