1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Alexander Drozdov.
4 ** Contact: Alexander Drozdov (adrozdoff@gmail.com)
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 "treescanner.h"
27
28 #include "projectexplorerconstants.h"
29 #include "projectnodeshelper.h"
30 #include "projecttree.h"
31
32 #include <coreplugin/iversioncontrol.h>
33 #include <coreplugin/vcsmanager.h>
34
35 #include <cpptools/cpptoolsconstants.h>
36
37 #include <utils/qtcassert.h>
38 #include <utils/algorithm.h>
39 #include <utils/runextensions.h>
40
41 #include <memory>
42
43 namespace ProjectExplorer {
44
TreeScanner(QObject * parent)45 TreeScanner::TreeScanner(QObject *parent) : QObject(parent)
46 {
47 m_factory = TreeScanner::genericFileType;
48 m_filter = [](const Utils::MimeType &mimeType, const Utils::FilePath &fn) {
49 return isWellKnownBinary(mimeType, fn) && isMimeBinary(mimeType, fn);
50 };
51
52 connect(&m_futureWatcher, &FutureWatcher::finished, this, &TreeScanner::finished);
53 }
54
~TreeScanner()55 TreeScanner::~TreeScanner()
56 {
57 disconnect(&m_futureWatcher, nullptr, nullptr, nullptr); // Do not trigger signals anymore!
58
59 if (!m_futureWatcher.isFinished()) {
60 m_futureWatcher.cancel();
61 m_futureWatcher.waitForFinished();
62 }
63 }
64
asyncScanForFiles(const Utils::FilePath & directory)65 bool TreeScanner::asyncScanForFiles(const Utils::FilePath &directory)
66 {
67 if (!m_futureWatcher.isFinished())
68 return false;
69
70 m_scanFuture = Utils::runAsync([this, directory](FutureInterface &fi) {
71 TreeScanner::scanForFiles(fi, directory, m_filter, m_factory);
72 });
73 m_futureWatcher.setFuture(m_scanFuture);
74
75 return true;
76 }
77
setFilter(TreeScanner::FileFilter filter)78 void TreeScanner::setFilter(TreeScanner::FileFilter filter)
79 {
80 if (isFinished())
81 m_filter = filter;
82 }
83
setTypeFactory(TreeScanner::FileTypeFactory factory)84 void TreeScanner::setTypeFactory(TreeScanner::FileTypeFactory factory)
85 {
86 if (isFinished())
87 m_factory = factory;
88 }
89
future() const90 TreeScanner::Future TreeScanner::future() const
91 {
92 return m_scanFuture;
93 }
94
isFinished() const95 bool TreeScanner::isFinished() const
96 {
97 return m_futureWatcher.isFinished();
98 }
99
result() const100 TreeScanner::Result TreeScanner::result() const
101 {
102 if (isFinished())
103 return m_scanFuture.result();
104 return Result();
105 }
106
release()107 TreeScanner::Result TreeScanner::release()
108 {
109 if (isFinished() && m_scanFuture.resultCount() > 0) {
110 auto result = m_scanFuture.result();
111 m_scanFuture = Future();
112 return result;
113 }
114 m_scanFuture = Future();
115 return Result();
116 }
117
reset()118 void TreeScanner::reset()
119 {
120 if (isFinished())
121 m_scanFuture = Future();
122 }
123
isWellKnownBinary(const Utils::MimeType &,const Utils::FilePath & fn)124 bool TreeScanner::isWellKnownBinary(const Utils::MimeType & /*mdb*/, const Utils::FilePath &fn)
125 {
126 return fn.endsWith(QLatin1String(".a")) ||
127 fn.endsWith(QLatin1String(".o")) ||
128 fn.endsWith(QLatin1String(".d")) ||
129 fn.endsWith(QLatin1String(".exe")) ||
130 fn.endsWith(QLatin1String(".dll")) ||
131 fn.endsWith(QLatin1String(".obj")) ||
132 fn.endsWith(QLatin1String(".elf"));
133 }
134
isMimeBinary(const Utils::MimeType & mimeType,const Utils::FilePath &)135 bool TreeScanner::isMimeBinary(const Utils::MimeType &mimeType, const Utils::FilePath &/*fn*/)
136 {
137 bool isBinary = false;
138 if (mimeType.isValid()) {
139 QStringList mimes;
140 mimes << mimeType.name() << mimeType.allAncestors();
141 isBinary = !mimes.contains(QLatin1String("text/plain"));
142 }
143 return isBinary;
144 }
145
genericFileType(const Utils::MimeType & mimeType,const Utils::FilePath &)146 FileType TreeScanner::genericFileType(const Utils::MimeType &mimeType, const Utils::FilePath &/*fn*/)
147 {
148 return Node::fileTypeForMimeType(mimeType);
149 }
150
createFolderNode(const Utils::FilePath & directory,const QList<FileNode * > & allFiles)151 static std::unique_ptr<FolderNode> createFolderNode(const Utils::FilePath &directory,
152 const QList<FileNode *> &allFiles)
153 {
154 auto fileSystemNode = std::make_unique<FolderNode>(directory);
155 for (const FileNode *fn : allFiles) {
156 if (!fn->filePath().isChildOf(directory))
157 continue;
158
159 std::unique_ptr<FileNode> node(fn->clone());
160 fileSystemNode->addNestedNode(std::move(node));
161 }
162 ProjectTree::applyTreeManager(fileSystemNode.get()); // QRC nodes
163 return fileSystemNode;
164 }
165
scanForFiles(FutureInterface & fi,const Utils::FilePath & directory,const FileFilter & filter,const FileTypeFactory & factory)166 void TreeScanner::scanForFiles(FutureInterface &fi, const Utils::FilePath& directory,
167 const FileFilter &filter, const FileTypeFactory &factory)
168 {
169 QList<FileNode *> nodes = ProjectExplorer::scanForFiles(fi, directory,
170 [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
171 const Utils::MimeType mimeType = Utils::mimeTypeForFile(fn);
172
173 // Skip some files during scan.
174 if (filter && filter(mimeType, fn))
175 return nullptr;
176
177 // Type detection
178 FileType type = FileType::Unknown;
179 if (factory)
180 type = factory(mimeType, fn);
181
182 return new FileNode(fn, type);
183 });
184
185 Utils::sort(nodes, ProjectExplorer::Node::sortByPath);
186
187 fi.setProgressValue(fi.progressMaximum());
188 Result result{createFolderNode(directory, nodes), nodes};
189
190 fi.reportResult(result);
191 }
192
193 } // namespace ProjectExplorer
194