2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "projectnodes.h"
|
2008-12-09 15:25:01 +01:00
|
|
|
|
|
|
|
|
#include "nodesvisitor.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "projectexplorerconstants.h"
|
2015-01-09 15:50:06 +01:00
|
|
|
#include "projecttree.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-03-10 13:56:57 +01:00
|
|
|
#include <coreplugin/fileiconprovider.h>
|
2012-11-07 21:17:11 +02:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/iversioncontrol.h>
|
|
|
|
|
#include <coreplugin/vcsmanager.h>
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2015-01-10 23:40:32 +02:00
|
|
|
#include <utils/fileutils.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QIcon>
|
|
|
|
|
#include <QStyle>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
namespace ProjectExplorer {
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
/*!
|
2011-04-14 12:58:14 +02:00
|
|
|
\class ProjectExplorer::Node
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The Node class is the base class of all nodes in the node hierarchy.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
The nodes are arranged in a tree where leaves are FileNodes and non-leaves are FolderNodes
|
|
|
|
|
A Project is a special Folder that manages the files and normal folders underneath it.
|
|
|
|
|
|
|
|
|
|
The Watcher emits signals for structural changes in the hierarchy.
|
|
|
|
|
A Visitor can be used to traverse all Projects and other Folders.
|
|
|
|
|
|
|
|
|
|
\sa ProjectExplorer::FileNode, ProjectExplorer::FolderNode, ProjectExplorer::ProjectNode
|
|
|
|
|
\sa ProjectExplorer::NodesWatcher, ProjectExplorer::NodesVisitor
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2011-04-14 12:58:14 +02:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
Node::Node(NodeType nodeType, const Utils::FileName &filePath, int line) :
|
2016-10-31 13:33:13 +01:00
|
|
|
m_filePath(filePath), m_line(line), m_nodeType(nodeType)
|
2016-04-13 15:52:14 +02:00
|
|
|
{ }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-02-01 12:20:15 +01:00
|
|
|
void Node::emitNodeSortKeyAboutToChange()
|
|
|
|
|
{
|
2015-01-09 15:50:06 +01:00
|
|
|
if (parentFolderNode())
|
|
|
|
|
ProjectTree::instance()->emitNodeSortKeyAboutToChange(this);
|
2013-02-01 12:20:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Node::emitNodeSortKeyChanged()
|
|
|
|
|
{
|
2015-01-09 15:50:06 +01:00
|
|
|
if (parentFolderNode())
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitNodeSortKeyChanged(this);
|
2013-02-01 12:20:15 +01:00
|
|
|
}
|
|
|
|
|
|
2015-10-29 17:53:47 +01:00
|
|
|
void Node::setAbsoluteFilePathAndLine(const Utils::FileName &path, int line)
|
2013-01-30 18:13:46 +01:00
|
|
|
{
|
2015-10-29 17:53:47 +01:00
|
|
|
if (m_filePath == path && m_line == line)
|
2013-02-01 12:20:15 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
emitNodeSortKeyAboutToChange();
|
2015-10-29 17:53:47 +01:00
|
|
|
m_filePath = path;
|
2014-02-18 18:06:05 +01:00
|
|
|
m_line = line;
|
|
|
|
|
emitNodeSortKeyChanged();
|
|
|
|
|
emitNodeUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
NodeType Node::nodeType() const
|
|
|
|
|
{
|
|
|
|
|
return m_nodeType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
The project that owns and manages the node. It is the first project in the list
|
|
|
|
|
of ancestors.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2016-11-09 13:39:59 +01:00
|
|
|
ProjectNode *Node::parentProjectNode() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
return m_projectNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
The parent in the node hierarchy.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
FolderNode *Node::parentFolderNode() const
|
|
|
|
|
{
|
|
|
|
|
return m_folderNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
The path of the file or folder in the filesystem the node represents.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2015-10-29 17:53:47 +01:00
|
|
|
const Utils::FileName &Node::filePath() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2015-10-29 17:53:47 +01:00
|
|
|
return m_filePath;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-01-30 18:13:46 +01:00
|
|
|
int Node::line() const
|
|
|
|
|
{
|
2014-07-22 13:15:03 +02:00
|
|
|
return m_line;
|
2013-01-30 18:13:46 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-04 11:49:37 +02:00
|
|
|
QString Node::displayName() const
|
|
|
|
|
{
|
2015-10-29 17:53:47 +01:00
|
|
|
return filePath().fileName();
|
2012-05-04 11:49:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString Node::tooltip() const
|
|
|
|
|
{
|
2015-10-29 17:53:47 +01:00
|
|
|
return filePath().toUserOutput();
|
2012-05-04 11:49:37 +02:00
|
|
|
}
|
|
|
|
|
|
2013-01-16 15:27:03 +01:00
|
|
|
bool Node::isEnabled() const
|
|
|
|
|
{
|
2016-10-31 13:55:52 +01:00
|
|
|
if (!m_isEnabled)
|
|
|
|
|
return false;
|
|
|
|
|
FolderNode *parent = parentFolderNode();
|
|
|
|
|
return parent ? parent->isEnabled() : true;
|
2013-01-16 15:27:03 +01:00
|
|
|
}
|
|
|
|
|
|
2014-02-03 14:45:28 +01:00
|
|
|
QList<ProjectAction> Node::supportedActions(Node *node) const
|
|
|
|
|
{
|
2014-02-18 16:31:36 +01:00
|
|
|
QList<ProjectAction> list = parentFolderNode()->supportedActions(node);
|
2015-02-03 23:59:04 +02:00
|
|
|
list.append(InheritedFromParent);
|
2014-02-18 16:31:36 +01:00
|
|
|
return list;
|
2014-02-03 14:45:28 +01:00
|
|
|
}
|
|
|
|
|
|
2016-10-31 13:55:52 +01:00
|
|
|
void Node::setEnabled(bool enabled)
|
|
|
|
|
{
|
|
|
|
|
if (m_isEnabled == enabled)
|
|
|
|
|
return;
|
|
|
|
|
m_isEnabled = enabled;
|
|
|
|
|
emitNodeUpdated();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Node::setProjectNode(ProjectNode *project)
|
|
|
|
|
{
|
|
|
|
|
m_projectNode = project;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-16 15:27:03 +01:00
|
|
|
void Node::emitNodeUpdated()
|
|
|
|
|
{
|
2015-01-09 15:50:06 +01:00
|
|
|
if (parentFolderNode())
|
|
|
|
|
ProjectTree::instance()->emitNodeUpdated(this);
|
2013-01-16 15:27:03 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
FileNode *Node::asFileNode()
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
return nullptr;
|
2015-02-18 13:10:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FolderNode *Node::asFolderNode()
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
return nullptr;
|
2015-02-18 13:10:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProjectNode *Node::asProjectNode()
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
return nullptr;
|
2015-02-18 13:10:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SessionNode *Node::asSessionNode()
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
return nullptr;
|
2015-02-18 13:10:40 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-01 17:08:39 +01:00
|
|
|
bool Node::sortByPath(Node *a, Node *b)
|
|
|
|
|
{
|
|
|
|
|
return a->filePath() < b->filePath();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void Node::setParentFolderNode(FolderNode *parentFolder)
|
|
|
|
|
{
|
|
|
|
|
m_folderNode = parentFolder;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2011-04-14 12:58:14 +02:00
|
|
|
\class ProjectExplorer::FileNode
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-10 17:16:10 +02:00
|
|
|
\brief The FileNode class is an in-memory presentation of a file.
|
|
|
|
|
|
|
|
|
|
All file nodes are leaf nodes.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
\sa ProjectExplorer::FolderNode, ProjectExplorer::ProjectNode
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
2015-02-02 00:37:38 +02:00
|
|
|
FileNode::FileNode(const Utils::FileName &filePath,
|
2008-12-02 12:01:29 +01:00
|
|
|
const FileType fileType,
|
2016-10-31 13:33:13 +01:00
|
|
|
bool generated, int line) : Node(NodeType::File, filePath, line),
|
2016-04-13 15:52:14 +02:00
|
|
|
m_fileType(fileType),
|
|
|
|
|
m_generated(generated)
|
|
|
|
|
{ }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
FileType FileNode::fileType() const
|
|
|
|
|
{
|
|
|
|
|
return m_fileType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Returns \c true if the file is automatically generated by a compile step.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
bool FileNode::isGenerated() const
|
|
|
|
|
{
|
|
|
|
|
return m_generated;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
FileNode *FileNode::asFileNode()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-20 13:27:10 +02:00
|
|
|
static QList<FileNode *> scanForFilesRecursively(const Utils::FileName &directory,
|
|
|
|
|
const std::function<FileNode *(const Utils::FileName &)> factory,
|
|
|
|
|
QSet<QString> &visited, QFutureInterface<QList<FileNode*>> *future,
|
|
|
|
|
double progressStart, double progressRange)
|
|
|
|
|
{
|
|
|
|
|
QList<FileNode *> result;
|
|
|
|
|
const QDir baseDir = QDir(directory.toString());
|
|
|
|
|
|
|
|
|
|
// Do not follow directory loops:
|
|
|
|
|
const int visitedCount = visited.count();
|
|
|
|
|
visited.insert(baseDir.canonicalPath());
|
|
|
|
|
if (visitedCount == visited.count())
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
const Core::IVersionControl *vcsControl
|
|
|
|
|
= Core::VcsManager::findVersionControlForDirectory(baseDir.absolutePath(), nullptr);
|
|
|
|
|
const QList<QFileInfo> entries = baseDir.entryInfoList(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot);
|
|
|
|
|
double progress = 0;
|
|
|
|
|
const double progressIncrement = progressRange / static_cast<double>(entries.count());
|
|
|
|
|
int lastIntProgress = 0;
|
|
|
|
|
for (const QFileInfo &entry : entries) {
|
|
|
|
|
const Utils::FileName entryName = Utils::FileName::fromString(entry.absoluteFilePath());
|
|
|
|
|
if (!vcsControl || !vcsControl->isVcsFileOrDirectory(entryName)) {
|
|
|
|
|
if (entry.isDir())
|
|
|
|
|
result.append(scanForFilesRecursively(entryName, factory, visited, future, progress, progressIncrement));
|
|
|
|
|
else
|
|
|
|
|
result.append(factory(entryName));
|
|
|
|
|
}
|
|
|
|
|
if (future) {
|
|
|
|
|
progress += progressIncrement;
|
|
|
|
|
const int intProgress = std::min(static_cast<int>(progressStart + progress), future->progressMaximum());
|
|
|
|
|
if (lastIntProgress < intProgress) {
|
|
|
|
|
future->setProgressValue(intProgress);
|
|
|
|
|
lastIntProgress = intProgress;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (future)
|
|
|
|
|
future->setProgressValue(std::min(static_cast<int>(progressStart + progressRange), future->progressMaximum()));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<FileNode *> FileNode::scanForFiles(const Utils::FileName &directory,
|
|
|
|
|
const std::function<FileNode *(const Utils::FileName &)> factory,
|
|
|
|
|
QFutureInterface<QList<FileNode*>> *future)
|
|
|
|
|
{
|
|
|
|
|
QSet<QString> visited;
|
|
|
|
|
future->setProgressRange(0, 1000000);
|
|
|
|
|
return scanForFilesRecursively(directory, factory, visited, future, 0.0, 1000000.0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2011-04-14 12:58:14 +02:00
|
|
|
\class ProjectExplorer::FolderNode
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
In-memory presentation of a folder. Note that the node itself + all children (files and folders) are "managed" by the owning project.
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2015-02-02 00:37:38 +02:00
|
|
|
FolderNode::FolderNode(const Utils::FileName &folderPath, NodeType nodeType, const QString &displayName) :
|
2012-05-04 11:49:37 +02:00
|
|
|
Node(nodeType, folderPath),
|
2014-09-23 13:05:00 +02:00
|
|
|
m_displayName(displayName)
|
2010-02-12 12:54:12 +01:00
|
|
|
{
|
2014-09-23 13:05:00 +02:00
|
|
|
if (m_displayName.isEmpty())
|
2015-02-02 00:37:38 +02:00
|
|
|
m_displayName = folderPath.toUserOutput();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FolderNode::~FolderNode()
|
|
|
|
|
{
|
2016-11-09 12:28:25 +01:00
|
|
|
qDeleteAll(m_folderNodes);
|
2008-12-02 12:01:29 +01:00
|
|
|
qDeleteAll(m_fileNodes);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Contains the display name that should be used in a view.
|
2011-04-14 12:58:14 +02:00
|
|
|
\sa setFolderName()
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2011-04-14 12:58:14 +02:00
|
|
|
|
2010-01-07 18:17:24 +01:00
|
|
|
QString FolderNode::displayName() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2010-02-24 15:03:54 +01:00
|
|
|
return m_displayName;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Contains the icon that should be used in a view. Default is the directory icon
|
|
|
|
|
(QStyle::S_PDirIcon).
|
2011-04-14 12:58:14 +02:00
|
|
|
s\a setIcon()
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
QIcon FolderNode::icon() const
|
|
|
|
|
{
|
2010-07-07 12:16:09 +02:00
|
|
|
// Instantiating the Icon provider is expensive.
|
|
|
|
|
if (m_icon.isNull())
|
2013-09-12 16:06:33 +02:00
|
|
|
m_icon = Core::FileIconProvider::icon(QFileIconProvider::Folder);
|
2008-12-02 12:01:29 +01:00
|
|
|
return m_icon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<FileNode*> FolderNode::fileNodes() const
|
|
|
|
|
{
|
|
|
|
|
return m_fileNodes;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-07 12:11:26 +01:00
|
|
|
FileNode *FolderNode::fileNode(const Utils::FileName &file) const
|
|
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(m_fileNodes, [&file](const FileNode *fn) {
|
|
|
|
|
return fn->filePath() == file;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileNode *FolderNode::recursiveFileNode(const Utils::FileName &file) const
|
|
|
|
|
{
|
|
|
|
|
Utils::FileName dir = file.parentDir();
|
|
|
|
|
|
|
|
|
|
const QDir thisDir(filePath().toString());
|
|
|
|
|
QString relativePath = thisDir.relativeFilePath(dir.toString());
|
|
|
|
|
if (relativePath == ".")
|
|
|
|
|
relativePath.clear();
|
|
|
|
|
QStringList parts = relativePath.split('/', QString::SkipEmptyParts);
|
|
|
|
|
const ProjectExplorer::FolderNode *parent = this;
|
|
|
|
|
foreach (const QString &part, parts) {
|
|
|
|
|
dir.appendPath(part);
|
|
|
|
|
// Find folder in subFolders
|
|
|
|
|
parent = Utils::findOrDefault(parent->folderNodes(), [&dir](const FolderNode *fn) {
|
|
|
|
|
return fn->filePath() == dir;
|
|
|
|
|
});
|
|
|
|
|
if (!parent)
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return parent->fileNode(file);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-30 20:33:34 +02:00
|
|
|
QList<FileNode *> FolderNode::recursiveFileNodes() const
|
|
|
|
|
{
|
|
|
|
|
QList<FileNode *> result = fileNodes();
|
2016-11-09 12:28:25 +01:00
|
|
|
foreach (ProjectExplorer::FolderNode *folder, folderNodes())
|
2016-09-30 20:33:34 +02:00
|
|
|
result.append(folder->recursiveFileNodes());
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 12:28:25 +01:00
|
|
|
QList<FolderNode*> FolderNode::folderNodes() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-11-09 12:28:25 +01:00
|
|
|
return m_folderNodes;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-07 12:11:26 +01:00
|
|
|
FolderNode *FolderNode::folderNode(const Utils::FileName &directory) const
|
|
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(m_folderNodes, [&directory](const FolderNode *fn) {
|
|
|
|
|
return fn->filePath() == directory;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FolderNode *FolderNode::recursiveFindOrCreateFolderNode(const QString &directory)
|
2016-09-30 20:33:34 +02:00
|
|
|
{
|
|
|
|
|
Utils::FileName path = filePath();
|
|
|
|
|
QDir parentDir(path.toString());
|
|
|
|
|
QString relativePath = parentDir.relativeFilePath(directory);
|
|
|
|
|
if (relativePath == ".")
|
|
|
|
|
relativePath.clear();
|
2016-11-07 12:11:26 +01:00
|
|
|
|
2016-09-30 20:33:34 +02:00
|
|
|
QStringList parts = relativePath.split('/', QString::SkipEmptyParts);
|
|
|
|
|
ProjectExplorer::FolderNode *parent = this;
|
|
|
|
|
foreach (const QString &part, parts) {
|
|
|
|
|
path.appendPath(part);
|
|
|
|
|
// Find folder in subFolders
|
2016-11-07 12:11:26 +01:00
|
|
|
FolderNode *next = parent->folderNode(path);
|
|
|
|
|
if (!next) {
|
2016-09-30 20:33:34 +02:00
|
|
|
// No FolderNode yet, so create it
|
|
|
|
|
auto tmp = new ProjectExplorer::FolderNode(path);
|
|
|
|
|
tmp->setDisplayName(part);
|
|
|
|
|
parent->addFolderNodes(QList<ProjectExplorer::FolderNode *>({ tmp }));
|
2016-11-07 12:11:26 +01:00
|
|
|
next = tmp;
|
2016-09-30 20:33:34 +02:00
|
|
|
}
|
2016-11-07 12:11:26 +01:00
|
|
|
parent = next;
|
2016-09-30 20:33:34 +02:00
|
|
|
}
|
|
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNode::buildTree(QList<FileNode *> &files)
|
|
|
|
|
{
|
|
|
|
|
// Gather old list
|
|
|
|
|
QList<ProjectExplorer::FileNode *> oldFiles = recursiveFileNodes();
|
2016-11-01 17:08:39 +01:00
|
|
|
Utils::sort(oldFiles, Node::sortByPath);
|
|
|
|
|
Utils::sort(files, Node::sortByPath);
|
2016-09-30 20:33:34 +02:00
|
|
|
|
|
|
|
|
QList<ProjectExplorer::FileNode *> added;
|
|
|
|
|
QList<ProjectExplorer::FileNode *> deleted;
|
|
|
|
|
|
2016-11-01 17:08:39 +01:00
|
|
|
ProjectExplorer::compareSortedLists(oldFiles, files, deleted, added, Node::sortByPath);
|
2016-09-30 20:33:34 +02:00
|
|
|
|
2016-11-01 17:08:39 +01:00
|
|
|
qDeleteAll(ProjectExplorer::subtractSortedList(files, added, Node::sortByPath));
|
2016-09-30 20:33:34 +02:00
|
|
|
|
|
|
|
|
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > addedFolderMapping;
|
|
|
|
|
QHash<ProjectExplorer::FolderNode *, QList<ProjectExplorer::FileNode *> > deletedFolderMapping;
|
|
|
|
|
|
|
|
|
|
// add added nodes
|
|
|
|
|
foreach (ProjectExplorer::FileNode *fn, added) {
|
|
|
|
|
// Get relative path to rootNode
|
|
|
|
|
QString parentDir = fn->filePath().toFileInfo().absolutePath();
|
2016-11-07 12:11:26 +01:00
|
|
|
ProjectExplorer::FolderNode *folder = recursiveFindOrCreateFolderNode(parentDir);
|
2016-09-30 20:33:34 +02:00
|
|
|
addedFolderMapping[folder] << fn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto i = addedFolderMapping.constBegin(); i != addedFolderMapping.constEnd(); ++i)
|
|
|
|
|
i.key()->addFileNodes(i.value());
|
|
|
|
|
|
|
|
|
|
// remove old file nodes and check whether folder nodes can be removed
|
|
|
|
|
foreach (ProjectExplorer::FileNode *fn, deleted)
|
|
|
|
|
deletedFolderMapping[fn->parentFolderNode()] << fn;
|
|
|
|
|
|
|
|
|
|
for (auto i = deletedFolderMapping.constBegin(); i != deletedFolderMapping.constEnd(); ++i) {
|
|
|
|
|
ProjectExplorer::FolderNode *parent = i.key();
|
|
|
|
|
parent->removeFileNodes(i.value());
|
2016-11-04 14:20:25 +01:00
|
|
|
|
|
|
|
|
if (parent == this) // Never delete this node!
|
|
|
|
|
continue;
|
|
|
|
|
|
2016-09-30 20:33:34 +02:00
|
|
|
// Check for empty parent
|
2016-11-09 12:28:25 +01:00
|
|
|
while (parent->folderNodes().isEmpty() && parent->fileNodes().isEmpty()) {
|
2016-09-30 20:33:34 +02:00
|
|
|
ProjectExplorer::FolderNode *grandparent = parent->parentFolderNode();
|
|
|
|
|
grandparent->removeFolderNodes(QList<ProjectExplorer::FolderNode *>() << parent);
|
|
|
|
|
parent = grandparent;
|
|
|
|
|
if (parent == this)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void FolderNode::accept(NodesVisitor *visitor)
|
|
|
|
|
{
|
|
|
|
|
visitor->visitFolderNode(this);
|
2016-11-09 12:28:25 +01:00
|
|
|
foreach (FolderNode *subFolder, m_folderNodes)
|
2008-12-02 12:01:29 +01:00
|
|
|
subFolder->accept(visitor);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-24 15:03:54 +01:00
|
|
|
void FolderNode::setDisplayName(const QString &name)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-02-01 12:20:15 +01:00
|
|
|
if (m_displayName == name)
|
|
|
|
|
return;
|
|
|
|
|
emitNodeSortKeyAboutToChange();
|
2010-02-24 15:03:54 +01:00
|
|
|
m_displayName = name;
|
2013-02-01 12:20:15 +01:00
|
|
|
emitNodeSortKeyChanged();
|
|
|
|
|
emitNodeUpdated();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNode::setIcon(const QIcon &icon)
|
|
|
|
|
{
|
|
|
|
|
m_icon = icon;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-02 17:00:46 +01:00
|
|
|
QString FolderNode::addFileFilter() const
|
|
|
|
|
{
|
|
|
|
|
return parentFolderNode()->addFileFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 15:18:33 +01:00
|
|
|
bool FolderNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
if (parentProjectNode())
|
|
|
|
|
return parentProjectNode()->addFiles(filePaths, notAdded);
|
2014-02-03 15:18:33 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FolderNode::removeFiles(const QStringList &filePaths, QStringList *notRemoved)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
if (parentProjectNode())
|
|
|
|
|
return parentProjectNode()->removeFiles(filePaths, notRemoved);
|
2014-02-03 15:18:33 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FolderNode::deleteFiles(const QStringList &filePaths)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
if (parentProjectNode())
|
|
|
|
|
return parentProjectNode()->deleteFiles(filePaths);
|
2014-02-03 15:18:33 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-14 15:33:50 +02:00
|
|
|
bool FolderNode::canRenameFile(const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
if (parentProjectNode())
|
|
|
|
|
return parentProjectNode()->canRenameFile(filePath, newFilePath);
|
2015-09-14 15:33:50 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-03 15:18:33 +01:00
|
|
|
bool FolderNode::renameFile(const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
if (parentProjectNode())
|
|
|
|
|
return parentProjectNode()->renameFile(filePath, newFilePath);
|
2014-02-03 15:18:33 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-07 16:23:04 +01:00
|
|
|
FolderNode::AddNewInformation FolderNode::addNewInformation(const QStringList &files, Node *context) const
|
2014-02-18 16:31:36 +01:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(files);
|
2015-04-08 17:01:01 +02:00
|
|
|
return AddNewInformation(displayName(), context == this ? 120 : 100);
|
2014-02-18 16:31:36 +01:00
|
|
|
}
|
|
|
|
|
|
2014-02-18 19:49:55 +01:00
|
|
|
/*!
|
|
|
|
|
Adds file nodes specified by \a files to the internal list of the folder
|
|
|
|
|
and emits the corresponding signals from the projectNode.
|
|
|
|
|
|
|
|
|
|
This function should be called within an implementation of the public function
|
|
|
|
|
addFiles.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void FolderNode::addFileNodes(const QList<FileNode *> &files)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
Q_ASSERT(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
if (files.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-20 15:24:58 +01:00
|
|
|
ProjectTree::instance()->emitFilesAboutToBeAdded(this, files);
|
2014-02-18 19:49:55 +01:00
|
|
|
|
|
|
|
|
foreach (FileNode *file, files) {
|
|
|
|
|
QTC_ASSERT(!file->parentFolderNode(),
|
|
|
|
|
qDebug("File node has already a parent folder"));
|
|
|
|
|
|
|
|
|
|
file->setParentFolderNode(this);
|
2016-11-09 13:39:59 +01:00
|
|
|
file->setProjectNode(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
// Now find the correct place to insert file
|
|
|
|
|
if (m_fileNodes.count() == 0
|
|
|
|
|
|| m_fileNodes.last() < file) {
|
|
|
|
|
// empty list or greater then last node
|
|
|
|
|
m_fileNodes.append(file);
|
|
|
|
|
} else {
|
2016-08-03 23:29:58 +03:00
|
|
|
auto it = std::lower_bound(m_fileNodes.begin(), m_fileNodes.end(), file);
|
2014-02-18 19:49:55 +01:00
|
|
|
m_fileNodes.insert(it, file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFilesAdded(this);
|
2014-02-18 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Removes \a files from the internal list and emits the corresponding signals.
|
|
|
|
|
|
|
|
|
|
All objects in the \a files list are deleted.
|
|
|
|
|
This function should be called within an implementation of the public function
|
|
|
|
|
removeFiles.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void FolderNode::removeFileNodes(const QList<FileNode *> &files)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
Q_ASSERT(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
|
|
|
|
|
if (files.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QList<FileNode*> toRemove = files;
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(toRemove);
|
2014-02-18 19:49:55 +01:00
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFilesAboutToBeRemoved(this, toRemove);
|
2014-02-18 19:49:55 +01:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto toRemoveIter = toRemove.constBegin();
|
|
|
|
|
auto filesIter = m_fileNodes.begin();
|
2014-02-18 19:49:55 +01:00
|
|
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
|
|
|
|
while (*filesIter != *toRemoveIter) {
|
|
|
|
|
++filesIter;
|
|
|
|
|
QTC_ASSERT(filesIter != m_fileNodes.end(),
|
|
|
|
|
qDebug("File to remove is not part of specified folder!"));
|
|
|
|
|
}
|
|
|
|
|
delete *filesIter;
|
|
|
|
|
filesIter = m_fileNodes.erase(filesIter);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFilesRemoved(this);
|
2014-02-18 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Adds folder nodes specified by \a subFolders to the node hierarchy below
|
|
|
|
|
\a parentFolder and emits the corresponding signals.
|
|
|
|
|
*/
|
|
|
|
|
void FolderNode::addFolderNodes(const QList<FolderNode*> &subFolders)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
Q_ASSERT(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
|
|
|
|
|
if (subFolders.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, subFolders);
|
2014-02-18 19:49:55 +01:00
|
|
|
foreach (FolderNode *folder, subFolders) {
|
|
|
|
|
QTC_ASSERT(!folder->parentFolderNode(),
|
|
|
|
|
qDebug("Project node has already a parent folder"));
|
|
|
|
|
folder->setParentFolderNode(this);
|
2016-11-09 13:39:59 +01:00
|
|
|
folder->setProjectNode(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
|
|
|
|
|
// Find the correct place to insert
|
2016-11-09 12:28:25 +01:00
|
|
|
if (m_folderNodes.count() == 0
|
|
|
|
|
|| m_folderNodes.last() < folder) {
|
2014-02-18 19:49:55 +01:00
|
|
|
// empty list or greater then last node
|
2016-11-09 12:28:25 +01:00
|
|
|
m_folderNodes.append(folder);
|
2014-02-18 19:49:55 +01:00
|
|
|
} else {
|
|
|
|
|
// Binary Search for insertion point
|
2016-11-09 12:28:25 +01:00
|
|
|
auto it = std::lower_bound(m_folderNodes.begin(), m_folderNodes.end(), folder);
|
|
|
|
|
m_folderNodes.insert(it, folder);
|
2014-02-18 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// project nodes have to be added via addProjectNodes
|
2016-10-31 13:33:13 +01:00
|
|
|
QTC_ASSERT(folder->nodeType() != NodeType::Project,
|
2014-02-18 19:49:55 +01:00
|
|
|
qDebug("project nodes have to be added via addProjectNodes"));
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAdded(this);
|
2014-02-18 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
Removes file nodes specified by \a subFolders from the node hierarchy and emits
|
|
|
|
|
the corresponding signals.
|
|
|
|
|
|
|
|
|
|
All objects in the \a subFolders list are deleted.
|
|
|
|
|
*/
|
|
|
|
|
void FolderNode::removeFolderNodes(const QList<FolderNode*> &subFolders)
|
|
|
|
|
{
|
2016-11-09 13:39:59 +01:00
|
|
|
Q_ASSERT(parentProjectNode());
|
2014-02-18 19:49:55 +01:00
|
|
|
|
|
|
|
|
if (subFolders.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QList<FolderNode*> toRemove = subFolders;
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(toRemove);
|
2014-02-18 19:49:55 +01:00
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
2014-02-18 19:49:55 +01:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto toRemoveIter = toRemove.constBegin();
|
2016-11-09 12:28:25 +01:00
|
|
|
auto folderIter = m_folderNodes.begin();
|
2014-02-18 19:49:55 +01:00
|
|
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
2016-10-31 13:33:13 +01:00
|
|
|
QTC_ASSERT((*toRemoveIter)->nodeType() != NodeType::Project,
|
2014-02-18 19:49:55 +01:00
|
|
|
qDebug("project nodes have to be removed via removeProjectNodes"));
|
|
|
|
|
while (*folderIter != *toRemoveIter) {
|
|
|
|
|
++folderIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
QTC_ASSERT(folderIter != m_folderNodes.end(),
|
2014-02-18 19:49:55 +01:00
|
|
|
qDebug("Folder to remove is not part of specified folder!"));
|
|
|
|
|
}
|
|
|
|
|
delete *folderIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
folderIter = m_folderNodes.erase(folderIter);
|
2014-02-18 19:49:55 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersRemoved(this);
|
2014-03-17 11:52:45 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
FolderNode *FolderNode::asFolderNode()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-17 11:52:45 +01:00
|
|
|
bool FolderNode::showInSimpleTree() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-04 11:49:37 +02:00
|
|
|
/*!
|
|
|
|
|
\class ProjectExplorer::VirtualFolderNode
|
|
|
|
|
|
|
|
|
|
In-memory presentation of a virtual folder.
|
|
|
|
|
Note that the node itself + all children (files and folders) are "managed" by the owning project.
|
|
|
|
|
A virtual folder does not correspond to a actual folder on the file system. See for example the
|
2013-10-29 17:37:39 +01:00
|
|
|
sources, headers and forms folder the QmakeProjectManager creates
|
2012-05-04 11:49:37 +02:00
|
|
|
VirtualFolderNodes are always sorted before FolderNodes and are sorted according to their priority.
|
|
|
|
|
|
|
|
|
|
\sa ProjectExplorer::FileNode, ProjectExplorer::ProjectNode
|
|
|
|
|
*/
|
2016-04-13 15:52:14 +02:00
|
|
|
VirtualFolderNode::VirtualFolderNode(const Utils::FileName &folderPath, int priority) :
|
2016-10-31 13:33:13 +01:00
|
|
|
FolderNode(folderPath, NodeType::VirtualFolder),
|
2016-04-13 15:52:14 +02:00
|
|
|
m_priority(priority)
|
|
|
|
|
{ }
|
2012-05-04 11:49:37 +02:00
|
|
|
|
|
|
|
|
int VirtualFolderNode::priority() const
|
|
|
|
|
{
|
|
|
|
|
return m_priority;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2011-04-14 12:58:14 +02:00
|
|
|
\class ProjectExplorer::ProjectNode
|
|
|
|
|
|
2013-09-10 17:16:10 +02:00
|
|
|
\brief The ProjectNode class is an in-memory presentation of a Project.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-10 17:16:10 +02:00
|
|
|
A concrete subclass must implement the persistent data.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
\sa ProjectExplorer::FileNode, ProjectExplorer::FolderNode
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Creates an uninitialized project node object.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2016-04-13 15:52:14 +02:00
|
|
|
ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) :
|
2016-10-31 13:33:13 +01:00
|
|
|
FolderNode(projectFilePath, NodeType::Project)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
// project node "manages" itself
|
|
|
|
|
setProjectNode(this);
|
2015-02-02 00:37:38 +02:00
|
|
|
setDisplayName(projectFilePath.fileName());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-08-30 17:13:29 +02:00
|
|
|
QString ProjectNode::vcsTopic() const
|
|
|
|
|
{
|
2015-10-29 17:53:47 +01:00
|
|
|
const QString dir = filePath().toFileInfo().absolutePath();
|
2012-11-07 21:17:11 +02:00
|
|
|
|
|
|
|
|
if (Core::IVersionControl *const vc =
|
2013-08-30 17:13:29 +02:00
|
|
|
Core::VcsManager::findVersionControlForDirectory(dir))
|
2012-11-07 21:17:11 +02:00
|
|
|
return vc->vcsTopic(dir);
|
|
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::canAddSubProject(const QString &proFilePath) const
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(proFilePath)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::addSubProjects(const QStringList &proFilePaths)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(proFilePaths)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::removeSubProjects(const QStringList &proFilePaths)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(proFilePaths)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::addFiles(const QStringList &filePaths, QStringList *notAdded)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(filePaths)
|
|
|
|
|
Q_UNUSED(notAdded)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::removeFiles(const QStringList &filePaths, QStringList *notRemoved)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(filePaths)
|
|
|
|
|
Q_UNUSED(notRemoved)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProjectNode::deleteFiles(const QStringList &filePaths)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(filePaths)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-14 15:33:50 +02:00
|
|
|
bool ProjectNode::canRenameFile(const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(filePath);
|
|
|
|
|
Q_UNUSED(newFilePath);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-10 17:47:57 +02:00
|
|
|
bool ProjectNode::renameFile(const QString &filePath, const QString &newFilePath)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(filePath)
|
|
|
|
|
Q_UNUSED(newFilePath)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-08-24 17:17:11 +02:00
|
|
|
bool ProjectNode::deploysFolder(const QString &folder) const
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(folder);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 08:35:00 +02:00
|
|
|
/*!
|
|
|
|
|
\function bool ProjectNode::runConfigurations() const
|
|
|
|
|
|
|
|
|
|
Returns a list of \c RunConfiguration suitable for this node.
|
|
|
|
|
*/
|
|
|
|
|
QList<RunConfiguration *> ProjectNode::runConfigurations() const
|
|
|
|
|
{
|
|
|
|
|
return QList<RunConfiguration *>();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void ProjectNode::accept(NodesVisitor *visitor)
|
|
|
|
|
{
|
|
|
|
|
visitor->visitProjectNode(this);
|
|
|
|
|
|
2016-11-09 12:28:25 +01:00
|
|
|
foreach (FolderNode *folder, m_folderNodes)
|
2008-12-02 12:01:29 +01:00
|
|
|
folder->accept(visitor);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-07 13:56:57 +01:00
|
|
|
ProjectNode *ProjectNode::projectNode(const Utils::FileName &file) const
|
|
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(m_projectNodes, [&file](const ProjectNode *fn) {
|
|
|
|
|
return fn->filePath() == file;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<ProjectNode*> ProjectNode::projectNodes() const
|
|
|
|
|
{
|
|
|
|
|
return m_projectNodes;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Adds project nodes specified by \a subProjects to the node hierarchy and
|
|
|
|
|
emits the corresponding signals.
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
void ProjectNode::addProjectNodes(const QList<ProjectNode*> &subProjects)
|
|
|
|
|
{
|
|
|
|
|
if (!subProjects.isEmpty()) {
|
|
|
|
|
QList<FolderNode*> folderNodes;
|
|
|
|
|
foreach (ProjectNode *projectNode, subProjects)
|
|
|
|
|
folderNodes << projectNode;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
foreach (ProjectNode *project, subProjects) {
|
2010-05-20 16:02:24 +02:00
|
|
|
QTC_ASSERT(!project->parentFolderNode() || project->parentFolderNode() == this,
|
|
|
|
|
qDebug("Project node has already a parent"));
|
2008-12-02 12:01:29 +01:00
|
|
|
project->setParentFolderNode(this);
|
2016-11-09 12:28:25 +01:00
|
|
|
m_folderNodes.append(project);
|
|
|
|
|
m_projectNodes.append(project);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2016-11-09 12:28:25 +01:00
|
|
|
Utils::sort(m_folderNodes);
|
|
|
|
|
Utils::sort(m_projectNodes);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAdded(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Removes project nodes specified by \a subProjects from the node hierarchy
|
|
|
|
|
and emits the corresponding signals.
|
2011-04-14 12:58:14 +02:00
|
|
|
|
2013-09-10 17:16:10 +02:00
|
|
|
All objects in the \a subProjects list are deleted.
|
2011-04-14 12:58:14 +02:00
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void ProjectNode::removeProjectNodes(const QList<ProjectNode*> &subProjects)
|
|
|
|
|
{
|
|
|
|
|
if (!subProjects.isEmpty()) {
|
|
|
|
|
QList<FolderNode*> toRemove;
|
|
|
|
|
foreach (ProjectNode *projectNode, subProjects)
|
|
|
|
|
toRemove << projectNode;
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(toRemove);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2015-01-20 15:24:01 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto toRemoveIter = toRemove.constBegin();
|
2016-11-09 12:28:25 +01:00
|
|
|
auto folderIter = m_folderNodes.begin();
|
|
|
|
|
auto projectIter = m_projectNodes.begin();
|
2008-12-02 12:01:29 +01:00
|
|
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
2012-05-04 11:49:37 +02:00
|
|
|
while (*projectIter != *toRemoveIter) {
|
2008-12-02 12:01:29 +01:00
|
|
|
++projectIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
QTC_ASSERT(projectIter != m_projectNodes.end(),
|
2008-12-09 16:18:28 +01:00
|
|
|
qDebug("Project to remove is not part of specified folder!"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-05-04 11:49:37 +02:00
|
|
|
while (*folderIter != *toRemoveIter) {
|
2008-12-02 12:01:29 +01:00
|
|
|
++folderIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
QTC_ASSERT(folderIter != m_folderNodes.end(),
|
2008-12-09 16:18:28 +01:00
|
|
|
qDebug("Project to remove is not part of specified folder!"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
delete *projectIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
projectIter = m_projectNodes.erase(projectIter);
|
|
|
|
|
folderIter = m_folderNodes.erase(folderIter);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersRemoved(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
ProjectNode *ProjectNode::asProjectNode()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-17 17:59:57 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2011-04-14 12:58:14 +02:00
|
|
|
\class ProjectExplorer::SessionNode
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
SessionNode::SessionNode() :
|
2016-10-31 13:33:13 +01:00
|
|
|
FolderNode(Utils::FileName::fromString("session"), NodeType::Session)
|
2016-04-13 15:52:14 +02:00
|
|
|
{ }
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-02-03 14:45:28 +01:00
|
|
|
QList<ProjectAction> SessionNode::supportedActions(Node *node) const
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(node)
|
|
|
|
|
return QList<ProjectAction>();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
void SessionNode::accept(NodesVisitor *visitor)
|
|
|
|
|
{
|
|
|
|
|
visitor->visitSessionNode(this);
|
|
|
|
|
foreach (ProjectNode *project, m_projectNodes)
|
|
|
|
|
project->accept(visitor);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-17 11:52:45 +01:00
|
|
|
bool SessionNode::showInSimpleTree() const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-14 17:39:46 +02:00
|
|
|
void SessionNode::projectDisplayNameChanged(Node *node)
|
|
|
|
|
{
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitNodeSortKeyAboutToChange(node);
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitNodeSortKeyChanged(node);
|
2014-07-14 17:39:46 +02:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
SessionNode *SessionNode::asSessionNode()
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
QList<ProjectNode*> SessionNode::projectNodes() const
|
|
|
|
|
{
|
|
|
|
|
return m_projectNodes;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-02 17:00:46 +01:00
|
|
|
QString SessionNode::addFileFilter() const
|
|
|
|
|
{
|
2016-09-30 20:33:34 +02:00
|
|
|
return QString::fromLatin1("*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.hpp; *.hxx;");
|
2015-11-02 17:00:46 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void SessionNode::addProjectNodes(const QList<ProjectNode*> &projectNodes)
|
|
|
|
|
{
|
|
|
|
|
if (!projectNodes.isEmpty()) {
|
|
|
|
|
QList<FolderNode*> folderNodes;
|
|
|
|
|
foreach (ProjectNode *projectNode, projectNodes)
|
|
|
|
|
folderNodes << projectNode;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeAdded(this, folderNodes);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
foreach (ProjectNode *project, projectNodes) {
|
2008-12-09 16:18:28 +01:00
|
|
|
QTC_ASSERT(!project->parentFolderNode(),
|
|
|
|
|
qDebug("Project node has already a parent folder"));
|
2008-12-02 12:01:29 +01:00
|
|
|
project->setParentFolderNode(this);
|
2016-11-09 12:28:25 +01:00
|
|
|
m_folderNodes.append(project);
|
2008-12-02 12:01:29 +01:00
|
|
|
m_projectNodes.append(project);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 12:28:25 +01:00
|
|
|
Utils::sort(m_folderNodes);
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(m_projectNodes);
|
2012-05-04 11:49:37 +02:00
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAdded(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionNode::removeProjectNodes(const QList<ProjectNode*> &projectNodes)
|
|
|
|
|
{
|
|
|
|
|
if (!projectNodes.isEmpty()) {
|
|
|
|
|
QList<FolderNode*> toRemove;
|
|
|
|
|
foreach (ProjectNode *projectNode, projectNodes)
|
|
|
|
|
toRemove << projectNode;
|
|
|
|
|
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(toRemove);
|
2012-05-04 11:49:37 +02:00
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
ProjectTree::instance()->emitFoldersAboutToBeRemoved(this, toRemove);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto toRemoveIter = toRemove.constBegin();
|
2016-11-09 12:28:25 +01:00
|
|
|
auto folderIter = m_folderNodes.begin();
|
2016-04-13 15:52:14 +02:00
|
|
|
auto projectIter = m_projectNodes.begin();
|
2008-12-02 12:01:29 +01:00
|
|
|
for (; toRemoveIter != toRemove.constEnd(); ++toRemoveIter) {
|
2012-05-04 11:49:37 +02:00
|
|
|
while (*projectIter != *toRemoveIter) {
|
2008-12-02 12:01:29 +01:00
|
|
|
++projectIter;
|
2008-12-09 16:18:28 +01:00
|
|
|
QTC_ASSERT(projectIter != m_projectNodes.end(),
|
|
|
|
|
qDebug("Project to remove is not part of specified folder!"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2012-05-04 11:49:37 +02:00
|
|
|
while (*folderIter != *toRemoveIter) {
|
2008-12-02 12:01:29 +01:00
|
|
|
++folderIter;
|
2016-11-09 12:28:25 +01:00
|
|
|
QTC_ASSERT(folderIter != m_folderNodes.end(),
|
2008-12-09 16:18:28 +01:00
|
|
|
qDebug("Project to remove is not part of specified folder!"));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
projectIter = m_projectNodes.erase(projectIter);
|
2016-11-09 12:28:25 +01:00
|
|
|
folderIter = m_folderNodes.erase(folderIter);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
ProjectTree::instance()->emitFoldersRemoved(this);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-04-13 15:52:14 +02:00
|
|
|
|
|
|
|
|
} // namespace ProjectExplorer
|