Change File System pane to a forest of trees

It shows the file system as a tree, where the user can change the root
directory of the view. Currently there are "Computer" (the default), and
all project directories.
If synchronization with the current editor is enabled, the view
automatically switches to the best fitting root directory.

Task-number: QTCREATORBUG-8305
Change-Id: Ic265eb49b1e8e0fd8cdeeb4fb1c64b8631f32e21
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Eike Ziller
2017-09-15 11:03:45 +02:00
parent 083ff55abe
commit 3c988e5a0d
3 changed files with 197 additions and 225 deletions

View File

@@ -26,8 +26,6 @@
#include "foldernavigationwidget.h" #include "foldernavigationwidget.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include <extensionsystem/pluginmanager.h>
#include <coreplugin/actionmanager/command.h> #include <coreplugin/actionmanager/command.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/idocument.h> #include <coreplugin/idocument.h>
@@ -35,62 +33,34 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/fileutils.h> #include <coreplugin/fileutils.h>
#include <coreplugin/find/findplugin.h>
#include <texteditor/findinfiles.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/elidinglabel.h> #include <utils/navigationtreeview.h>
#include <utils/itemviews.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QDebug> #include <QComboBox>
#include <QHeaderView>
#include <QSize> #include <QSize>
#include <QTimer>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QToolButton> #include <QToolButton>
#include <QSortFilterProxyModel>
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <QFileDialog>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
enum { debug = 0 };
namespace ProjectExplorer { namespace ProjectExplorer {
namespace Internal { namespace Internal {
// Hide the '.' entry. static FolderNavigationWidgetFactory *m_instance = nullptr;
class DotRemovalFilter : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit DotRemovalFilter(QObject *parent = nullptr);
protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex &parent) const;
Qt::DropActions supportedDragActions() const;
};
DotRemovalFilter::DotRemovalFilter(QObject *parent) : QSortFilterProxyModel(parent) QVector<FolderNavigationWidgetFactory::DirectoryEntry>
{ } FolderNavigationWidgetFactory::m_rootDirectories = {
{FolderNavigationWidget::tr("Computer"), Utils::FileName()}};
bool DotRemovalFilter::filterAcceptsRow(int source_row, const QModelIndex &parent) const
{
const QVariant fileName = sourceModel()->data(parent.child(source_row, 0));
if (Utils::HostOsInfo::isAnyUnixHost())
if (sourceModel()->data(parent) == QLatin1String("/") && fileName == QLatin1String(".."))
return false;
return fileName != QLatin1String(".");
}
Qt::DropActions DotRemovalFilter::supportedDragActions() const
{
return sourceModel()->supportedDragActions();
}
// FolderNavigationModel: Shows path as tooltip. // FolderNavigationModel: Shows path as tooltip.
class FolderNavigationModel : public QFileSystemModel class FolderNavigationModel : public QFileSystemModel
@@ -117,42 +87,46 @@ Qt::DropActions FolderNavigationModel::supportedDragActions() const
return Qt::MoveAction; return Qt::MoveAction;
} }
/*! static void showOnlyFirstColumn(QTreeView *view)
\class FolderNavigationWidget {
const int columnCount = view->header()->count();
for (int i = 1; i < columnCount; ++i)
view->setColumnHidden(i, true);
}
Shows a file system folder /*!
*/ \class FolderNavigationWidget
Shows a file system tree, with the root directory selectable from a dropdown.
\internal
*/
FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent), FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent),
m_listView(new Utils::ListView(this)), m_listView(new Utils::NavigationTreeView(this)),
m_fileSystemModel(new FolderNavigationModel(this)), m_fileSystemModel(new FolderNavigationModel(this)),
m_filterHiddenFilesAction(new QAction(tr("Show Hidden Files"), this)), m_filterHiddenFilesAction(new QAction(tr("Show Hidden Files"), this)),
m_filterModel(new DotRemovalFilter(this)), m_toggleSync(new QToolButton(this)),
m_title(new Utils::ElidingLabel(this)), m_rootSelector(new QComboBox)
m_toggleSync(new QToolButton(this))
{ {
m_fileSystemModel->setResolveSymlinks(false); m_fileSystemModel->setResolveSymlinks(false);
m_fileSystemModel->setIconProvider(Core::FileIconProvider::iconProvider()); m_fileSystemModel->setIconProvider(Core::FileIconProvider::iconProvider());
QDir::Filters filters = QDir::AllDirs | QDir::Files | QDir::Drives QDir::Filters filters = QDir::AllEntries | QDir::NoDotAndDotDot;
| QDir::Readable| QDir::Writable
| QDir::Executable | QDir::Hidden;
if (Utils::HostOsInfo::isWindowsHost()) // Symlinked directories can cause file watcher warnings on Win32. if (Utils::HostOsInfo::isWindowsHost()) // Symlinked directories can cause file watcher warnings on Win32.
filters |= QDir::NoSymLinks; filters |= QDir::NoSymLinks;
m_fileSystemModel->setFilter(filters); m_fileSystemModel->setFilter(filters);
m_filterModel->setSourceModel(m_fileSystemModel); m_fileSystemModel->setRootPath(QString());
m_filterHiddenFilesAction->setCheckable(true); m_filterHiddenFilesAction->setCheckable(true);
setHiddenFilesFilter(false); setHiddenFilesFilter(false);
m_listView->setIconSize(QSize(16,16)); m_listView->setIconSize(QSize(16,16));
m_listView->setModel(m_filterModel); m_listView->setModel(m_fileSystemModel);
m_listView->setFrameStyle(QFrame::NoFrame);
m_listView->setAttribute(Qt::WA_MacShowFocusRect, false);
m_listView->setDragEnabled(true); m_listView->setDragEnabled(true);
m_listView->setDragDropMode(QAbstractItemView::DragOnly); m_listView->setDragDropMode(QAbstractItemView::DragOnly);
showOnlyFirstColumn(m_listView);
setFocusProxy(m_listView); setFocusProxy(m_listView);
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
layout->addWidget(m_title); layout->addWidget(m_rootSelector);
layout->addWidget(m_listView); layout->addWidget(m_listView);
m_title->setMargin(5);
layout->setSpacing(0); layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout); setLayout(layout);
@@ -164,13 +138,26 @@ FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent
// connections // connections
connect(m_listView, &QAbstractItemView::activated, connect(m_listView, &QAbstractItemView::activated,
this, &FolderNavigationWidget::slotOpenItem); this, [this](const QModelIndex &index) { openItem(index); });
connect(m_filterHiddenFilesAction, &QAction::toggled, connect(m_filterHiddenFilesAction, &QAction::toggled,
this, &FolderNavigationWidget::setHiddenFilesFilter); this, &FolderNavigationWidget::setHiddenFilesFilter);
connect(m_toggleSync, &QAbstractButton::clicked, connect(m_toggleSync, &QAbstractButton::clicked,
this, &FolderNavigationWidget::toggleAutoSynchronization); this, &FolderNavigationWidget::toggleAutoSynchronization);
connect(m_filterModel, &QAbstractItemModel::layoutChanged, connect(m_rootSelector,
this, &FolderNavigationWidget::ensureCurrentIndex); static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this,
[this](int index) {
const auto directory = m_rootSelector->itemData(index).value<Utils::FileName>();
m_rootSelector->setToolTip(directory.toString());
setRootDirectory(directory);
});
connect(m_rootSelector,
static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
this,
[this] {
if (m_autoSync && Core::EditorManager::currentEditor())
selectFile(Core::EditorManager::currentEditor()->document()->filePath());
});
} }
void FolderNavigationWidget::toggleAutoSynchronization() void FolderNavigationWidget::toggleAutoSynchronization()
@@ -178,6 +165,29 @@ void FolderNavigationWidget::toggleAutoSynchronization()
setAutoSynchronization(!m_autoSync); setAutoSynchronization(!m_autoSync);
} }
void FolderNavigationWidget::addRootDirectory(const QString &displayName,
const Utils::FileName &directory)
{
m_rootSelector->addItem(displayName, qVariantFromValue(directory));
m_rootSelector->setItemData(m_rootSelector->count() - 1,
directory.toUserOutput(),
Qt::ToolTipRole);
if (m_autoSync) // we might find a better root for current selection now
setCurrentEditor(Core::EditorManager::currentEditor());
}
void FolderNavigationWidget::removeRootDirectory(const Utils::FileName &directory)
{
for (int i = 0; i < m_rootSelector->count(); ++i) {
if (m_rootSelector->itemData(i).value<Utils::FileName>() == directory) {
m_rootSelector->removeItem(i);
break;
}
}
if (m_autoSync) // we might need to find a new root for current selection
setCurrentEditor(Core::EditorManager::currentEditor());
}
bool FolderNavigationWidget::autoSynchronization() const bool FolderNavigationWidget::autoSynchronization() const
{ {
return m_autoSync; return m_autoSync;
@@ -193,148 +203,95 @@ void FolderNavigationWidget::setAutoSynchronization(bool sync)
if (m_autoSync) { if (m_autoSync) {
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
this, &FolderNavigationWidget::setCurrentFile); this, &FolderNavigationWidget::setCurrentEditor);
setCurrentFile(Core::EditorManager::currentEditor()); setCurrentEditor(Core::EditorManager::currentEditor());
} else { } else {
disconnect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, disconnect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
this, &FolderNavigationWidget::setCurrentFile); this, &FolderNavigationWidget::setCurrentEditor);
} }
} }
void FolderNavigationWidget::setCurrentFile(Core::IEditor *editor) void FolderNavigationWidget::setCurrentEditor(Core::IEditor *editor)
{ {
if (!editor) if (!editor)
return; return;
const Utils::FileName filePath = editor->document()->filePath();
// switch to most fitting root
const int bestRootIndex = bestRootForFile(filePath);
m_rootSelector->setCurrentIndex(bestRootIndex);
// select
selectFile(filePath);
}
const QString filePath = editor->document()->filePath().toString(); void FolderNavigationWidget::selectFile(const Utils::FileName &filePath)
// Try to find directory of current file {
bool pathOpened = false; const QModelIndex fileIndex = m_fileSystemModel->index(filePath.toString());
if (!filePath.isEmpty()) { if (fileIndex.isValid()) {
const QFileInfo fi(filePath); // TODO This only scrolls to the right position if all directory contents are loaded.
if (fi.exists()) // Unfortunately listening to directoryLoaded was still not enough (there might also
pathOpened = setCurrentDirectory(fi.absolutePath()); // be some delayed sorting involved?).
// Use magic timer for scrolling.
m_listView->setCurrentIndex(fileIndex);
QTimer::singleShot(200, this, [this, filePath] {
const QModelIndex fileIndex = m_fileSystemModel->index(filePath.toString());
m_listView->scrollTo(fileIndex);
});
} }
if (!pathOpened) // Default to home. }
setCurrentDirectory(Utils::PathChooser::homePath());
// Select the current file. void FolderNavigationWidget::setRootDirectory(const Utils::FileName &directory)
if (pathOpened) { {
const QModelIndex fileIndex = m_fileSystemModel->index(filePath); const QModelIndex index = m_fileSystemModel->setRootPath(directory.toString());
if (fileIndex.isValid()) { m_listView->setRootIndex(index);
QItemSelectionModel *selections = m_listView->selectionModel(); }
const QModelIndex mainIndex = m_filterModel->mapFromSource(fileIndex);
selections->setCurrentIndex(mainIndex, QItemSelectionModel::SelectCurrent int FolderNavigationWidget::bestRootForFile(const Utils::FileName &filePath)
| QItemSelectionModel::Clear); {
m_listView->scrollTo(mainIndex); int index = 0; // Computer is default
int commonLength = 0;
for (int i = 1; i < m_rootSelector->count(); ++i) {
const auto root = m_rootSelector->itemData(i).value<Utils::FileName>();
if (filePath.isChildOf(root) && root.length() > commonLength) {
index = i;
commonLength = root.length();
} }
} }
return index;
} }
bool FolderNavigationWidget::setCurrentDirectory(const QString &directory) void FolderNavigationWidget::openItem(const QModelIndex &index)
{ {
const QString newDirectory = directory.isEmpty() ? QDir::rootPath() : directory; if (!index.isValid())
if (debug)
qDebug() << "setcurdir" << directory << newDirectory;
// Set the root path on the model instead of changing the top index
// of the view to cause the model to clean out its file watchers.
const QModelIndex index = m_fileSystemModel->setRootPath(newDirectory);
if (!index.isValid()) {
setCurrentTitle(QString(), QString());
return false;
}
QModelIndex oldRootIndex = m_listView->rootIndex();
QModelIndex newRootIndex = m_filterModel->mapFromSource(index);
m_listView->setRootIndex(newRootIndex);
const QDir current(QDir::cleanPath(newDirectory));
setCurrentTitle(current.dirName(),
QDir::toNativeSeparators(current.absolutePath()));
if (oldRootIndex.parent() == newRootIndex) { // cdUp, so select the old directory
m_listView->setCurrentIndex(oldRootIndex);
m_listView->scrollTo(oldRootIndex, QAbstractItemView::EnsureVisible);
}
return !directory.isEmpty();
}
QString FolderNavigationWidget::currentDirectory() const
{
return m_fileSystemModel->rootPath();
}
void FolderNavigationWidget::slotOpenItem(const QModelIndex &viewIndex)
{
if (viewIndex.isValid())
openItem(m_filterModel->mapToSource(viewIndex));
}
void FolderNavigationWidget::openItem(const QModelIndex &srcIndex, bool openDirectoryAsProject)
{
const QString fileName = m_fileSystemModel->fileName(srcIndex);
if (fileName == QLatin1String("."))
return; return;
if (fileName == QLatin1String("..")) { const QString path = m_fileSystemModel->filePath(index);
// cd up: Special behaviour: The fileInfo of ".." is that of the parent directory. if (m_fileSystemModel->isDir(index)) {
const QString parentPath = m_fileSystemModel->fileInfo(srcIndex).absoluteFilePath(); const QFileInfo fi = m_fileSystemModel->fileInfo(index);
setCurrentDirectory(parentPath);
return;
}
const QString path = m_fileSystemModel->filePath(srcIndex);
if (m_fileSystemModel->isDir(srcIndex)) {
const QFileInfo fi = m_fileSystemModel->fileInfo(srcIndex);
if (!fi.isReadable() || !fi.isExecutable()) if (!fi.isReadable() || !fi.isExecutable())
return; return;
// Try to find project files in directory and open those. // Try to find project files in directory and open those.
if (openDirectoryAsProject) { const QStringList projectFiles = FolderNavigationWidget::projectFilesInDirectory(path);
const QStringList projectFiles = FolderNavigationWidget::projectFilesInDirectory(path); if (!projectFiles.isEmpty())
if (!projectFiles.isEmpty()) Core::ICore::instance()->openFiles(projectFiles);
Core::ICore::instance()->openFiles(projectFiles); } else {
return; // Open editor
} Core::EditorManager::openEditor(path);
// Change to directory
setCurrentDirectory(path);
return;
} }
// Open file.
Core::ICore::instance()->openFiles(QStringList(path));
}
void FolderNavigationWidget::setCurrentTitle(QString dirName, const QString &fullPath)
{
if (dirName.isEmpty())
dirName = fullPath;
m_title->setText(dirName);
m_title->setToolTip(fullPath);
}
QModelIndex FolderNavigationWidget::currentItem() const
{
const QModelIndex current = m_listView->currentIndex();
if (current.isValid())
return m_filterModel->mapToSource(current);
return QModelIndex();
}
// Format the text for the "open" action of the context menu according
// to the selectect entry
static inline QString actionOpenText(const QFileSystemModel *model,
const QModelIndex &index)
{
if (!index.isValid())
return FolderNavigationWidget::tr("Open");
const QString fileName = model->fileName(index);
if (fileName == QLatin1String(".."))
return FolderNavigationWidget::tr("Open Parent Folder");
return FolderNavigationWidget::tr("Open \"%1\"").arg(fileName);
} }
void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev) void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
{ {
QMenu menu; QMenu menu;
// Open current item // Open current item
const QModelIndex current = currentItem(); const QModelIndex current = m_listView->currentIndex();
const bool hasCurrentItem = current.isValid(); const bool hasCurrentItem = current.isValid();
QAction *actionOpen = menu.addAction(actionOpenText(m_fileSystemModel, current)); QAction *actionOpen = nullptr;
actionOpen->setEnabled(hasCurrentItem); if (hasCurrentItem) {
const QString fileName = m_fileSystemModel->fileName(current);
if (m_fileSystemModel->isDir(current))
actionOpen = menu.addAction(tr("Open Project in \"%1\"").arg(fileName));
else
actionOpen = menu.addAction(tr("Open \"%1\"").arg(fileName));
}
// we need dummy DocumentModel::Entry with absolute file path in it // we need dummy DocumentModel::Entry with absolute file path in it
// to get EditorManager::addNativeDirAndOpenWithActions() working // to get EditorManager::addNativeDirAndOpenWithActions() working
@@ -344,17 +301,6 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
fakeEntry.document = &document; fakeEntry.document = &document;
Core::EditorManager::addNativeDirAndOpenWithActions(&menu, &fakeEntry); Core::EditorManager::addNativeDirAndOpenWithActions(&menu, &fakeEntry);
const bool isDirectory = hasCurrentItem && m_fileSystemModel->isDir(current);
QAction *actionOpenDirectoryAsProject = 0;
if (isDirectory && m_fileSystemModel->fileName(current) != QLatin1String("..")) {
actionOpenDirectoryAsProject =
menu.addAction(tr("Open Project in \"%1\"")
.arg(m_fileSystemModel->fileName(current)));
}
// Open file dialog to choose a path starting from current
QAction *actionChooseFolder = menu.addAction(tr("Choose Folder..."));
QAction *action = menu.exec(ev->globalPos()); QAction *action = menu.exec(ev->globalPos());
if (!action) if (!action)
return; return;
@@ -362,12 +308,6 @@ void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
ev->accept(); ev->accept();
if (action == actionOpen) { // Handle open file. if (action == actionOpen) { // Handle open file.
openItem(current); openItem(current);
} else if (action == actionOpenDirectoryAsProject) {
openItem(current, true);
} else if (action == actionChooseFolder) { // Open file dialog
const QString newPath = QFileDialog::getExistingDirectory(this, tr("Choose Folder"), currentDirectory());
if (!newPath.isEmpty())
setCurrentDirectory(newPath);
} }
} }
@@ -387,17 +327,6 @@ bool FolderNavigationWidget::hiddenFilesFilter() const
return m_filterHiddenFilesAction->isChecked(); return m_filterHiddenFilesAction->isChecked();
} }
void FolderNavigationWidget::ensureCurrentIndex()
{
QModelIndex index = m_listView->currentIndex();
if (!index.isValid()
|| index.parent() != m_listView->rootIndex()) {
index = m_listView->rootIndex().child(0, 0);
m_listView->setCurrentIndex(index);
}
m_listView->scrollTo(index);
}
QStringList FolderNavigationWidget::projectFilesInDirectory(const QString &path) QStringList FolderNavigationWidget::projectFilesInDirectory(const QString &path)
{ {
QDir dir(path); QDir dir(path);
@@ -410,6 +339,7 @@ QStringList FolderNavigationWidget::projectFilesInDirectory(const QString &path)
// --------------------FolderNavigationWidgetFactory // --------------------FolderNavigationWidgetFactory
FolderNavigationWidgetFactory::FolderNavigationWidgetFactory() FolderNavigationWidgetFactory::FolderNavigationWidgetFactory()
{ {
m_instance = this;
setDisplayName(tr("File System")); setDisplayName(tr("File System"));
setPriority(400); setPriority(400);
setId("File System"); setId("File System");
@@ -418,8 +348,19 @@ FolderNavigationWidgetFactory::FolderNavigationWidgetFactory()
Core::NavigationView FolderNavigationWidgetFactory::createWidget() Core::NavigationView FolderNavigationWidgetFactory::createWidget()
{ {
Core::NavigationView n;
auto fnw = new FolderNavigationWidget; auto fnw = new FolderNavigationWidget;
for (const DirectoryEntry &root : m_rootDirectories)
fnw->addRootDirectory(root.first, root.second);
connect(this,
&FolderNavigationWidgetFactory::rootDirectoryAdded,
fnw,
&FolderNavigationWidget::addRootDirectory);
connect(this,
&FolderNavigationWidgetFactory::rootDirectoryRemoved,
fnw,
&FolderNavigationWidget::removeRootDirectory);
Core::NavigationView n;
n.widget = fnw; n.widget = fnw;
auto filter = new QToolButton; auto filter = new QToolButton;
filter->setIcon(Utils::Icons::FILTER.icon()); filter->setIcon(Utils::Icons::FILTER.icon());
@@ -450,7 +391,23 @@ void FolderNavigationWidgetFactory::restoreSettings(QSettings *settings, int pos
fnw->setHiddenFilesFilter(settings->value(baseKey + QLatin1String(".HiddenFilesFilter"), false).toBool()); fnw->setHiddenFilesFilter(settings->value(baseKey + QLatin1String(".HiddenFilesFilter"), false).toBool());
fnw->setAutoSynchronization(settings->value(baseKey + QLatin1String(".SyncWithEditor"), true).toBool()); fnw->setAutoSynchronization(settings->value(baseKey + QLatin1String(".SyncWithEditor"), true).toBool());
} }
void FolderNavigationWidgetFactory::addRootDirectory(const QString &displayName,
const Utils::FileName &directory)
{
m_rootDirectories.append(DirectoryEntry(displayName, directory));
emit m_instance->rootDirectoryAdded(displayName, directory);
}
void FolderNavigationWidgetFactory::removeRootDirectory(const Utils::FileName &directory)
{
const int index = Utils::indexOf(m_rootDirectories, [directory](const DirectoryEntry &entry) {
return entry.second == directory;
});
QTC_ASSERT(index >= 0, return);
m_rootDirectories.removeAt(index);
emit m_instance->rootDirectoryRemoved(directory);
}
} // namespace Internal } // namespace Internal
} // namespace ProjectExplorer } // namespace ProjectExplorer
#include "foldernavigationwidget.moc"

View File

@@ -29,15 +29,18 @@
#include <QWidget> #include <QWidget>
namespace Utils { class ListView; }
namespace Core { class IEditor; } namespace Core { class IEditor; }
namespace Utils {
class FileName;
class NavigationTreeView;
}
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QLabel;
class QSortFilterProxyModel;
class QModelIndex;
class QFileSystemModel;
class QAction; class QAction;
class QComboBox;
class QFileSystemModel;
class QModelIndex;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace ProjectExplorer { namespace ProjectExplorer {
@@ -58,29 +61,26 @@ public:
void setAutoSynchronization(bool sync); void setAutoSynchronization(bool sync);
void toggleAutoSynchronization(); void toggleAutoSynchronization();
private: void addRootDirectory(const QString &displayName, const Utils::FileName &directory);
void setCurrentFile(Core::IEditor *editor); void removeRootDirectory(const Utils::FileName &directory);
void slotOpenItem(const QModelIndex &viewIndex);
void setHiddenFilesFilter(bool filter);
void ensureCurrentIndex();
protected: protected:
void contextMenuEvent(QContextMenuEvent *ev) override; void contextMenuEvent(QContextMenuEvent *ev) override;
private: private:
void setCurrentTitle(QString dirName, const QString &fullPath); void setHiddenFilesFilter(bool filter);
bool setCurrentDirectory(const QString &directory); void setCurrentEditor(Core::IEditor *editor);
void openItem(const QModelIndex &srcIndex, bool openDirectoryAsProject = false); void selectFile(const Utils::FileName &filePath);
QModelIndex currentItem() const; void setRootDirectory(const Utils::FileName &directory);
QString currentDirectory() const; int bestRootForFile(const Utils::FileName &filePath);
void openItem(const QModelIndex &index);
Utils::ListView *m_listView; Utils::NavigationTreeView *m_listView = nullptr;
QFileSystemModel *m_fileSystemModel; QFileSystemModel *m_fileSystemModel = nullptr;
QAction *m_filterHiddenFilesAction; QAction *m_filterHiddenFilesAction = nullptr;
QSortFilterProxyModel *m_filterModel;
QLabel *m_title;
bool m_autoSync = false; bool m_autoSync = false;
QToolButton *m_toggleSync; QToolButton *m_toggleSync = nullptr;
QComboBox *m_rootSelector = nullptr;
// FolderNavigationWidgetFactory needs private members to build a menu // FolderNavigationWidgetFactory needs private members to build a menu
friend class FolderNavigationWidgetFactory; friend class FolderNavigationWidgetFactory;
@@ -96,6 +96,17 @@ public:
Core::NavigationView createWidget() override; Core::NavigationView createWidget() override;
void saveSettings(QSettings *settings, int position, QWidget *widget) override; void saveSettings(QSettings *settings, int position, QWidget *widget) override;
void restoreSettings(QSettings *settings, int position, QWidget *widget) override; void restoreSettings(QSettings *settings, int position, QWidget *widget) override;
static void addRootDirectory(const QString &displayName, const Utils::FileName &directory);
static void removeRootDirectory(const Utils::FileName &directory);
signals:
void rootDirectoryAdded(const QString &displayName, const Utils::FileName &directory);
void rootDirectoryRemoved(const Utils::FileName &directory);
private:
using DirectoryEntry = std::pair<QString, Utils::FileName>;
static QVector<DirectoryEntry> m_rootDirectories;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -30,6 +30,7 @@
#include "kit.h" #include "kit.h"
#include "buildconfiguration.h" #include "buildconfiguration.h"
#include "deployconfiguration.h" #include "deployconfiguration.h"
#include "foldernavigationwidget.h"
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projectnodes.h" #include "projectnodes.h"
#include "editorconfiguration.h" #include "editorconfiguration.h"
@@ -385,6 +386,8 @@ void SessionManager::addProject(Project *pro)
m_instance, [pro]() { m_instance->projectDisplayNameChanged(pro); }); m_instance, [pro]() { m_instance->projectDisplayNameChanged(pro); });
emit m_instance->projectAdded(pro); emit m_instance->projectAdded(pro);
FolderNavigationWidgetFactory::addRootDirectory(pro->displayName(),
pro->projectFilePath().parentDir());
configureEditors(pro); configureEditors(pro);
connect(pro, &Project::fileListChanged, [pro](){ configureEditors(pro); }); connect(pro, &Project::fileListChanged, [pro](){ configureEditors(pro); });
} }
@@ -739,6 +742,7 @@ void SessionManager::removeProjects(QList<Project *> remove)
m_instance, &SessionManager::clearProjectFileCache); m_instance, &SessionManager::clearProjectFileCache);
d->m_projectFileCache.remove(pro); d->m_projectFileCache.remove(pro);
emit m_instance->projectRemoved(pro); emit m_instance->projectRemoved(pro);
FolderNavigationWidgetFactory::removeRootDirectory(pro->projectFilePath().parentDir());
delete pro; delete pro;
} }