2014-11-19 17:58:33 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
|
|
|
|
** Contact: http://www.qt-project.org/legal
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** 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
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://www.qt.io/licensing. For further information
|
|
|
|
|
** use the contact form at http://www.qt.io/contact-us.
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
|
|
|
**
|
|
|
|
|
** In addition, as a special exception, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
|
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "projecttree.h"
|
|
|
|
|
#include "projecttreewidget.h"
|
|
|
|
|
#include "session.h"
|
|
|
|
|
#include "project.h"
|
|
|
|
|
#include "projectnodes.h"
|
2015-01-13 15:50:37 +01:00
|
|
|
#include "projectexplorerconstants.h"
|
2015-03-03 15:11:01 +01:00
|
|
|
#include "nodesvisitor.h"
|
2014-11-19 17:58:33 +01:00
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2015-02-26 13:38:54 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
2014-11-19 17:58:33 +01:00
|
|
|
#include <coreplugin/infobar.h>
|
|
|
|
|
#include <coreplugin/vcsmanager.h>
|
2015-01-13 15:50:37 +01:00
|
|
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
|
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2015-01-16 17:47:11 +01:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2014-11-19 17:58:33 +01:00
|
|
|
|
|
|
|
|
#include <QApplication>
|
2015-02-26 13:38:54 +01:00
|
|
|
#include <QMenu>
|
2014-12-15 18:24:25 +01:00
|
|
|
#include <QTimer>
|
2014-11-19 17:58:33 +01:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
const char EXTERNAL_FILE_WARNING[] = "ExternalFile";
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-01 18:44:47 +02:00
|
|
|
using namespace Utils;
|
2015-02-04 12:18:30 +02:00
|
|
|
|
|
|
|
|
namespace ProjectExplorer {
|
|
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
using namespace Internal;
|
|
|
|
|
|
|
|
|
|
ProjectTree *ProjectTree::s_instance = 0;
|
|
|
|
|
|
|
|
|
|
ProjectTree::ProjectTree(QObject *parent)
|
|
|
|
|
: QObject(parent),
|
|
|
|
|
m_currentNode(0),
|
|
|
|
|
m_currentProject(0),
|
2014-12-08 12:03:36 +01:00
|
|
|
m_resetCurrentNodeFolder(false),
|
|
|
|
|
m_resetCurrentNodeFile(false),
|
2015-01-13 15:50:37 +01:00
|
|
|
m_resetCurrentNodeProject(false),
|
|
|
|
|
m_focusForContextMenu(0)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
|
|
|
|
s_instance = this;
|
|
|
|
|
|
2015-01-16 17:45:06 +01:00
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
|
2014-11-19 17:58:33 +01:00
|
|
|
this, &ProjectTree::documentManagerCurrentFileChanged);
|
|
|
|
|
|
|
|
|
|
connect(qApp, &QApplication::focusChanged,
|
|
|
|
|
this, &ProjectTree::focusChanged);
|
2015-01-16 17:47:11 +01:00
|
|
|
|
|
|
|
|
connect(SessionManager::instance(), &SessionManager::projectAdded,
|
2015-05-04 16:47:47 +02:00
|
|
|
this, &ProjectTree::sessionChanged);
|
2015-01-16 17:47:11 +01:00
|
|
|
connect(SessionManager::instance(), &SessionManager::projectRemoved,
|
2015-05-04 16:47:47 +02:00
|
|
|
this, &ProjectTree::sessionChanged);
|
2015-01-16 17:47:11 +01:00
|
|
|
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
|
2015-05-04 16:47:47 +02:00
|
|
|
this, &ProjectTree::sessionChanged);
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2014-12-15 18:24:25 +01:00
|
|
|
void ProjectTree::aboutToShutDown()
|
|
|
|
|
{
|
|
|
|
|
disconnect(qApp, &QApplication::focusChanged,
|
|
|
|
|
s_instance, &ProjectTree::focusChanged);
|
|
|
|
|
s_instance->update(0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
ProjectTree *ProjectTree::instance()
|
|
|
|
|
{
|
|
|
|
|
return s_instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Project *ProjectTree::currentProject()
|
|
|
|
|
{
|
|
|
|
|
return s_instance->m_currentProject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Node *ProjectTree::currentNode()
|
|
|
|
|
{
|
|
|
|
|
return s_instance->m_currentNode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::registerWidget(ProjectTreeWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
s_instance->m_projectTreeWidgets.append(widget);
|
|
|
|
|
if (hasFocus(widget))
|
|
|
|
|
s_instance->updateFromProjectTreeWidget(widget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::unregisterWidget(ProjectTreeWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
s_instance->m_projectTreeWidgets.removeOne(widget);
|
|
|
|
|
if (hasFocus(widget))
|
|
|
|
|
s_instance->updateFromDocumentManager();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::nodeChanged(ProjectTreeWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
if (hasFocus(widget))
|
|
|
|
|
s_instance->updateFromProjectTreeWidget(widget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::focusChanged()
|
|
|
|
|
{
|
|
|
|
|
s_instance->updateFromFocus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::updateFromFocus(bool invalidCurrentNode)
|
|
|
|
|
{
|
2015-01-13 15:50:37 +01:00
|
|
|
ProjectTreeWidget *focus = m_focusForContextMenu;
|
|
|
|
|
if (!focus)
|
2015-02-01 18:44:47 +02:00
|
|
|
focus = Utils::findOrDefault(m_projectTreeWidgets, &ProjectTree::hasFocus);
|
2014-11-19 17:58:33 +01:00
|
|
|
|
|
|
|
|
if (focus)
|
|
|
|
|
updateFromProjectTreeWidget(focus);
|
2014-12-09 14:16:11 +03:00
|
|
|
else
|
2014-11-19 17:58:33 +01:00
|
|
|
updateFromDocumentManager(invalidCurrentNode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::updateFromProjectTreeWidget(ProjectTreeWidget *widget)
|
|
|
|
|
{
|
2014-12-09 00:15:43 +03:00
|
|
|
Node *currentNode = widget->currentNode();
|
|
|
|
|
Project *project = projectForNode(currentNode);
|
2014-11-19 17:58:33 +01:00
|
|
|
|
|
|
|
|
update(currentNode, project);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::documentManagerCurrentFileChanged()
|
|
|
|
|
{
|
2014-12-09 14:16:11 +03:00
|
|
|
updateFromFocus();
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Project *ProjectTree::projectForNode(Node *node)
|
|
|
|
|
{
|
|
|
|
|
if (!node)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
FolderNode *rootProjectNode = node->asFolderNode();
|
2014-11-19 17:58:33 +01:00
|
|
|
if (!rootProjectNode)
|
|
|
|
|
rootProjectNode = node->parentFolderNode();
|
|
|
|
|
|
|
|
|
|
while (rootProjectNode && rootProjectNode->parentFolderNode() != SessionManager::sessionNode())
|
|
|
|
|
rootProjectNode = rootProjectNode->parentFolderNode();
|
|
|
|
|
|
|
|
|
|
Q_ASSERT(rootProjectNode);
|
|
|
|
|
|
|
|
|
|
return Utils::findOrDefault(SessionManager::projects(), Utils::equal(&Project::rootProjectNode, rootProjectNode));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::updateFromDocumentManager(bool invalidCurrentNode)
|
|
|
|
|
{
|
2015-01-16 17:45:06 +01:00
|
|
|
Core::IDocument *document = Core::EditorManager::currentDocument();
|
2015-02-02 00:37:38 +02:00
|
|
|
const FileName fileName = document ? document->filePath() : FileName();
|
2014-11-19 17:58:33 +01:00
|
|
|
|
2014-12-09 00:15:43 +03:00
|
|
|
Node *currentNode = 0;
|
2014-11-19 17:58:33 +01:00
|
|
|
if (!invalidCurrentNode && m_currentNode && m_currentNode->path() == fileName)
|
|
|
|
|
currentNode = m_currentNode;
|
|
|
|
|
else
|
|
|
|
|
currentNode = ProjectTreeWidget::nodeForFile(fileName);
|
|
|
|
|
|
2015-03-03 15:11:01 +01:00
|
|
|
updateFromNode(currentNode);
|
|
|
|
|
}
|
2014-11-19 17:58:33 +01:00
|
|
|
|
2015-03-03 15:11:01 +01:00
|
|
|
void ProjectTree::updateFromNode(Node *node)
|
|
|
|
|
{
|
2015-05-04 16:47:47 +02:00
|
|
|
Project *project;
|
|
|
|
|
if (node)
|
|
|
|
|
project = projectForNode(node);
|
|
|
|
|
else
|
|
|
|
|
project = SessionManager::startupProject();
|
2015-03-03 15:11:01 +01:00
|
|
|
|
|
|
|
|
update(node, project);
|
2014-11-19 17:58:33 +01:00
|
|
|
foreach (ProjectTreeWidget *widget, m_projectTreeWidgets)
|
2015-03-03 15:11:01 +01:00
|
|
|
widget->sync(node);
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::update(Node *node, Project *project)
|
|
|
|
|
{
|
2015-01-21 15:24:27 +01:00
|
|
|
bool changedProject = project != m_currentProject;
|
|
|
|
|
bool changedNode = node != m_currentNode;
|
|
|
|
|
if (changedProject) {
|
2014-11-19 17:58:33 +01:00
|
|
|
if (m_currentProject) {
|
2015-01-09 15:50:06 +01:00
|
|
|
disconnect(m_currentProject, &Project::projectContextUpdated,
|
2014-11-19 17:58:33 +01:00
|
|
|
this, &ProjectTree::updateContext);
|
2015-01-09 15:50:06 +01:00
|
|
|
disconnect(m_currentProject, &Project::projectLanguagesUpdated,
|
2014-11-19 17:58:33 +01:00
|
|
|
this, &ProjectTree::updateContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_currentProject = project;
|
|
|
|
|
|
|
|
|
|
if (m_currentProject) {
|
2015-01-09 15:50:06 +01:00
|
|
|
connect(m_currentProject, &Project::projectContextUpdated,
|
2014-11-19 17:58:33 +01:00
|
|
|
this, &ProjectTree::updateContext);
|
2015-01-09 15:50:06 +01:00
|
|
|
connect(m_currentProject, &Project::projectLanguagesUpdated,
|
2014-11-19 17:58:33 +01:00
|
|
|
this, &ProjectTree::updateContext);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node && Core::EditorManager::currentDocument()) {
|
|
|
|
|
connect(Core::EditorManager::currentDocument(), &Core::IDocument::changed,
|
|
|
|
|
this, &ProjectTree::updateExternalFileWarning,
|
|
|
|
|
Qt::UniqueConnection);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 15:24:27 +01:00
|
|
|
if (changedNode) {
|
2014-11-19 17:58:33 +01:00
|
|
|
m_currentNode = node;
|
|
|
|
|
emit currentNodeChanged(m_currentNode, project);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
|
2015-01-21 15:24:27 +01:00
|
|
|
if (changedProject) {
|
|
|
|
|
emit currentProjectChanged(m_currentProject);
|
2015-05-04 16:47:47 +02:00
|
|
|
sessionChanged();
|
2015-01-21 15:24:27 +01:00
|
|
|
updateContext();
|
|
|
|
|
}
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-05-04 16:47:47 +02:00
|
|
|
void ProjectTree::sessionChanged()
|
2015-01-16 17:47:11 +01:00
|
|
|
{
|
|
|
|
|
if (m_currentProject)
|
|
|
|
|
Core::DocumentManager::setDefaultLocationForNewFiles(m_currentProject->projectDirectory().toString());
|
|
|
|
|
else if (SessionManager::startupProject())
|
|
|
|
|
Core::DocumentManager::setDefaultLocationForNewFiles(SessionManager::startupProject()->projectDirectory().toString());
|
|
|
|
|
else
|
|
|
|
|
Core::DocumentManager::setDefaultLocationForNewFiles(QString());
|
2015-05-04 16:47:47 +02:00
|
|
|
updateFromFocus();
|
2015-01-16 17:47:11 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
void ProjectTree::updateContext()
|
|
|
|
|
{
|
|
|
|
|
Core::Context oldContext;
|
|
|
|
|
oldContext.add(m_lastProjectContext);
|
|
|
|
|
|
|
|
|
|
Core::Context newContext;
|
|
|
|
|
if (m_currentProject) {
|
|
|
|
|
newContext.add(m_currentProject->projectContext());
|
|
|
|
|
newContext.add(m_currentProject->projectLanguages());
|
|
|
|
|
|
|
|
|
|
m_lastProjectContext = newContext;
|
|
|
|
|
} else {
|
|
|
|
|
m_lastProjectContext = Core::Context();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Core::ICore::updateAdditionalContexts(oldContext, newContext);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
void ProjectTree::emitNodeUpdated(Node *node)
|
|
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(node))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit nodeUpdated(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::emitAboutToChangeShowInSimpleTree(FolderNode *node)
|
|
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(node))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit aboutToChangeShowInSimpleTree(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::emitShowInSimpleTreeChanged(FolderNode *node)
|
|
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(node))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit showInSimpleTreeChanged(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::emitFoldersAboutToBeAdded(FolderNode *parentFolder, const QList<FolderNode *> &newFolders)
|
|
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(parentFolder))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-03-03 15:11:01 +01:00
|
|
|
m_foldersAdded = newFolders;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
emit foldersAboutToBeAdded(parentFolder, newFolders);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
void ProjectTree::emitFoldersAdded(FolderNode *folder)
|
2015-01-09 15:50:06 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
emit foldersAdded();
|
|
|
|
|
|
|
|
|
|
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-03-03 15:11:01 +01:00
|
|
|
if (!m_currentNode) {
|
|
|
|
|
Core::IDocument *document = Core::EditorManager::currentDocument();
|
|
|
|
|
const FileName fileName = document ? document->filePath() : FileName();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FindNodesForFileVisitor findNodes(fileName);
|
|
|
|
|
foreach (FolderNode *fn, m_foldersAdded)
|
|
|
|
|
fn->accept(&findNodes);
|
|
|
|
|
|
|
|
|
|
Node *bestNode = ProjectTreeWidget::mostExpandedNode(findNodes.nodes());
|
|
|
|
|
if (!bestNode)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
updateFromNode(bestNode);
|
|
|
|
|
}
|
|
|
|
|
m_foldersAdded.clear();
|
2015-01-09 15:50:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::emitFoldersAboutToBeRemoved(FolderNode *parentFolder, const QList<FolderNode *> &staleFolders)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(parentFolder))
|
|
|
|
|
return;
|
|
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
Node *n = ProjectTree::currentNode();
|
|
|
|
|
while (n) {
|
2015-02-18 13:10:40 +01:00
|
|
|
if (FolderNode *fn = n->asFolderNode()) {
|
2015-01-09 15:50:06 +01:00
|
|
|
if (staleFolders.contains(fn)) {
|
2014-11-19 17:58:33 +01:00
|
|
|
ProjectNode *pn = n->projectNode();
|
|
|
|
|
// Make sure the node we are switching too isn't going to be removed also
|
2015-01-09 15:50:06 +01:00
|
|
|
while (staleFolders.contains(pn))
|
2014-11-19 17:58:33 +01:00
|
|
|
pn = pn->parentFolderNode()->projectNode();
|
|
|
|
|
m_resetCurrentNodeFolder = true;
|
2015-01-09 15:50:06 +01:00
|
|
|
break;
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
n = n->parentFolderNode();
|
|
|
|
|
}
|
2015-01-09 15:50:06 +01:00
|
|
|
emit foldersAboutToBeRemoved(parentFolder, staleFolders);
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
void ProjectTree::emitFoldersRemoved(FolderNode *folder)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
emit foldersRemoved();
|
|
|
|
|
|
|
|
|
|
if (m_resetCurrentNodeFolder) {
|
|
|
|
|
updateFromFocus(true);
|
|
|
|
|
m_resetCurrentNodeFolder = false;
|
|
|
|
|
}
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
void ProjectTree::emitFilesAboutToBeAdded(FolderNode *folder, const QList<FileNode *> &newFiles)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
2015-03-03 15:11:01 +01:00
|
|
|
m_filesAdded = newFiles;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit filesAboutToBeAdded(folder, newFiles);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
void ProjectTree::emitFilesAdded(FolderNode *folder)
|
2015-01-09 15:50:06 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
emit filesAdded();
|
|
|
|
|
|
|
|
|
|
if (Utils::anyOf(m_projectTreeWidgets, &ProjectTreeWidget::hasFocus))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-03-03 15:11:01 +01:00
|
|
|
if (!m_currentNode) {
|
|
|
|
|
Core::IDocument *document = Core::EditorManager::currentDocument();
|
|
|
|
|
const FileName fileName = document ? document->filePath() : FileName();
|
|
|
|
|
|
|
|
|
|
int index = Utils::indexOf(m_filesAdded, [&fileName](FileNode *node) {
|
|
|
|
|
return node->path() == fileName;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
updateFromNode(m_filesAdded.at(index));
|
|
|
|
|
}
|
|
|
|
|
m_filesAdded.clear();
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
void ProjectTree::emitFilesAboutToBeRemoved(FolderNode *folder, const QList<FileNode *> &staleFiles)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
|
|
|
|
|
2015-02-18 13:10:40 +01:00
|
|
|
if (m_currentNode)
|
|
|
|
|
if (FileNode *fileNode = m_currentNode->asFileNode())
|
|
|
|
|
if (staleFiles.contains(fileNode))
|
|
|
|
|
m_resetCurrentNodeFile = true;
|
2015-01-09 15:50:06 +01:00
|
|
|
|
|
|
|
|
emit filesAboutToBeRemoved(folder, staleFiles);
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
void ProjectTree::emitFilesRemoved(FolderNode *folder)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(folder))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit filesRemoved();
|
|
|
|
|
|
|
|
|
|
if (m_resetCurrentNodeFile) {
|
|
|
|
|
updateFromFocus(true);
|
|
|
|
|
m_resetCurrentNodeFile = false;
|
|
|
|
|
}
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-09 15:50:06 +01:00
|
|
|
void ProjectTree::emitNodeSortKeyAboutToChange(Node *node)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(node))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit nodeSortKeyAboutToChange(node);
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-14 15:35:48 +01:00
|
|
|
void ProjectTree::emitNodeSortKeyChanged(Node *node)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-14 15:35:48 +01:00
|
|
|
if (!isInNodeHierarchy(node))
|
|
|
|
|
return;
|
2015-01-09 15:50:06 +01:00
|
|
|
emit nodeSortKeyChanged();
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
|
|
|
|
|
2015-01-13 15:50:37 +01:00
|
|
|
void ProjectTree::collapseAll()
|
|
|
|
|
{
|
|
|
|
|
if (m_focusForContextMenu)
|
|
|
|
|
m_focusForContextMenu->collapseAll();
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-19 17:58:33 +01:00
|
|
|
void ProjectTree::updateExternalFileWarning()
|
|
|
|
|
{
|
|
|
|
|
Core::IDocument *document = qobject_cast<Core::IDocument *>(sender());
|
|
|
|
|
if (!document || document->filePath().isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
Core::InfoBar *infoBar = document->infoBar();
|
|
|
|
|
Core::Id externalFileId(EXTERNAL_FILE_WARNING);
|
|
|
|
|
if (!document->isModified()) {
|
|
|
|
|
infoBar->removeInfo(externalFileId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!infoBar->canInfoBeAdded(externalFileId))
|
|
|
|
|
return;
|
2015-02-01 18:44:47 +02:00
|
|
|
const FileName fileName = document->filePath();
|
2014-12-26 10:15:10 +02:00
|
|
|
const QList<Project *> projects = SessionManager::projects();
|
|
|
|
|
if (projects.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
foreach (Project *project, projects) {
|
2015-02-01 18:44:47 +02:00
|
|
|
FileName projectDir = project->projectDirectory();
|
2014-11-19 17:58:33 +01:00
|
|
|
if (projectDir.isEmpty())
|
|
|
|
|
continue;
|
|
|
|
|
if (fileName.isChildOf(projectDir))
|
|
|
|
|
return;
|
|
|
|
|
// External file. Test if it under the same VCS
|
|
|
|
|
QString topLevel;
|
|
|
|
|
if (Core::VcsManager::findVersionControlForDirectory(projectDir.toString(), &topLevel)
|
2015-02-01 18:44:47 +02:00
|
|
|
&& fileName.isChildOf(FileName::fromString(topLevel))) {
|
2014-11-19 17:58:33 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
infoBar->addInfo(Core::InfoBarEntry(externalFileId,
|
|
|
|
|
tr("<b>Warning:</b> This file is outside the project directory."),
|
|
|
|
|
Core::InfoBarEntry::GlobalSuppressionEnabled));
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-09 00:15:43 +03:00
|
|
|
bool ProjectTree::hasFocus(ProjectTreeWidget *widget)
|
2014-11-19 17:58:33 +01:00
|
|
|
{
|
2015-01-13 15:50:37 +01:00
|
|
|
return widget
|
|
|
|
|
&& ((widget->focusWidget() && widget->focusWidget()->hasFocus())
|
|
|
|
|
|| s_instance->m_focusForContextMenu == widget);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::showContextMenu(ProjectTreeWidget *focus, const QPoint &globalPos, Node *node)
|
|
|
|
|
{
|
|
|
|
|
QMenu *contextMenu = 0;
|
|
|
|
|
|
|
|
|
|
if (!node)
|
|
|
|
|
node = SessionManager::sessionNode();
|
|
|
|
|
if (node->nodeType() != SessionNodeType) {
|
|
|
|
|
Project *project = SessionManager::projectForNode(node);
|
|
|
|
|
|
|
|
|
|
emit s_instance->aboutToShowContextMenu(project, node);
|
|
|
|
|
switch (node->nodeType()) {
|
|
|
|
|
case ProjectNodeType:
|
|
|
|
|
if (node->parentFolderNode() == SessionManager::sessionNode())
|
|
|
|
|
contextMenu = Core::ActionManager::actionContainer(Constants::M_PROJECTCONTEXT)->menu();
|
|
|
|
|
else
|
|
|
|
|
contextMenu = Core::ActionManager::actionContainer(Constants::M_SUBPROJECTCONTEXT)->menu();
|
|
|
|
|
break;
|
|
|
|
|
case VirtualFolderNodeType:
|
|
|
|
|
case FolderNodeType:
|
|
|
|
|
contextMenu = Core::ActionManager::actionContainer(Constants::M_FOLDERCONTEXT)->menu();
|
|
|
|
|
break;
|
|
|
|
|
case FileNodeType:
|
|
|
|
|
contextMenu = Core::ActionManager::actionContainer(Constants::M_FILECONTEXT)->menu();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
qWarning("ProjectExplorerPlugin::showContextMenu - Missing handler for node type");
|
|
|
|
|
}
|
|
|
|
|
} else { // session item
|
|
|
|
|
emit s_instance->aboutToShowContextMenu(0, node);
|
|
|
|
|
|
|
|
|
|
contextMenu = Core::ActionManager::actionContainer(Constants::M_SESSIONCONTEXT)->menu();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (contextMenu && contextMenu->actions().count() > 0) {
|
|
|
|
|
contextMenu->popup(globalPos);
|
|
|
|
|
s_instance->m_focusForContextMenu = focus;
|
|
|
|
|
connect(contextMenu, &QMenu::aboutToHide,
|
|
|
|
|
s_instance, &ProjectTree::hideContextMenu,
|
2015-01-26 11:44:49 +02:00
|
|
|
Qt::ConnectionType(Qt::UniqueConnection | Qt::QueuedConnection));
|
2015-01-13 15:50:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProjectTree::hideContextMenu()
|
|
|
|
|
{
|
|
|
|
|
m_focusForContextMenu = 0;
|
2014-11-19 17:58:33 +01:00
|
|
|
}
|
2015-01-14 15:35:48 +01:00
|
|
|
|
|
|
|
|
bool ProjectTree::isInNodeHierarchy(Node *n)
|
|
|
|
|
{
|
|
|
|
|
Node *sessionNode = SessionManager::sessionNode();
|
|
|
|
|
do {
|
|
|
|
|
if (n == sessionNode)
|
|
|
|
|
return true;
|
|
|
|
|
n = n->parentFolderNode();
|
|
|
|
|
} while (n);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-02-04 12:18:30 +02:00
|
|
|
|
|
|
|
|
} // namespace ProjectExplorer
|