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 #pragma once 27 28 #include "projectexplorer_export.h" 29 30 #include <QFutureInterface> 31 #include <QIcon> 32 #include <QStringList> 33 34 #include <utils/fileutils.h> 35 #include <utils/id.h> 36 #include <utils/optional.h> 37 #include <utils/variant.h> 38 39 #include <functional> 40 41 namespace Utils { class MimeType; } 42 43 namespace ProjectExplorer { 44 45 class BuildSystem; 46 class Project; 47 48 // File types common for qt projects 49 enum class FileType : quint16 { 50 Unknown = 0, 51 Header, 52 Source, 53 Form, 54 StateChart, 55 Resource, 56 QML, 57 Project, 58 FileTypeSize 59 }; 60 61 enum class ProductType { App, Lib, Other, None }; 62 63 enum ProjectAction { 64 // Special value to indicate that the actions are handled by the parent 65 InheritedFromParent, 66 AddSubProject, 67 AddExistingProject, 68 RemoveSubProject, 69 // Let's the user select to which project file 70 // the file is added 71 AddNewFile, 72 AddExistingFile, 73 // Add files, which match user defined filters, 74 // from an existing directory and its subdirectories 75 AddExistingDirectory, 76 // Removes a file from the project, optionally also 77 // delete it on disc 78 RemoveFile, 79 // Deletes a file from the file system, informs the project 80 // that a file was deleted 81 // DeleteFile is a define on windows... 82 EraseFile, 83 Rename, 84 // hides actions that use the path(): Open containing folder, open terminal here and Find in Directory 85 HidePathActions, 86 HideFileActions, 87 HideFolderActions, 88 }; 89 90 enum class RemovedFilesFromProject { Ok, Wildcard, Error }; 91 92 class FileNode; 93 class FolderNode; 94 class ProjectNode; 95 class ContainerNode; 96 97 class PROJECTEXPLORER_EXPORT DirectoryIcon 98 { 99 public: 100 explicit DirectoryIcon(const QString &overlay); 101 102 QIcon icon() const; // only safe in UI thread 103 104 private: 105 QString m_overlay; 106 static QHash<QString, QIcon> m_cache; 107 }; 108 109 using IconCreator = std::function<QIcon()>; 110 111 // Documentation inside. 112 class PROJECTEXPLORER_EXPORT Node 113 { 114 public: 115 enum PriorityLevel { 116 DefaultPriority = 0, 117 DefaultFilePriority = 100000, 118 DefaultFolderPriority = 200000, 119 DefaultVirtualFolderPriority = 300000, 120 DefaultProjectPriority = 400000, 121 DefaultProjectFilePriority = 500000 122 }; 123 124 virtual ~Node(); 125 isFolderNodeType()126 virtual bool isFolderNodeType() const { return false; } isProjectNodeType()127 virtual bool isProjectNodeType() const { return false; } isVirtualFolderType()128 virtual bool isVirtualFolderType() const { return false; } 129 130 int priority() const; 131 132 ProjectNode *parentProjectNode() const; // parent project, will be nullptr for the top-level project 133 FolderNode *parentFolderNode() const; // parent folder or project 134 135 ProjectNode *managingProject(); // project managing this node. 136 // result is the container's rootProject node if this is a project container node 137 // (i.e. possibly null) 138 // or node if node is a top-level ProjectNode directly below a container 139 // or node->parentProjectNode() for all other cases. 140 const ProjectNode *managingProject() const; // see above. 141 142 Project *getProject() const; 143 144 const Utils::FilePath &filePath() const; // file system path 145 int line() const; 146 virtual QString displayName() const; 147 virtual QString tooltip() const; 148 bool isEnabled() const; 149 bool listInProject() const; 150 bool isGenerated() const; 151 152 virtual bool supportsAction(ProjectAction action, const Node *node) const; 153 154 void setEnabled(bool enabled); 155 void setAbsoluteFilePathAndLine(const Utils::FilePath &filePath, int line); 156 asFileNode()157 virtual FileNode *asFileNode() { return nullptr; } asFileNode()158 virtual const FileNode *asFileNode() const { return nullptr; } asFolderNode()159 virtual FolderNode *asFolderNode() { return nullptr; } asFolderNode()160 virtual const FolderNode *asFolderNode() const { return nullptr; } asProjectNode()161 virtual ProjectNode *asProjectNode() { return nullptr; } asProjectNode()162 virtual const ProjectNode *asProjectNode() const { return nullptr; } asContainerNode()163 virtual ContainerNode *asContainerNode() { return nullptr; } asContainerNode()164 virtual const ContainerNode *asContainerNode() const { return nullptr; } 165 buildKey()166 virtual QString buildKey() const { return QString(); } 167 168 static bool sortByPath(const Node *a, const Node *b); 169 void setParentFolderNode(FolderNode *parentFolder); 170 171 void setListInProject(bool l); 172 void setIsGenerated(bool g); 173 void setPriority(int priority); 174 void setLine(int line); 175 176 static FileType fileTypeForMimeType(const Utils::MimeType &mt); 177 static FileType fileTypeForFileName(const Utils::FilePath &file); 178 path()179 QString path() const { return pathOrDirectory(false); } directory()180 QString directory() const { return pathOrDirectory(true); } 181 182 protected: 183 Node(); 184 Node(const Node &other) = delete; 185 bool operator=(const Node &other) = delete; 186 187 void setFilePath(const Utils::FilePath &filePath); 188 189 private: 190 QString pathOrDirectory(bool dir) const; 191 192 FolderNode *m_parentFolderNode = nullptr; 193 Utils::FilePath m_filePath; 194 int m_line = -1; 195 int m_priority = DefaultPriority; 196 197 enum NodeFlag : quint16 { 198 FlagNone = 0, 199 FlagIsEnabled = 1 << 0, 200 FlagIsGenerated = 1 << 1, 201 FlagListInProject = 1 << 2, 202 }; 203 NodeFlag m_flags = FlagIsEnabled; 204 }; 205 206 class PROJECTEXPLORER_EXPORT FileNode : public Node 207 { 208 public: 209 FileNode(const Utils::FilePath &filePath, const FileType fileType); 210 211 FileNode *clone() const; 212 213 FileType fileType() const; 214 asFileNode()215 FileNode *asFileNode() final { return this; } asFileNode()216 const FileNode *asFileNode() const final { return this; } 217 218 bool supportsAction(ProjectAction action, const Node *node) const override; 219 QString displayName() const override; 220 221 bool hasError() const; 222 void setHasError(const bool error); 223 void setHasError(const bool error) const; 224 225 QIcon icon() const; 226 void setIcon(const QIcon icon); 227 228 private: 229 FileType m_fileType; 230 mutable QIcon m_icon; 231 mutable bool m_hasError = false; 232 }; 233 234 // Documentation inside. 235 class PROJECTEXPLORER_EXPORT FolderNode : public Node 236 { 237 public: 238 explicit FolderNode(const Utils::FilePath &folderPath); 239 240 QString displayName() const override; 241 // only safe from UI thread 242 QIcon icon() const; 243 isFolderNodeType()244 bool isFolderNodeType() const override { return true; } 245 246 Node *findNode(const std::function<bool(Node *)> &filter); 247 QList<Node *> findNodes(const std::function<bool(Node *)> &filter); 248 249 void forEachNode(const std::function<void(FileNode *)> &fileTask, 250 const std::function<void(FolderNode *)> &folderTask = {}, 251 const std::function<bool(const FolderNode *)> &folderFilterTask = {}) const; 252 void forEachGenericNode(const std::function<void(Node *)> &genericTask) const; 253 void forEachProjectNode(const std::function<void(const ProjectNode *)> &genericTask) const; 254 ProjectNode *findProjectNode(const std::function<bool(const ProjectNode *)> &predicate); 255 const QList<Node *> nodes() const; 256 QList<FileNode *> fileNodes() const; 257 FileNode *fileNode(const Utils::FilePath &file) const; 258 QList<FolderNode *> folderNodes() const; 259 FolderNode *folderNode(const Utils::FilePath &directory) const; 260 261 using FolderNodeFactory = std::function<std::unique_ptr<FolderNode>(const Utils::FilePath &)>; 262 void addNestedNodes(std::vector<std::unique_ptr<FileNode>> &&files, 263 const Utils::FilePath &overrideBaseDir = Utils::FilePath(), 264 const FolderNodeFactory &factory 265 = [](const Utils::FilePath &fn) { return std::make_unique<FolderNode>(fn); }); 266 void addNestedNode(std::unique_ptr<FileNode> &&fileNode, 267 const Utils::FilePath &overrideBaseDir = Utils::FilePath(), 268 const FolderNodeFactory &factory 269 = [](const Utils::FilePath &fn) { return std::make_unique<FolderNode>(fn); }); 270 void compress(); 271 272 // takes ownership of newNode. 273 // Will delete newNode if oldNode is not a child of this node. 274 bool replaceSubtree(Node *oldNode, std::unique_ptr<Node> &&newNode); 275 276 void setDisplayName(const QString &name); 277 // you have to make sure the QIcon is created in the UI thread if you are calling setIcon(QIcon) 278 void setIcon(const QIcon &icon); 279 void setIcon(const DirectoryIcon &directoryIcon); 280 void setIcon(const QString &path); 281 void setIcon(const IconCreator &iconCreator); 282 283 class LocationInfo 284 { 285 public: 286 LocationInfo() = default; 287 LocationInfo(const QString &dn, 288 const Utils::FilePath &p, 289 const int l = 0, 290 const unsigned int prio = 0) path(p)291 : path(p) 292 , line(l) 293 , priority(prio) 294 , displayName(dn) 295 {} 296 297 Utils::FilePath path; 298 int line = -1; 299 unsigned int priority = 0; 300 QString displayName; 301 }; 302 void setLocationInfo(const QVector<LocationInfo> &info); 303 const QVector<LocationInfo> locationInfo() const; 304 305 QString addFileFilter() const; setAddFileFilter(const QString & filter)306 void setAddFileFilter(const QString &filter) { m_addFileFilter = filter; } 307 308 bool supportsAction(ProjectAction action, const Node *node) const override; 309 310 virtual bool addFiles(const Utils::FilePaths &filePaths, Utils::FilePaths *notAdded = nullptr); 311 virtual RemovedFilesFromProject removeFiles(const Utils::FilePaths &filePaths, 312 Utils::FilePaths *notRemoved = nullptr); 313 virtual bool deleteFiles(const Utils::FilePaths &filePaths); 314 virtual bool canRenameFile(const Utils::FilePath &oldFilePath, 315 const Utils::FilePath &newFilePath); 316 virtual bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath); 317 virtual bool addDependencies(const QStringList &dependencies); 318 319 class AddNewInformation 320 { 321 public: AddNewInformation(const QString & name,int p)322 AddNewInformation(const QString &name, int p) 323 :displayName(name), priority(p) 324 { } 325 QString displayName; 326 int priority; 327 }; 328 329 virtual AddNewInformation addNewInformation(const QStringList &files, Node *context) const; 330 331 332 // determines if node will be shown in the flat view, by default folder and projects aren't shown 333 virtual bool showInSimpleTree() const; 334 335 // determines if node will always be shown when hiding empty directories 336 bool showWhenEmpty() const; 337 void setShowWhenEmpty(bool showWhenEmpty); 338 339 void addNode(std::unique_ptr<Node> &&node); 340 341 bool isEmpty() const; 342 asFolderNode()343 FolderNode *asFolderNode() override { return this; } asFolderNode()344 const FolderNode *asFolderNode() const override { return this; } 345 346 protected: 347 virtual void handleSubTreeChanged(FolderNode *node); 348 349 std::vector<std::unique_ptr<Node>> m_nodes; 350 QVector<LocationInfo> m_locations; 351 352 private: 353 std::unique_ptr<Node> takeNode(Node *node); 354 355 QString m_displayName; 356 QString m_addFileFilter; 357 mutable Utils::variant<QIcon, DirectoryIcon, QString, IconCreator> m_icon; 358 bool m_showWhenEmpty = false; 359 }; 360 361 class PROJECTEXPLORER_EXPORT VirtualFolderNode : public FolderNode 362 { 363 public: 364 explicit VirtualFolderNode(const Utils::FilePath &folderPath); 365 isFolderNodeType()366 bool isFolderNodeType() const override { return false; } isVirtualFolderType()367 bool isVirtualFolderType() const override { return true; } 368 isSourcesOrHeaders()369 bool isSourcesOrHeaders() const { return m_isSourcesOrHeaders; } setIsSourcesOrHeaders(bool on)370 void setIsSourcesOrHeaders(bool on) { m_isSourcesOrHeaders = on; } 371 372 private: 373 bool m_isSourcesOrHeaders = false; // "Sources" or "Headers" 374 }; 375 376 // Documentation inside. 377 class PROJECTEXPLORER_EXPORT ProjectNode : public FolderNode 378 { 379 public: 380 explicit ProjectNode(const Utils::FilePath &projectFilePath); 381 382 virtual bool canAddSubProject(const QString &proFilePath) const; 383 virtual bool addSubProject(const QString &proFile); 384 virtual QStringList subProjectFileNamePatterns() const; 385 virtual bool removeSubProject(const QString &proFilePath); visibleAfterAddFileAction()386 virtual Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const { 387 return Utils::nullopt; 388 } 389 isFolderNodeType()390 bool isFolderNodeType() const override { return false; } isProjectNodeType()391 bool isProjectNodeType() const override { return true; } showInSimpleTree()392 bool showInSimpleTree() const override { return true; } 393 394 bool addFiles(const Utils::FilePaths &filePaths, Utils::FilePaths *notAdded = nullptr) final; 395 RemovedFilesFromProject removeFiles(const Utils::FilePaths &filePaths, 396 Utils::FilePaths *notRemoved = nullptr) final; 397 bool deleteFiles(const Utils::FilePaths &filePaths) final; 398 bool canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final; 399 bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) final; 400 bool addDependencies(const QStringList &dependencies) final; 401 bool supportsAction(ProjectAction action, const Node *node) const final; 402 403 // by default returns false 404 virtual bool deploysFolder(const QString &folder) const; 405 406 ProjectNode *projectNode(const Utils::FilePath &file) const; 407 asProjectNode()408 ProjectNode *asProjectNode() final { return this; } asProjectNode()409 const ProjectNode *asProjectNode() const final { return this; } 410 targetApplications()411 virtual QStringList targetApplications() const { return {}; } parseInProgress()412 virtual bool parseInProgress() const { return false; } 413 validParse()414 virtual bool validParse() const { return false; } 415 virtual QVariant data(Utils::Id role) const; 416 virtual bool setData(Utils::Id role, const QVariant &value) const; 417 isProduct()418 bool isProduct() const { return m_productType != ProductType::None; } productType()419 ProductType productType() const { return m_productType; } 420 421 // TODO: Currently used only for "Build for current run config" functionality, but we should 422 // probably use it to centralize the node-specific "Build" functionality that 423 // currently each project manager plugin adds to the context menu by itself. 424 // The function should then move up to the Node class, so it can also serve the 425 // "build single file" case. build()426 virtual void build() {} 427 428 void setFallbackData(Utils::Id key, const QVariant &value); 429 430 protected: setProductType(ProductType type)431 void setProductType(ProductType type) { m_productType = type; } 432 433 QString m_target; 434 435 private: 436 BuildSystem *buildSystem() const; 437 438 QHash<Utils::Id, QVariant> m_fallbackData; // Used in data(), unless overridden. 439 ProductType m_productType = ProductType::None; 440 }; 441 442 class PROJECTEXPLORER_EXPORT ContainerNode : public FolderNode 443 { 444 public: 445 ContainerNode(Project *project); 446 447 QString displayName() const final; 448 bool supportsAction(ProjectAction action, const Node *node) const final; 449 isFolderNodeType()450 bool isFolderNodeType() const override { return false; } isProjectNodeType()451 bool isProjectNodeType() const override { return true; } 452 asContainerNode()453 ContainerNode *asContainerNode() final { return this; } asContainerNode()454 const ContainerNode *asContainerNode() const final { return this; } 455 456 ProjectNode *rootProjectNode() const; project()457 Project *project() const { return m_project; } 458 459 void removeAllChildren(); 460 461 private: 462 void handleSubTreeChanged(FolderNode *node) final; 463 464 Project *m_project; 465 }; 466 467 } // namespace ProjectExplorer 468 469 Q_DECLARE_METATYPE(ProjectExplorer::Node *) 470 Q_DECLARE_METATYPE(ProjectExplorer::FolderNode *) 471