1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Canonical 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 "cmaketoolmanager.h"
27
28 #include "cmaketoolsettingsaccessor.h"
29
30 #include <extensionsystem/pluginmanager.h>
31
32 #include <coreplugin/helpmanager.h>
33 #include <coreplugin/icore.h>
34
35 #include <utils/environment.h>
36 #include <utils/pointeralgorithm.h>
37 #include <utils/qtcassert.h>
38
39 using namespace Core;
40 using namespace Utils;
41
42 namespace CMakeProjectManager {
43
44 // --------------------------------------------------------------------
45 // CMakeToolManagerPrivate:
46 // --------------------------------------------------------------------
47
48 class CMakeToolManagerPrivate
49 {
50 public:
51 Id m_defaultCMake;
52 std::vector<std::unique_ptr<CMakeTool>> m_cmakeTools;
53 Internal::CMakeToolSettingsAccessor m_accessor;
54 };
55 static CMakeToolManagerPrivate *d = nullptr;
56
57 // --------------------------------------------------------------------
58 // CMakeToolManager:
59 // --------------------------------------------------------------------
60
61 CMakeToolManager *CMakeToolManager::m_instance = nullptr;
62
CMakeToolManager()63 CMakeToolManager::CMakeToolManager()
64 {
65 QTC_ASSERT(!m_instance, return);
66 m_instance = this;
67
68 qRegisterMetaType<QString *>();
69
70 d = new CMakeToolManagerPrivate;
71 connect(ICore::instance(), &ICore::saveSettingsRequested,
72 this, &CMakeToolManager::saveCMakeTools);
73
74 connect(this, &CMakeToolManager::cmakeAdded, this, &CMakeToolManager::cmakeToolsChanged);
75 connect(this, &CMakeToolManager::cmakeRemoved, this, &CMakeToolManager::cmakeToolsChanged);
76 connect(this, &CMakeToolManager::cmakeUpdated, this, &CMakeToolManager::cmakeToolsChanged);
77
78 setObjectName("CMakeToolManager");
79 ExtensionSystem::PluginManager::addObject(this);
80 }
81
~CMakeToolManager()82 CMakeToolManager::~CMakeToolManager()
83 {
84 ExtensionSystem::PluginManager::removeObject(this);
85 delete d;
86 }
87
instance()88 CMakeToolManager *CMakeToolManager::instance()
89 {
90 return m_instance;
91 }
92
cmakeTools()93 QList<CMakeTool *> CMakeToolManager::cmakeTools()
94 {
95 return Utils::toRawPointer<QList>(d->m_cmakeTools);
96 }
97
registerCMakeTool(std::unique_ptr<CMakeTool> && tool)98 bool CMakeToolManager::registerCMakeTool(std::unique_ptr<CMakeTool> &&tool)
99 {
100 if (!tool || Utils::contains(d->m_cmakeTools, tool.get()))
101 return true;
102
103 const Utils::Id toolId = tool->id();
104 QTC_ASSERT(toolId.isValid(),return false);
105
106 //make sure the same id was not used before
107 QTC_ASSERT(!Utils::contains(d->m_cmakeTools, [toolId](const std::unique_ptr<CMakeTool> &known) {
108 return toolId == known->id();
109 }), return false);
110
111 d->m_cmakeTools.emplace_back(std::move(tool));
112
113 emit CMakeToolManager::m_instance->cmakeAdded(toolId);
114
115 ensureDefaultCMakeToolIsValid();
116
117 updateDocumentation();
118
119 return true;
120 }
121
deregisterCMakeTool(const Id & id)122 void CMakeToolManager::deregisterCMakeTool(const Id &id)
123 {
124 auto toRemove = Utils::take(d->m_cmakeTools, Utils::equal(&CMakeTool::id, id));
125 if (toRemove.has_value()) {
126 ensureDefaultCMakeToolIsValid();
127
128 updateDocumentation();
129
130 emit m_instance->cmakeRemoved(id);
131 }
132 }
133
defaultCMakeTool()134 CMakeTool *CMakeToolManager::defaultCMakeTool()
135 {
136 return findById(d->m_defaultCMake);
137 }
138
setDefaultCMakeTool(const Id & id)139 void CMakeToolManager::setDefaultCMakeTool(const Id &id)
140 {
141 if (d->m_defaultCMake != id && findById(id)) {
142 d->m_defaultCMake = id;
143 emit m_instance->defaultCMakeChanged();
144 return;
145 }
146
147 ensureDefaultCMakeToolIsValid();
148 }
149
findByCommand(const Utils::FilePath & command)150 CMakeTool *CMakeToolManager::findByCommand(const Utils::FilePath &command)
151 {
152 return Utils::findOrDefault(d->m_cmakeTools, Utils::equal(&CMakeTool::cmakeExecutable, command));
153 }
154
findById(const Id & id)155 CMakeTool *CMakeToolManager::findById(const Id &id)
156 {
157 return Utils::findOrDefault(d->m_cmakeTools, Utils::equal(&CMakeTool::id, id));
158 }
159
restoreCMakeTools()160 void CMakeToolManager::restoreCMakeTools()
161 {
162 Internal::CMakeToolSettingsAccessor::CMakeTools tools
163 = d->m_accessor.restoreCMakeTools(ICore::dialogParent());
164 d->m_cmakeTools = std::move(tools.cmakeTools);
165 setDefaultCMakeTool(tools.defaultToolId);
166
167 updateDocumentation();
168
169 emit m_instance->cmakeToolsLoaded();
170 }
171
updateDocumentation()172 void CMakeToolManager::updateDocumentation()
173 {
174 const QList<CMakeTool *> tools = cmakeTools();
175 QStringList docs;
176 for (const auto tool : tools) {
177 if (!tool->qchFilePath().isEmpty())
178 docs.append(tool->qchFilePath().toString());
179 }
180 Core::HelpManager::registerDocumentation(docs);
181 }
182
autoDetectCMakeForDevice(const FilePath & deviceRoot,const QString & detectionSource,QString * logMessage)183 void CMakeToolManager::autoDetectCMakeForDevice(const FilePath &deviceRoot,
184 const QString &detectionSource,
185 QString *logMessage)
186 {
187 QStringList messages{tr("Searching CMake binaries...")};
188 const FilePaths candidates = {deviceRoot.withNewPath("cmake")};
189 const Environment env = deviceRoot.deviceEnvironment();
190 for (const FilePath &candidate : candidates) {
191 const FilePath cmake = candidate.searchOnDevice(env.path());
192 if (!cmake.isEmpty()) {
193 registerCMakeByPath(cmake, detectionSource);
194 messages.append(tr("Found \"%1\"").arg(cmake.toUserOutput()));
195 }
196 }
197 if (logMessage)
198 *logMessage = messages.join('\n');
199 }
200
201
registerCMakeByPath(const FilePath & cmakePath,const QString & detectionSource)202 void CMakeToolManager::registerCMakeByPath(const FilePath &cmakePath, const QString &detectionSource)
203 {
204 const Id id = Id::fromString(cmakePath.toUserOutput());
205
206 CMakeTool *cmakeTool = findById(id);
207 if (cmakeTool)
208 return;
209
210 auto newTool = std::make_unique<CMakeTool>(CMakeTool::ManualDetection, id);
211 newTool->setFilePath(cmakePath);
212 newTool->setDetectionSource(detectionSource);
213 newTool->setDisplayName(cmakePath.toUserOutput());
214 registerCMakeTool(std::move(newTool));
215 }
216
removeDetectedCMake(const QString & detectionSource,QString * logMessage)217 void CMakeToolManager::removeDetectedCMake(const QString &detectionSource, QString *logMessage)
218 {
219 QStringList logMessages{tr("Removing CMake entries...")};
220 while (true) {
221 auto toRemove = Utils::take(d->m_cmakeTools, Utils::equal(&CMakeTool::detectionSource, detectionSource));
222 if (!toRemove.has_value())
223 break;
224 logMessages.append(tr("Removed \"%1\"").arg((*toRemove)->displayName()));
225 emit m_instance->cmakeRemoved((*toRemove)->id());
226 }
227
228 ensureDefaultCMakeToolIsValid();
229 updateDocumentation();
230 if (logMessage)
231 *logMessage = logMessages.join('\n');
232 }
233
listDetectedCMake(const QString & detectionSource,QString * logMessage)234 void CMakeToolManager::listDetectedCMake(const QString &detectionSource, QString *logMessage)
235 {
236 QTC_ASSERT(logMessage, return);
237 QStringList logMessages{tr("CMake:")};
238 for (const auto &tool : qAsConst(d->m_cmakeTools)) {
239 if (tool->detectionSource() == detectionSource)
240 logMessages.append(tool->displayName());
241 }
242 *logMessage = logMessages.join('\n');
243 }
244
notifyAboutUpdate(CMakeTool * tool)245 void CMakeToolManager::notifyAboutUpdate(CMakeTool *tool)
246 {
247 if (!tool || !Utils::contains(d->m_cmakeTools, tool))
248 return;
249 emit m_instance->cmakeUpdated(tool->id());
250 }
251
saveCMakeTools()252 void CMakeToolManager::saveCMakeTools()
253 {
254 d->m_accessor.saveCMakeTools(cmakeTools(), d->m_defaultCMake, ICore::dialogParent());
255 }
256
ensureDefaultCMakeToolIsValid()257 void CMakeToolManager::ensureDefaultCMakeToolIsValid()
258 {
259 const Utils::Id oldId = d->m_defaultCMake;
260 if (d->m_cmakeTools.size() == 0) {
261 d->m_defaultCMake = Utils::Id();
262 } else {
263 if (findById(d->m_defaultCMake))
264 return;
265 d->m_defaultCMake = d->m_cmakeTools.at(0)->id();
266 }
267
268 // signaling:
269 if (oldId != d->m_defaultCMake)
270 emit m_instance->defaultCMakeChanged();
271 }
272
273 } // namespace CMakeProjectManager
274