ProjectExplorer
ProjectExplorer
命名空间中的类都是与 Qt Creator 中的工程管理相关的。该命名空间由 projectexplorer 插件提供,而 Qt Crteaor 所支持的工程类型也是由这个插件提供。例如,
- cmakeprojectmanager 插件实现了
ProjectExplorer
命名空间中所定义的接口,支持的是 CMake 工程; - qt4projectmanager 插件提供对 Qt 4 工程的支持;
- qmlprojectmanager 插件提供对 QML 工程的支持。
下面列出的是ProjectManager
命名空间中一些关键的类和接口:
类/接口 | 描述 |
ProjectExplorer::IProjectManager | 如果需要提供一种新的工程类型,必须实现此接口。该接口的实现帮助 Qt Creator 加载工程。 |
ProjectExplorer::Project | 该接口定义了一个工程的几个术语:
|
ProjectManager::ProjectExplorerPlugin | 工程浏览器插件所需实现的Core::IPlugin 接口。通过该类,我们可以:
|
获取已打开工程列表
使用ProjectManager::ProjectExplorerPlugin
,我们可以获取 Qt Creator 的所有已打开的工程。下面的代码显示如何做到这一点:
#include <extensionsystem/pluginmanager.h> #include <projectexplorer/projectexplorer.h> // Catch hold of the plugin-manager ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); // Look for the ProjectExplorerPlugin object ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin = pm->getObject(); // Fetch a list of all open projects QList<ProjectExplorer::Project*> projects = d->projectPlugin->session()->projects();
利用我们得到的 projects 列表,我们可以访问该工程文件以及工程中的其他文件(源代码文件、头文件、资源文件等)。于是,我们可以编写如下的代码:
Q_FOREACH(ProjectExplorer::Project* project, projects) { QString name = project->name(); Core::IFile* projectFile = project->file(); // Do something with the above. For example: qDebug("Project %s has project file as %s", qPrintable(name), qPrintable(projectFile->fileName())); }
上面的代码展示了如何获取工程文件(CMakeLists.txt,.pro 文件等),但是并不能获取与工程关联的其他文件。而下面的代码则显示了如何从 projects 列表获取所有文件的文件名列表:
// Make a list of files in each project QStringList files; Q_FOREACH(ProjectManager::Project* project, projects) { files += project->files(Project::AllFiles); }
条件设置 HeaderFilter
我们的HeaderFilter
应该在至少有一个工程打开的情况下才能够使用。为简单起见,我们前面将isEnabled()
函数的返回值始终设置为 true。下面,我们来修改这段代码,以便满足我们的需求:
struct HeaderFilterData { ProjectExplorer::ProjectExplorerPlugin* projectExplorer() { if(m_projectPlugin) { return m_projectPlugin; } ExtensionSystem::PluginManager* pm = ExtensionSystem::PluginManager::instance(); m_projectPlugin = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>(); return m_projectPlugin; } private: ProjectExplorer::ProjectExplorerPlugin* m_projectPlugin; }; // ... bool HeaderFilter::isEnabled() const { return d->projectExplorer()->session()->projects().count() > 0; }
在文件中搜索
从前面的内容中,我们已经了解到如何访问与打开的工程相关联的文件名。现在,我们就可以在这些文件中进行查找了。下面,我们开始一步步实现HeaderFilter::findAll()
函数:
void HeaderFilter::findAll(const QString &text, Find::FindFlags findFlags) { // Fetch a list of all open projects QList<ProjectExplorer::Project*> projects = d->projectExplorer()->session()->projects(); // Make a list of files in each project QStringList files; Q_FOREACH(ProjectExplorer::Project* project, projects) { files += project->files(ProjectExplorer::Project::AllFiles); } // Remove duplicates files.removeDuplicates(); // Search for text in files // ... }
我们可以获知需要搜索的文件的数目:或许只有 1 个文件,也可能有 1000 或者更多的文件!因此,直接在findAll()
函数中进行搜索不是一个好主意。如果findAll()
函数执行时间过长,就会使得整个 Qt Creator 界面停止响应,直到搜索完成(通常,这是 GUI 程序设计中需要注意的一个问题:不要在 GUI 线程执行过于复杂的操作,以免拖慢 GUI 的响应)!
这种问题的解决方案是:
- 使用
QtConcurrent
,创建多个线程执行实际的搜索; - 为
QtConcurrent
返回的QFuture
初始化一个QFutureWatcher
,以便在搜索结果生成之后发送 signals; - 监听
QFutureWatcher
发出的信息,列出搜索结果。
Qt Creator 已经为我们提供了函数findInFiles()
,用于在一个文件列表中查找一个字符串,然后返回一个用于监视搜索结果的 QFuture 对象。这个函数在 src/libs/utils/filesearch.h 中声明:
namespace Utils { // ... class QTCREATOR_UTILS_EXPORT FileSearchResult { public: FileSearchResult() {} FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength, QStringList regexpCapturedTexts) : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength), regexpCapturedTexts(regexpCapturedTexts) { } QString fileName; int lineNumber; QString matchingLine; int matchStart; int matchLength; QStringList regexpCapturedTexts; }; typedef QList<FileSearchResult> FileSearchResultList; QTCREATOR_UTILS_EXPORT QFuture<FileSearchResultList> findInFiles( const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>()); QTCREATOR_UTILS_EXPORT QFuture<FileSearchResultList> findInFilesRegExp( const QString &searchTerm, FileIterator *files, QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>()); // ... } // namespace Utils
好了,现在照着新的思路,继续完成HeaderFilter::findAll()
函数吧:
struct HeaderFilterData { QFutureWatcher<Utils::FileSearchResultList> watcher; ProjectExplorer::ProjectExplorerPlugin* projectExplorer() { // ... } private: ProjectExplorer::ProjectExplorerPlugin* m_projectPlugin; }; HeaderFilter::HeaderFilter() { d = new HeaderFilterData; connect(&d->watcher, SIGNAL(resultReadyAt(int)), SLOT(displayResult(int))); } void HeaderFilter::findAll(const QString &text, Find::FindFlags findFlags) { // ... // Remove duplicates files.removeDuplicates(); // Search for text in files // Variable to hold search results that will // come as the search task progresses QFuture searchResults; // Begin searching QString includeline = "#include <" + text + ">"; QList<QTextCodec *> codecs; codecs << QTextCodec::codecForLocale(); searchResults = Utils::findInFiles(includeline, new Utils::FileIterator(files, codecs), Find::textDocumentFlagsForFindFlags(findFlags)); // Let the watcher monitor the search results d->watcher.setFuture(searchResults); } void HeaderFilter::displayResult(int index) { // ... }
在findAll()
的后续代码中,我们使用了findInFiles()
函数,在后台开始了多个线程用于查找字符串。一旦搜索结果生成,根据我们的 connect,displayResult(int)
就会被调用。在这个槽函数中,我们需要将搜索结果展示出来。
2 评论
大佬,上文说的d指针是哪个对象啊,求助!!!1
session()返回的对象是什么呀