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()返回的对象是什么呀