/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "qmakenodetreebuilder.h" #include "qmakeproject.h" #include #include #include #include #include #include #include #include using namespace Core; using namespace ProjectExplorer; using namespace QtSupport; using namespace Utils; namespace { // Static cached data in struct QmakeStaticData providing information and icons // for file types and the project. Do some magic via qAddPostRoutine() // to make sure the icons do not outlive QApplication, triggering warnings on X11. class FileTypeDataStorage { public: FileType type; const char *typeName; const char *icon; const char *addFileFilter; }; const FileTypeDataStorage fileTypeDataStorage[] = { { FileType::Header, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Headers"), ProjectExplorer::Constants::FILEOVERLAY_H, "*.h; *.hh; *.hpp; *.hxx;"}, { FileType::Source, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Sources"), ProjectExplorer::Constants::FILEOVERLAY_CPP, "*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++;" }, { FileType::Form, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Forms"), ProjectExplorer::Constants::FILEOVERLAY_UI, "*.ui;" }, { FileType::StateChart, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "State charts"), ProjectExplorer::Constants::FILEOVERLAY_SCXML, "*.scxml;" }, { FileType::Resource, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Resources"), ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" }, { FileType::QML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "QML"), ProjectExplorer::Constants::FILEOVERLAY_QML, "*.qml;" }, { FileType::Unknown, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFile", "Other files"), ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" } }; class QmakeStaticData { public: class FileTypeData { public: FileTypeData(FileType t = FileType::Unknown, const QString &tN = QString(), const QString &aff = QString(), const QIcon &i = QIcon()) : type(t), typeName(tN), addFileFilter(aff), icon(i) { } FileType type; QString typeName; QString addFileFilter; QIcon icon; }; QmakeStaticData(); QVector fileTypeData; QIcon projectIcon; }; void clearQmakeStaticData(); QmakeStaticData::QmakeStaticData() { // File type data const unsigned count = sizeof(fileTypeDataStorage)/sizeof(FileTypeDataStorage); fileTypeData.reserve(count); for (unsigned i = 0 ; i < count; ++i) { const QString desc = QCoreApplication::translate("QmakeProjectManager::QmakePriFile", fileTypeDataStorage[i].typeName); const QString filter = QString::fromUtf8(fileTypeDataStorage[i].addFileFilter); fileTypeData.push_back(QmakeStaticData::FileTypeData(fileTypeDataStorage[i].type, desc, filter, Core::FileIconProvider::directoryIcon(QLatin1String(fileTypeDataStorage[i].icon)))); } // Project icon projectIcon = Core::FileIconProvider::directoryIcon(ProjectExplorer::Constants::FILEOVERLAY_QT); qAddPostRoutine(clearQmakeStaticData); } Q_GLOBAL_STATIC(QmakeStaticData, qmakeStaticData) void clearQmakeStaticData() { qmakeStaticData()->fileTypeData.clear(); qmakeStaticData()->projectIcon = QIcon(); } } // namespace namespace QmakeProjectManager { static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const FileNameList &toExclude) { QTC_ASSERT(pri, return); QTC_ASSERT(node, return); node->setDisplayName(pri->displayName()); node->setIcon(qmakeStaticData()->projectIcon); // .pro/.pri-file itself: node->addNode(std::make_unique(pri->filePath(), FileType::Project, false)); // other normal files: const QVector &fileTypes = qmakeStaticData()->fileTypeData; for (int i = 0; i < fileTypes.size(); ++i) { FileType type = fileTypes.at(i).type; const QSet &newFilePaths = Utils::filtered(pri->files(type), [&toExclude](const Utils::FileName &fn) { return !Utils::contains(toExclude, [&fn](const Utils::FileName &ex) { return fn.isChildOf(ex); }); }); if (!newFilePaths.isEmpty()) { auto vfolder = std::make_unique(pri->filePath().parentDir(), Node::DefaultVirtualFolderPriority - i); vfolder->setIcon(fileTypes.at(i).icon); vfolder->setDisplayName(fileTypes.at(i).typeName); vfolder->setAddFileFilter(fileTypes.at(i).addFileFilter); if (type == FileType::Resource) { for (const FileName &file : newFilePaths) { auto vfs = pri->project()->qmakeVfs(); QString contents; QString errorMessage; // Prefer the cumulative file if it's non-empty, based on the assumption // that it contains more "stuff". int cid = vfs->idForFileName(file.toString(), QMakeVfs::VfsCumulative); vfs->readFile(cid, &contents, &errorMessage); // If the cumulative evaluation botched the file too much, try the exact one. if (contents.isEmpty()) { int eid = vfs->idForFileName(file.toString(), QMakeVfs::VfsExact); vfs->readFile(eid, &contents, &errorMessage); } vfolder->addNode(std::make_unique(file, false, contents, vfolder.get())); } } else { for (const FileName &fn : newFilePaths) { // Qmake will flag everything in SOURCES as source, even when the // qt quick compiler moves qrc files into it:-/ Get better data based on // the filename. type = FileNode::fileTypeForFileName(fn); vfolder->addNestedNode(std::make_unique(fn, type, false)); } for (FolderNode *fn : vfolder->folderNodes()) fn->compress(); } node->addNode(std::move(vfolder)); } } // Virtual folders: for (QmakePriFile *c : pri->children()) { std::unique_ptr newNode; if (auto pf = dynamic_cast(c)) newNode = std::make_unique(c->project(), c->filePath(), pf); else newNode = std::make_unique(c->project(), node->proFileNode(), c->filePath(), c); createTree(c, newNode.get(), toExclude); node->addNode(std::move(newNode)); } } std::unique_ptr QmakeNodeTreeBuilder::buildTree(QmakeProject *project) { // Remove qmake implementation details that litter up the project data: Target *t = project->activeTarget(); Kit *k = t ? t->kit() : KitManager::defaultKit(); BaseQtVersion *qt = k ? QtKitInformation::qtVersion(k) : nullptr; const FileNameList toExclude = qt ? qt->directoriesToIgnoreInProjectTree() : FileNameList(); auto root = std::make_unique(project, project->projectFilePath(), project->rootProFile()); createTree(project->rootProFile(), root.get(), toExclude); return root; } } // namespace QmakeProjectManager