/**************************************************************************** ** ** Copyright (C) 2016 Dmitry Savchenko ** Copyright (C) 2016 Vasiliy Sorokin ** 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 "todoitemsprovider.h" #include "constants.h" #include "cpptodoitemsscanner.h" #include "qmljstodoitemsscanner.h" #include "todoitemsmodel.h" #include "todoitemsscanner.h" #include #include #include #include #include #include #include #include #include using namespace ProjectExplorer; using namespace Utils; namespace Todo { namespace Internal { TodoItemsProvider::TodoItemsProvider(Settings settings, QObject *parent) : QObject(parent), m_settings(settings) { setupItemsModel(); setupStartupProjectBinding(); setupCurrentEditorBinding(); setupUpdateListTimer(); createScanners(); } TodoItemsModel *TodoItemsProvider::todoItemsModel() { return m_itemsModel; } void TodoItemsProvider::settingsChanged(const Settings &newSettings) { if (newSettings.keywords != m_settings.keywords) { foreach (TodoItemsScanner *scanner, m_scanners) scanner->setParams(newSettings.keywords); } m_settings = newSettings; updateList(); } void TodoItemsProvider::projectSettingsChanged(Project *project) { Q_UNUSED(project) updateList(); } void TodoItemsProvider::updateList() { m_itemsList.clear(); // Show only items of the current file if any if (m_settings.scanningScope == ScanningScopeCurrentFile) { if (m_currentEditor) m_itemsList = m_itemsHash.value(m_currentEditor->document()->filePath()); // Show only items of the current sub-project } else if (m_settings.scanningScope == ScanningScopeSubProject) { if (m_startupProject) setItemsListWithinSubproject(); // Show only items of the startup project if any } else if (m_startupProject) { setItemsListWithinStartupProject(); } m_itemsModel->todoItemsListUpdated(); } void TodoItemsProvider::createScanners() { qRegisterMetaType >("QList"); if (CppTools::CppModelManager::instance()) m_scanners << new CppTodoItemsScanner(m_settings.keywords, this); if (QmlJS::ModelManagerInterface::instance()) m_scanners << new QmlJsTodoItemsScanner(m_settings.keywords, this); foreach (TodoItemsScanner *scanner, m_scanners) { connect(scanner, &TodoItemsScanner::itemsFetched, this, &TodoItemsProvider::itemsFetched, Qt::QueuedConnection); } } void TodoItemsProvider::setItemsListWithinStartupProject() { const auto filePaths = Utils::toSet(m_startupProject->files(Project::SourceFiles)); QVariantMap settings = m_startupProject->namedSettings(Constants::SETTINGS_NAME_KEY).toMap(); for (auto it = m_itemsHash.cbegin(), end = m_itemsHash.cend(); it != end; ++it) { const FilePath filePath = it.key(); if (filePaths.contains(filePath)) { bool skip = false; for (const QVariant &pattern : settings[Constants::EXCLUDES_LIST_KEY].toList()) { QRegularExpression re(pattern.toString()); if (filePath.toString().indexOf(re) != -1) { skip = true; break; } } if (!skip) m_itemsList << it.value(); } } } void TodoItemsProvider::setItemsListWithinSubproject() { // TODO prefer current editor as source of sub-project const Node *node = ProjectTree::currentNode(); if (node) { ProjectNode *projectNode = node->parentProjectNode(); if (projectNode) { // FIXME: The name doesn't match the implementation that lists all files. QSet subprojectFileNames; projectNode->forEachGenericNode([&](Node *node) { subprojectFileNames.insert(node->filePath()); }); // files must be both in the current subproject and the startup-project. const auto fileNames = Utils::toSet(m_startupProject->files(Project::SourceFiles)); for (auto it = m_itemsHash.cbegin(), end = m_itemsHash.cend(); it != end; ++it) { if (subprojectFileNames.contains(it.key()) && fileNames.contains(it.key())) m_itemsList << it.value(); } } } } void TodoItemsProvider::itemsFetched(const QString &fileName, const QList &items) { // Replace old items with new ones m_itemsHash.insert(FilePath::fromString(fileName), items); m_shouldUpdateList = true; } void TodoItemsProvider::startupProjectChanged(Project *project) { m_startupProject = project; updateList(); } void TodoItemsProvider::projectsFilesChanged() { updateList(); } void TodoItemsProvider::currentEditorChanged(Core::IEditor *editor) { m_currentEditor = editor; if (m_settings.scanningScope == ScanningScopeCurrentFile || m_settings.scanningScope == ScanningScopeSubProject) { updateList(); } } void TodoItemsProvider::updateListTimeoutElapsed() { if (m_shouldUpdateList) { m_shouldUpdateList = false; updateList(); } } void TodoItemsProvider::setupStartupProjectBinding() { m_startupProject = SessionManager::startupProject(); connect(SessionManager::instance(), &SessionManager::startupProjectChanged, this, &TodoItemsProvider::startupProjectChanged); connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged, this, &TodoItemsProvider::projectsFilesChanged); } void TodoItemsProvider::setupCurrentEditorBinding() { m_currentEditor = Core::EditorManager::currentEditor(); connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, this, &TodoItemsProvider::currentEditorChanged); } void TodoItemsProvider::setupUpdateListTimer() { m_shouldUpdateList = false; QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &TodoItemsProvider::updateListTimeoutElapsed); timer->start(Constants::OUTPUT_PANE_UPDATE_INTERVAL); } void TodoItemsProvider::setupItemsModel() { m_itemsModel = new TodoItemsModel(this); m_itemsModel->setTodoItemsList(&m_itemsList); } } }