1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "symbolsfindfilter.h"
27 #include "cppmodelmanager.h"
28 #include "cpptoolsconstants.h"
29
30 #include <coreplugin/icore.h>
31 #include <coreplugin/progressmanager/futureprogress.h>
32 #include <coreplugin/progressmanager/progressmanager.h>
33 #include <coreplugin/editormanager/editormanager.h>
34 #include <coreplugin/find/searchresultwindow.h>
35 #include <projectexplorer/project.h>
36 #include <projectexplorer/projectexplorer.h>
37 #include <projectexplorer/session.h>
38
39 #include <utils/algorithm.h>
40 #include <utils/runextensions.h>
41 #include <utils/qtcassert.h>
42
43 #include <QSet>
44 #include <QGridLayout>
45 #include <QLabel>
46 #include <QButtonGroup>
47
48 using namespace Core;
49 using namespace Utils;
50
51 namespace CppTools {
52 namespace Internal {
53
54 const char SETTINGS_GROUP[] = "CppSymbols";
55 const char SETTINGS_SYMBOLTYPES[] = "SymbolsToSearchFor";
56 const char SETTINGS_SEARCHSCOPE[] = "SearchScope";
57
SymbolsFindFilter(CppModelManager * manager)58 SymbolsFindFilter::SymbolsFindFilter(CppModelManager *manager)
59 : m_manager(manager),
60 m_enabled(true),
61 m_symbolsToSearch(SearchSymbols::AllTypes),
62 m_scope(SymbolSearcher::SearchProjectsOnly)
63 {
64 // for disabling while parser is running
65 connect(ProgressManager::instance(), &ProgressManager::taskStarted,
66 this, &SymbolsFindFilter::onTaskStarted);
67 connect(ProgressManager::instance(), &ProgressManager::allTasksFinished,
68 this, &SymbolsFindFilter::onAllTasksFinished);
69 }
70
id() const71 QString SymbolsFindFilter::id() const
72 {
73 return QLatin1String(Constants::SYMBOLS_FIND_FILTER_ID);
74 }
75
displayName() const76 QString SymbolsFindFilter::displayName() const
77 {
78 return QString(Constants::SYMBOLS_FIND_FILTER_DISPLAY_NAME);
79 }
80
isEnabled() const81 bool SymbolsFindFilter::isEnabled() const
82 {
83 return m_enabled;
84 }
85
cancel()86 void SymbolsFindFilter::cancel()
87 {
88 auto search = qobject_cast<SearchResult *>(sender());
89 QTC_ASSERT(search, return);
90 QFutureWatcher<SearchResultItem> *watcher = m_watchers.key(search);
91 QTC_ASSERT(watcher, return);
92 watcher->cancel();
93 }
94
setPaused(bool paused)95 void SymbolsFindFilter::setPaused(bool paused)
96 {
97 auto search = qobject_cast<SearchResult *>(sender());
98 QTC_ASSERT(search, return);
99 QFutureWatcher<SearchResultItem> *watcher = m_watchers.key(search);
100 QTC_ASSERT(watcher, return);
101 if (!paused || watcher->isRunning()) // guard against pausing when the search is finished
102 watcher->setPaused(paused);
103 }
104
findAll(const QString & txt,FindFlags findFlags)105 void SymbolsFindFilter::findAll(const QString &txt, FindFlags findFlags)
106 {
107 SearchResultWindow *window = SearchResultWindow::instance();
108 SearchResult *search = window->startNewSearch(label(), toolTip(findFlags), txt);
109 search->setSearchAgainSupported(true);
110 connect(search, &SearchResult::activated,
111 this, &SymbolsFindFilter::openEditor);
112 connect(search, &SearchResult::cancelled, this, &SymbolsFindFilter::cancel);
113 connect(search, &SearchResult::paused, this, &SymbolsFindFilter::setPaused);
114 connect(search, &SearchResult::searchAgainRequested, this, &SymbolsFindFilter::searchAgain);
115 connect(this, &IFindFilter::enabledChanged, search, &SearchResult::setSearchAgainEnabled);
116 window->popup(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
117
118 SymbolSearcher::Parameters parameters;
119 parameters.text = txt;
120 parameters.flags = findFlags;
121 parameters.types = m_symbolsToSearch;
122 parameters.scope = m_scope;
123 search->setUserData(QVariant::fromValue(parameters));
124 startSearch(search);
125 }
126
startSearch(SearchResult * search)127 void SymbolsFindFilter::startSearch(SearchResult *search)
128 {
129 SymbolSearcher::Parameters parameters = search->userData().value<SymbolSearcher::Parameters>();
130 QSet<QString> projectFileNames;
131 if (parameters.scope == SymbolSearcher::SearchProjectsOnly) {
132 for (ProjectExplorer::Project *project : ProjectExplorer::SessionManager::projects())
133 projectFileNames += Utils::transform<QSet>(project->files(ProjectExplorer::Project::AllFiles), &Utils::FilePath::toString);
134 }
135
136 auto watcher = new QFutureWatcher<SearchResultItem>;
137 m_watchers.insert(watcher, search);
138 connect(watcher, &QFutureWatcherBase::finished,
139 this, &SymbolsFindFilter::finish);
140 connect(watcher, &QFutureWatcherBase::resultsReadyAt,
141 this, &SymbolsFindFilter::addResults);
142 SymbolSearcher *symbolSearcher = m_manager->indexingSupport()->createSymbolSearcher(parameters, projectFileNames);
143 connect(watcher, &QFutureWatcherBase::finished,
144 symbolSearcher, &QObject::deleteLater);
145 watcher->setFuture(Utils::runAsync(m_manager->sharedThreadPool(),
146 &SymbolSearcher::runSearch, symbolSearcher));
147 FutureProgress *progress = ProgressManager::addTask(watcher->future(), tr("Searching for Symbol"),
148 Core::Constants::TASK_SEARCH);
149 connect(progress, &FutureProgress::clicked, search, &SearchResult::popup);
150 }
151
addResults(int begin,int end)152 void SymbolsFindFilter::addResults(int begin, int end)
153 {
154 auto watcher = static_cast<QFutureWatcher<SearchResultItem> *>(sender());
155 SearchResult *search = m_watchers.value(watcher);
156 if (!search) {
157 // search was removed from search history while the search is running
158 watcher->cancel();
159 return;
160 }
161 QList<SearchResultItem> items;
162 for (int i = begin; i < end; ++i)
163 items << watcher->resultAt(i);
164 search->addResults(items, SearchResult::AddSorted);
165 }
166
finish()167 void SymbolsFindFilter::finish()
168 {
169 auto watcher = static_cast<QFutureWatcher<SearchResultItem> *>(sender());
170 SearchResult *search = m_watchers.value(watcher);
171 if (search)
172 search->finishSearch(watcher->isCanceled());
173 m_watchers.remove(watcher);
174 watcher->deleteLater();
175 }
176
openEditor(const SearchResultItem & item)177 void SymbolsFindFilter::openEditor(const SearchResultItem &item)
178 {
179 if (!item.userData().canConvert<IndexItem::Ptr>())
180 return;
181 IndexItem::Ptr info = item.userData().value<IndexItem::Ptr>();
182 EditorManager::openEditorAt(info->fileName(), info->line(), info->column());
183 }
184
createConfigWidget()185 QWidget *SymbolsFindFilter::createConfigWidget()
186 {
187 return new SymbolsFindFilterConfigWidget(this);
188 }
189
writeSettings(QSettings * settings)190 void SymbolsFindFilter::writeSettings(QSettings *settings)
191 {
192 settings->beginGroup(QLatin1String(SETTINGS_GROUP));
193 settings->setValue(QLatin1String(SETTINGS_SYMBOLTYPES), int(m_symbolsToSearch));
194 settings->setValue(QLatin1String(SETTINGS_SEARCHSCOPE), int(m_scope));
195 settings->endGroup();
196 }
197
readSettings(QSettings * settings)198 void SymbolsFindFilter::readSettings(QSettings *settings)
199 {
200 settings->beginGroup(QLatin1String(SETTINGS_GROUP));
201 m_symbolsToSearch = static_cast<SearchSymbols::SymbolTypes>(
202 settings->value(QLatin1String(SETTINGS_SYMBOLTYPES),
203 int(SearchSymbols::AllTypes)).toInt());
204 m_scope = static_cast<SearchScope>(
205 settings->value(QLatin1String(SETTINGS_SEARCHSCOPE),
206 int(SymbolSearcher::SearchProjectsOnly)).toInt());
207 settings->endGroup();
208 emit symbolsToSearchChanged();
209 }
210
onTaskStarted(Id type)211 void SymbolsFindFilter::onTaskStarted(Id type)
212 {
213 if (type == CppTools::Constants::TASK_INDEX) {
214 m_enabled = false;
215 emit enabledChanged(m_enabled);
216 }
217 }
218
onAllTasksFinished(Id type)219 void SymbolsFindFilter::onAllTasksFinished(Id type)
220 {
221 if (type == CppTools::Constants::TASK_INDEX) {
222 m_enabled = true;
223 emit enabledChanged(m_enabled);
224 }
225 }
226
searchAgain()227 void SymbolsFindFilter::searchAgain()
228 {
229 auto search = qobject_cast<SearchResult *>(sender());
230 QTC_ASSERT(search, return);
231 search->restart();
232 startSearch(search);
233 }
234
label() const235 QString SymbolsFindFilter::label() const
236 {
237 return tr("C++ Symbols:");
238 }
239
toolTip(FindFlags findFlags) const240 QString SymbolsFindFilter::toolTip(FindFlags findFlags) const
241 {
242 QStringList types;
243 if (m_symbolsToSearch & SymbolSearcher::Classes)
244 types.append(tr("Classes"));
245 if (m_symbolsToSearch & SymbolSearcher::Functions)
246 types.append(tr("Functions"));
247 if (m_symbolsToSearch & SymbolSearcher::Enums)
248 types.append(tr("Enums"));
249 if (m_symbolsToSearch & SymbolSearcher::Declarations)
250 types.append(tr("Declarations"));
251 return tr("Scope: %1\nTypes: %2\nFlags: %3")
252 .arg(searchScope() == SymbolSearcher::SearchGlobal ? tr("All") : tr("Projects"),
253 types.join(", "),
254 IFindFilter::descriptionForFindFlags(findFlags));
255 }
256
257 // #pragma mark -- SymbolsFindFilterConfigWidget
258
SymbolsFindFilterConfigWidget(SymbolsFindFilter * filter)259 SymbolsFindFilterConfigWidget::SymbolsFindFilterConfigWidget(SymbolsFindFilter *filter)
260 : m_filter(filter)
261 {
262 connect(m_filter, &SymbolsFindFilter::symbolsToSearchChanged,
263 this, &SymbolsFindFilterConfigWidget::getState);
264
265 auto layout = new QGridLayout(this);
266 setLayout(layout);
267 layout->setContentsMargins(0, 0, 0, 0);
268
269 auto typeLabel = new QLabel(tr("Types:"));
270 layout->addWidget(typeLabel, 0, 0);
271
272 m_typeClasses = new QCheckBox(tr("Classes"));
273 layout->addWidget(m_typeClasses, 0, 1);
274
275 m_typeMethods = new QCheckBox(tr("Functions"));
276 layout->addWidget(m_typeMethods, 0, 2);
277
278 m_typeEnums = new QCheckBox(tr("Enums"));
279 layout->addWidget(m_typeEnums, 1, 1);
280
281 m_typeDeclarations = new QCheckBox(tr("Declarations"));
282 layout->addWidget(m_typeDeclarations, 1, 2);
283
284 // hacks to fix layouting:
285 typeLabel->setMinimumWidth(80);
286 typeLabel->setAlignment(Qt::AlignRight);
287 m_typeClasses->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
288 m_typeMethods->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
289
290 connect(m_typeClasses, &QAbstractButton::clicked,
291 this, &SymbolsFindFilterConfigWidget::setState);
292 connect(m_typeMethods, &QAbstractButton::clicked,
293 this, &SymbolsFindFilterConfigWidget::setState);
294 connect(m_typeEnums, &QAbstractButton::clicked,
295 this, &SymbolsFindFilterConfigWidget::setState);
296 connect(m_typeDeclarations, &QAbstractButton::clicked,
297 this, &SymbolsFindFilterConfigWidget::setState);
298
299 m_searchProjectsOnly = new QRadioButton(tr("Projects only"));
300 layout->addWidget(m_searchProjectsOnly, 2, 1);
301
302 m_searchGlobal = new QRadioButton(tr("All files"));
303 layout->addWidget(m_searchGlobal, 2, 2);
304
305 m_searchGroup = new QButtonGroup(this);
306 m_searchGroup->addButton(m_searchProjectsOnly);
307 m_searchGroup->addButton(m_searchGlobal);
308
309 connect(m_searchProjectsOnly, &QAbstractButton::clicked,
310 this, &SymbolsFindFilterConfigWidget::setState);
311 connect(m_searchGlobal, &QAbstractButton::clicked,
312 this, &SymbolsFindFilterConfigWidget::setState);
313 }
314
getState()315 void SymbolsFindFilterConfigWidget::getState()
316 {
317 SearchSymbols::SymbolTypes symbols = m_filter->symbolsToSearch();
318 m_typeClasses->setChecked(symbols & SymbolSearcher::Classes);
319 m_typeMethods->setChecked(symbols & SymbolSearcher::Functions);
320 m_typeEnums->setChecked(symbols & SymbolSearcher::Enums);
321 m_typeDeclarations->setChecked(symbols & SymbolSearcher::Declarations);
322
323 SymbolsFindFilter::SearchScope scope = m_filter->searchScope();
324 m_searchProjectsOnly->setChecked(scope == SymbolSearcher::SearchProjectsOnly);
325 m_searchGlobal->setChecked(scope == SymbolSearcher::SearchGlobal);
326 }
327
setState() const328 void SymbolsFindFilterConfigWidget::setState() const
329 {
330 SearchSymbols::SymbolTypes symbols;
331 if (m_typeClasses->isChecked())
332 symbols |= SymbolSearcher::Classes;
333 if (m_typeMethods->isChecked())
334 symbols |= SymbolSearcher::Functions;
335 if (m_typeEnums->isChecked())
336 symbols |= SymbolSearcher::Enums;
337 if (m_typeDeclarations->isChecked())
338 symbols |= SymbolSearcher::Declarations;
339 m_filter->setSymbolsToSearch(symbols);
340
341 if (m_searchProjectsOnly->isChecked())
342 m_filter->setSearchScope(SymbolSearcher::SearchProjectsOnly);
343 else
344 m_filter->setSearchScope(SymbolSearcher::SearchGlobal);
345 }
346
347 } // namespace Internal
348 } // namespace CppTools
349