diff --git a/CMakeLists.txt b/CMakeLists.txt index c7e86cd6d8a..b6e03deb43e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,8 +101,8 @@ else() endif() install(TARGETS OptionalSvg EXPORT QtCreator) -find_package(LLVM QUIET) find_package(Clang COMPONENTS libclang QUIET) +find_package(LLVM QUIET) if (APPLE) find_library(FWCoreFoundation CoreFoundation) diff --git a/src/app/main.cpp b/src/app/main.cpp index 359bb673b58..c7b5aff49c3 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -523,6 +523,8 @@ int main(int argc, char **argv) } } + app.setDesktopFileName("org.qt-project.qtcreator.desktop"); + // Make sure we honor the system's proxy settings QNetworkProxyFactory::setUseSystemConfiguration(true); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index aeee344aeae..6c29cf53fd1 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -174,7 +174,7 @@ CMakeTargetNode::CMakeTargetNode(const Utils::FilePath &directory, const QString setPriority(Node::DefaultProjectPriority + 900); setIcon(QIcon(":/projectexplorer/images/build.png")); // TODO: Use proper icon! setListInProject(false); - setIsProduct(); + setProductType(ProductType::Other); } QString CMakeTargetNode::tooltip() const diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index 6c33b8dafe2..f920ffc3891 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -117,7 +117,10 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget connect(copyAction, &QAction::triggered, this, &QPlainTextEdit::copy); connect(pasteAction, &QAction::triggered, this, &QPlainTextEdit::paste); connect(selectAllAction, &QAction::triggered, this, &QPlainTextEdit::selectAll); - connect(this, &QPlainTextEdit::blockCountChanged, this, &OutputWindow::filterNewContent); + connect(this, &QPlainTextEdit::blockCountChanged, this, [this] { + if (!d->filterText.isEmpty()) + filterNewContent(); + }); connect(this, &QPlainTextEdit::undoAvailable, undoAction, &QAction::setEnabled); connect(this, &QPlainTextEdit::redoAvailable, redoAction, &QAction::setEnabled); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 66dc416f1ba..8201e13a71e 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2288,15 +2288,20 @@ void WatchModel::showEditValue(const WatchItem *item) QTC_ASSERT(0 < nbytes && nbytes < 10000 * 10000, return); QTC_ASSERT(0 < imformat && imformat < 32, return); QImage im(width, height, QImage::Format(imformat)); - std::memcpy(im.bits(), bits, nbytes); - auto v = m_separatedView->prepareObject(item); - v->setInfo(item->address ? - tr("%1 Object at %2").arg(item->type, item->hexAddress()) : - tr("%1 Object at Unknown Address").arg(item->type) + " " + - ImageViewer::tr("Size: %1x%2, %3 byte, format: %4, depth: %5") - .arg(width).arg(height).arg(nbytes).arg(im.format()).arg(im.depth()) - ); - v->setImage(im); + const qsizetype size = im.sizeInBytes(); + // If our computation of image size doesn't fit the client's + // chances are that we can't properly display it either. + if (size == nbytes) { + std::memcpy(im.bits(), bits, nbytes); + auto v = m_separatedView->prepareObject(item); + v->setInfo(item->address ? + tr("%1 Object at %2").arg(item->type, item->hexAddress()) : + tr("%1 Object at Unknown Address").arg(item->type) + " " + + ImageViewer::tr("Size: %1x%2, %3 byte, format: %4, depth: %5") + .arg(width).arg(height).arg(nbytes).arg(im.format()).arg(im.depth()) + ); + v->setImage(im); + } } else if (format == DisplayLatin1String || format == DisplayUtf8String || format == DisplayUtf16String diff --git a/src/plugins/designer/resourcehandler.cpp b/src/plugins/designer/resourcehandler.cpp index a86bf217927..392b632a8f8 100644 --- a/src/plugins/designer/resourcehandler.cpp +++ b/src/plugins/designer/resourcehandler.cpp @@ -103,26 +103,37 @@ void ResourceHandler::updateResourcesHelper(bool updateProjectResources) // Find the (sub-)project the file belongs to. We don't want to find resources // from other parts of the project tree, e.g. via a qmake subdirs project. - ProjectNode *projectNode = project->rootProjectNode(); - Node * const fileNode = projectNode->findNode([&fileName](const Node *n) { + Node * const fileNode = project->rootProjectNode()->findNode([&fileName](const Node *n) { return n->filePath().toString() == fileName; }); + ProjectNode *projectNodeForUiFile = nullptr; if (fileNode) { // We do not want qbs groups or qmake .pri files here, as they contain only a subset // of the relevant files. - projectNode = fileNode->parentProjectNode(); - while (projectNode && !projectNode->isProduct()) - projectNode = projectNode->parentProjectNode(); + projectNodeForUiFile = fileNode->parentProjectNode(); + while (projectNodeForUiFile && !projectNodeForUiFile->isProduct()) + projectNodeForUiFile = projectNodeForUiFile->parentProjectNode(); } - if (!projectNode) - projectNode = project->rootProjectNode(); + if (!projectNodeForUiFile) + projectNodeForUiFile = project->rootProjectNode(); + + const auto useQrcFile = [projectNodeForUiFile, project](const Node *qrcNode) { + if (projectNodeForUiFile == project->rootProjectNode()) + return true; + ProjectNode *projectNodeForQrcFile = qrcNode->parentProjectNode(); + while (projectNodeForQrcFile && !projectNodeForQrcFile->isProduct()) + projectNodeForQrcFile = projectNodeForQrcFile->parentProjectNode(); + return !projectNodeForQrcFile + || projectNodeForQrcFile == projectNodeForUiFile + || projectNodeForQrcFile->productType() != ProductType::App; + }; QStringList projectQrcFiles; - projectNode->forEachNode([&](FileNode *node) { - if (node->fileType() == FileType::Resource) + project->rootProjectNode()->forEachNode([&](FileNode *node) { + if (node->fileType() == FileType::Resource && useQrcFile(node)) projectQrcFiles.append(node->filePath().toString()); }, [&](FolderNode *node) { - if (dynamic_cast(node)) + if (dynamic_cast(node) && useQrcFile(node)) projectQrcFiles.append(node->filePath().toString()); }); // Check if the user has chosen to update the lacking resource inside designer @@ -134,7 +145,7 @@ void ResourceHandler::updateResourcesHelper(bool updateProjectResources) } if (!qrcPathsToBeAdded.isEmpty()) { m_handlingResources = true; - projectNode->addFiles(qrcPathsToBeAdded); + projectNodeForUiFile->addFiles(qrcPathsToBeAdded); m_handlingResources = false; projectQrcFiles += qrcPathsToBeAdded; } diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 0bea9c38102..68e11a178de 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -57,6 +57,8 @@ enum class FileType : quint16 { FileTypeSize }; +enum class ProductType { App, Lib, Other, None }; + enum ProjectAction { // Special value to indicate that the actions are handled by the parent InheritedFromParent, @@ -379,7 +381,8 @@ public: virtual QVariant data(Core::Id role) const; virtual bool setData(Core::Id role, const QVariant &value) const; - bool isProduct() const { return m_isProduct; } + bool isProduct() const { return m_productType != ProductType::None; } + ProductType productType() const { return m_productType; } // TODO: Currently used only for "Build for current run config" functionality, but we should // probably use it to centralize the node-specific "Build" functionality that @@ -391,13 +394,13 @@ public: void setFallbackData(Core::Id key, const QVariant &value); protected: - void setIsProduct() { m_isProduct = true; } + void setProductType(ProductType type) { m_productType = type; } QString m_target; private: - bool m_isProduct = false; QHash m_fallbackData; // Used in data(), unless overridden. + ProductType m_productType = ProductType::None; }; class PROJECTEXPLORER_EXPORT ContainerNode : public FolderNode diff --git a/src/plugins/qbsprojectmanager/qbsnodes.cpp b/src/plugins/qbsprojectmanager/qbsnodes.cpp index 719897ec78a..4a7f5fa5418 100644 --- a/src/plugins/qbsprojectmanager/qbsnodes.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodes.cpp @@ -328,7 +328,14 @@ QbsProductNode::QbsProductNode(const qbs::ProductData &prd) : { static QIcon productIcon = Core::FileIconProvider::directoryIcon(Constants::QBS_PRODUCT_OVERLAY_ICON); setIcon(productIcon); - setIsProduct(); + if (m_qbsProductData.isRunnable()) { + setProductType(ProductType::App); + } else if (m_qbsProductData.type().contains("dynamiclibrary") + || m_qbsProductData.type().contains("staticlibrary")) { + setProductType(ProductType::Lib); + } else { + setProductType(ProductType::Other); + } } bool QbsProductNode::supportsAction(ProjectAction action, const Node *node) const diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index a51c09f0ac2..c2a15c9eaf9 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -257,7 +257,14 @@ FolderNode::AddNewInformation QmakePriFileNode::addNewInformation(const QStringL QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FilePath &filePath, QmakeProFile *pf) : QmakePriFileNode(project, this, filePath, pf) { - setIsProduct(); + if (projectType() == ProjectType::ApplicationTemplate) { + setProductType(ProductType::App); + } else if (projectType() == ProjectType::SharedLibraryTemplate + || projectType() == ProjectType::StaticLibraryTemplate) { + setProductType(ProductType::Lib); + } else if (projectType() != ProjectType::SubDirsTemplate) { + setProductType(ProductType::Other); + } } bool QmakeProFileNode::showInSimpleTree() const diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 2337f4fc4ff..08398f14fab 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -662,3 +662,12 @@ def addCPlusPlusFile(name, template, projectName, forceOverwrite=False, addToVCS buttonToClick = 'Cancel' clickButton("{text='%s' type='QPushButton' unnamed='1' visible='1' window=%s}" % (buttonToClick, overwriteDialog)) + +# if one of the parameters is set to 0 or below the respective parsing won't be waited for +def waitForProjectParsing(projectParsingTimeout=10000, codemodelParsingTimeout=10000): + if projectParsingTimeout > 0: + runButton = findObject(':*Qt Creator.Run_Core::Internal::FancyToolButton') + # Wait for parsing to complete + waitFor("runButton.enabled", projectParsingTimeout) + if codemodelParsingTimeout > 0: + progressBarWait(codemodelParsingTimeout) diff --git a/tests/system/suite_CSUP/tst_CSUP04/test.py b/tests/system/suite_CSUP/tst_CSUP04/test.py index 196d25bc1d8..143e3fe8126 100644 --- a/tests/system/suite_CSUP/tst_CSUP04/test.py +++ b/tests/system/suite_CSUP/tst_CSUP04/test.py @@ -44,7 +44,7 @@ def main(): # open example project openQmakeProject(examplePath) # wait for parsing to complete - progressBarWait(30000) + waitForProjectParsing() checkCodeModelSettings(useClang) # open .cpp file in editor if not openDocument("openglwindow.Sources.main\\.cpp"): diff --git a/tests/system/suite_CSUP/tst_CSUP05/test.py b/tests/system/suite_CSUP/tst_CSUP05/test.py index c9f3cb892d1..3e686b0509a 100644 --- a/tests/system/suite_CSUP/tst_CSUP05/test.py +++ b/tests/system/suite_CSUP/tst_CSUP05/test.py @@ -43,7 +43,7 @@ def main(): # open example project openQmakeProject(examplePath) # wait for parsing to complete - progressBarWait(30000) + waitForProjectParsing() checkCodeModelSettings(useClang) # open .cpp file in editor if not openDocument("openglwindow.Sources.main\\.cpp"): diff --git a/tests/system/suite_WELP/tst_WELP02/test.py b/tests/system/suite_WELP/tst_WELP02/test.py index 7fe8b3d4648..b44f0382dce 100644 --- a/tests/system/suite_WELP/tst_WELP02/test.py +++ b/tests/system/suite_WELP/tst_WELP02/test.py @@ -99,7 +99,7 @@ def main(): # select "Open project" and select a project examplePath = os.path.join(prepareTemplate(sourceExample), "animation.pro") openQmakeProject(examplePath, fromWelcome = True) - progressBarWait(30000) + waitForProjectParsing() test.verify(checkIfObjectExists("{column='0' container=':Qt Creator_Utils::NavigationTreeView'" " text~='animation( \(.*\))?' type='QModelIndex'}"), "Verifying: The project is opened in 'Edit' mode after configuring.") diff --git a/tests/system/suite_editors/tst_basic_cpp_support/test.py b/tests/system/suite_editors/tst_basic_cpp_support/test.py index 69e43adf7fe..425512c4c7c 100644 --- a/tests/system/suite_editors/tst_basic_cpp_support/test.py +++ b/tests/system/suite_editors/tst_basic_cpp_support/test.py @@ -42,7 +42,7 @@ def main(): if not startedWithoutPluginError(): return openQmakeProject(proFile) - progressBarWait(20000) + waitForProjectParsing() selectFromLocator("dummy.cpp") ## Waiting for a solution from Froglogic to make the below work. diff --git a/tests/system/suite_general/tst_build_speedcrunch/test.py b/tests/system/suite_general/tst_build_speedcrunch/test.py index 32a132ad639..e3543d55fae 100644 --- a/tests/system/suite_general/tst_build_speedcrunch/test.py +++ b/tests/system/suite_general/tst_build_speedcrunch/test.py @@ -42,7 +42,7 @@ def main(): if not startedWithoutPluginError(): return openQmakeProject(SpeedCrunchPath, [Targets.DESKTOP_4_8_7_DEFAULT]) - progressBarWait(30000) + waitForProjectParsing() fancyToolButton = waitForObject(":*Qt Creator_Core::Internal::FancyToolButton") diff --git a/tests/system/suite_general/tst_cmake_speedcrunch/test.py b/tests/system/suite_general/tst_cmake_speedcrunch/test.py index afc196abb8e..2d9a3e2defd 100644 --- a/tests/system/suite_general/tst_cmake_speedcrunch/test.py +++ b/tests/system/suite_general/tst_cmake_speedcrunch/test.py @@ -60,7 +60,7 @@ def main(): test.fatal("Could not open/create cmake project - leaving test") invokeMenuItem("File", "Exit") return - progressBarWait(30000) + waitForProjectParsing() naviTreeView = "{column='0' container=':Qt Creator_Utils::NavigationTreeView' text~='%s' type='QModelIndex'}" if cmakeSupportsServerMode(): treeFile = "projecttree_speedcrunch_server.tsv" diff --git a/tests/system/suite_general/tst_rename_file/test.py b/tests/system/suite_general/tst_rename_file/test.py index 9d46be1d37f..cb5d434fe15 100644 --- a/tests/system/suite_general/tst_rename_file/test.py +++ b/tests/system/suite_general/tst_rename_file/test.py @@ -46,7 +46,7 @@ def main(): "OTHER_FILES += example.qml") invokeMenuItem("File", "Save All") invokeMenuItem("File", "Close All") - progressBarWait() + waitForProjectParsing() for filetype, filename in [["Headers", "person.h"], ["Sources", "main.cpp"], ["Sources", "person.cpp"], @@ -66,7 +66,7 @@ def main(): renameFile(templateDir, usedProFile, projectName + "." + tempFiletype, previous, filename) # QTCREATORBUG-13176 does update the navigator async - progressBarWait() + waitForProjectParsing() if filetype == "Headers": verifyRenamedIncludes(templateDir, "main.cpp", previous, filename) verifyRenamedIncludes(templateDir, "person.cpp", previous, filename) diff --git a/tests/system/suite_general/tst_session_handling/test.py b/tests/system/suite_general/tst_session_handling/test.py index 3a536975f2e..702273b265f 100644 --- a/tests/system/suite_general/tst_session_handling/test.py +++ b/tests/system/suite_general/tst_session_handling/test.py @@ -40,7 +40,7 @@ def main(): checkWelcomePage(sessionName, True) for project in projects: openQmakeProject(project, [Targets.DESKTOP_5_6_1_DEFAULT]) - progressBarWait(20000) + waitForProjectParsing() checkNavigator(52, "Verifying whether all projects have been opened.") openDocument("animation.Resources.animation\\.qrc./animation.basics.animators\\.qml") openDocument("keyinteraction.Sources.main\\.cpp") diff --git a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py index 58ef85e3331..c1e5105ba1a 100644 --- a/tests/system/suite_qtquick/tst_qtquick_creation4/test.py +++ b/tests/system/suite_qtquick/tst_qtquick_creation4/test.py @@ -33,7 +33,7 @@ def main(): # using a temporary directory won't mess up a potentially existing createNewQmlExtension(tempDir(), [target]) # wait for parsing to complete - progressBarWait(30000) + waitForProjectParsing() test.log("Building project Qt Quick 2 Extension Plugin (%s)" % Targets.getStringForTarget(target)) invokeMenuItem("Build","Build All")