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 "foldernavigationwidget.h"
|
2014-04-17 16:49:43 +02:00
|
|
|
#include "projectexplorer.h"
|
2017-11-29 16:18:01 +01:00
|
|
|
#include "projectexplorerconstants.h"
|
2017-10-09 06:59:54 +02:00
|
|
|
#include "projectexplorericons.h"
|
2017-11-29 16:18:01 +01:00
|
|
|
#include "projectnodes.h"
|
|
|
|
|
#include "projecttree.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2012-05-23 14:02:36 +02:00
|
|
|
#include <coreplugin/actionmanager/command.h>
|
2017-11-08 13:15:36 +01:00
|
|
|
#include <coreplugin/diffservice.h>
|
2017-09-18 13:39:35 +02:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2015-01-16 17:45:06 +01:00
|
|
|
#include <coreplugin/editormanager/ieditor.h>
|
2017-11-29 16:18:01 +01:00
|
|
|
#include <coreplugin/fileiconprovider.h>
|
2011-08-16 18:55:23 +02:00
|
|
|
#include <coreplugin/fileutils.h>
|
2017-11-29 16:18:01 +01:00
|
|
|
#include <coreplugin/icontext.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/idocument.h>
|
2011-09-05 10:19:49 +02:00
|
|
|
|
2017-11-08 13:15:36 +01:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
|
|
|
|
|
|
|
|
|
#include <texteditor/textdocument.h>
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
#include <utils/algorithm.h>
|
2017-11-07 17:50:32 +01:00
|
|
|
#include <utils/filecrumblabel.h>
|
2013-03-14 11:35:27 +01:00
|
|
|
#include <utils/hostosinfo.h>
|
2017-09-15 11:03:45 +02:00
|
|
|
#include <utils/navigationtreeview.h>
|
2017-11-29 16:18:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2016-08-03 17:55:54 +02:00
|
|
|
#include <utils/utilsicons.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-11-22 16:34:31 +01:00
|
|
|
#include <QAction>
|
|
|
|
|
#include <QApplication>
|
2017-09-15 11:03:45 +02:00
|
|
|
#include <QComboBox>
|
2017-11-22 16:34:31 +01:00
|
|
|
#include <QContextMenuEvent>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QFileSystemModel>
|
2017-09-15 11:03:45 +02:00
|
|
|
#include <QHeaderView>
|
2017-11-22 16:34:31 +01:00
|
|
|
#include <QMenu>
|
2017-11-29 16:18:01 +01:00
|
|
|
#include <QMessageBox>
|
2017-11-07 17:50:32 +01:00
|
|
|
#include <QScrollBar>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QSize>
|
2017-09-15 11:03:45 +02:00
|
|
|
#include <QTimer>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QToolButton>
|
2017-11-22 16:34:31 +01:00
|
|
|
#include <QVBoxLayout>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-09-15 13:30:26 +02:00
|
|
|
const int PATH_ROLE = Qt::UserRole;
|
|
|
|
|
const int ID_ROLE = Qt::UserRole + 1;
|
2017-09-26 17:19:00 +02:00
|
|
|
const int SORT_ROLE = Qt::UserRole + 2;
|
2017-09-15 13:30:26 +02:00
|
|
|
|
2017-09-18 13:39:35 +02:00
|
|
|
const char PROJECTSDIRECTORYROOT_ID[] = "A.Projects";
|
2017-11-29 16:18:01 +01:00
|
|
|
const char C_FOLDERNAVIGATIONWIDGET[] = "ProjectExplorer.FolderNavigationWidget";
|
2017-09-18 13:39:35 +02:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
namespace ProjectExplorer {
|
2008-12-02 16:19:05 +01:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
static FolderNavigationWidgetFactory *m_instance = nullptr;
|
2010-01-26 10:33:39 +01:00
|
|
|
|
2017-09-15 13:30:26 +02:00
|
|
|
QVector<FolderNavigationWidgetFactory::RootDirectory>
|
2017-09-18 14:59:17 +02:00
|
|
|
FolderNavigationWidgetFactory::m_rootDirectories;
|
2014-09-08 12:26:12 +02:00
|
|
|
|
2017-11-15 09:20:58 +01:00
|
|
|
|
|
|
|
|
static QWidget *createHLine()
|
|
|
|
|
{
|
|
|
|
|
auto widget = new QFrame;
|
|
|
|
|
widget->setFrameStyle(QFrame::Plain | QFrame::HLine);
|
|
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 16:34:31 +01:00
|
|
|
// Call delayLayoutOnce to delay reporting the new heightForWidget by the double-click interval.
|
|
|
|
|
// Call setScrollBarOnce to set a scroll bar's value once during layouting (where heightForWidget
|
|
|
|
|
// is called).
|
|
|
|
|
class DelayedFileCrumbLabel : public Utils::FileCrumbLabel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
DelayedFileCrumbLabel(QWidget *parent) : Utils::FileCrumbLabel(parent) {}
|
|
|
|
|
|
|
|
|
|
int immediateHeightForWidth(int w) const;
|
|
|
|
|
int heightForWidth(int w) const final;
|
|
|
|
|
void delayLayoutOnce();
|
|
|
|
|
void setScrollBarOnce(QScrollBar *bar, int value);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void setScrollBarOnce() const;
|
|
|
|
|
|
|
|
|
|
QPointer<QScrollBar> m_bar;
|
|
|
|
|
int m_barValue = 0;
|
|
|
|
|
bool m_delaying = false;
|
|
|
|
|
};
|
|
|
|
|
|
2010-03-29 15:48:04 +02:00
|
|
|
// FolderNavigationModel: Shows path as tooltip.
|
2010-02-03 16:52:08 +01:00
|
|
|
class FolderNavigationModel : public QFileSystemModel
|
|
|
|
|
{
|
|
|
|
|
public:
|
2016-04-13 15:52:14 +02:00
|
|
|
explicit FolderNavigationModel(QObject *parent = nullptr);
|
2017-11-29 16:18:01 +01:00
|
|
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const final;
|
|
|
|
|
Qt::DropActions supportedDragActions() const final;
|
|
|
|
|
Qt::ItemFlags flags(const QModelIndex &index) const final;
|
|
|
|
|
bool setData(const QModelIndex &index, const QVariant &value, int role) final;
|
2010-02-03 16:52:08 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
FolderNavigationModel::FolderNavigationModel(QObject *parent) : QFileSystemModel(parent)
|
|
|
|
|
{ }
|
2010-02-03 16:52:08 +01:00
|
|
|
|
|
|
|
|
QVariant FolderNavigationModel::data(const QModelIndex &index, int role) const
|
|
|
|
|
{
|
|
|
|
|
if (role == Qt::ToolTipRole)
|
|
|
|
|
return QDir::toNativeSeparators(QDir::cleanPath(filePath(index)));
|
|
|
|
|
else
|
|
|
|
|
return QFileSystemModel::data(index, role);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-08 12:26:12 +02:00
|
|
|
Qt::DropActions FolderNavigationModel::supportedDragActions() const
|
|
|
|
|
{
|
|
|
|
|
return Qt::MoveAction;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
Qt::ItemFlags FolderNavigationModel::flags(const QModelIndex &index) const
|
|
|
|
|
{
|
|
|
|
|
if (index.isValid() && !fileInfo(index).isRoot())
|
|
|
|
|
return QFileSystemModel::flags(index) | Qt::ItemIsEditable;
|
|
|
|
|
return QFileSystemModel::flags(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QVector<FolderNode *> renamableFolderNodes(const Utils::FileName &before,
|
|
|
|
|
const Utils::FileName &after)
|
|
|
|
|
{
|
|
|
|
|
QVector<FolderNode *> folderNodes;
|
|
|
|
|
ProjectTree::forEachNode([&](Node *node) {
|
|
|
|
|
if (node->nodeType() == NodeType::File && node->filePath() == before
|
|
|
|
|
&& node->parentFolderNode()
|
|
|
|
|
&& node->parentFolderNode()->renameFile(before.toString(), after.toString())) {
|
|
|
|
|
folderNodes.append(node->parentFolderNode());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return folderNodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FolderNavigationModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(index.isValid() && parent(index).isValid() && index.column() == 0
|
|
|
|
|
&& role == Qt::EditRole && value.canConvert<QString>(),
|
|
|
|
|
return false);
|
|
|
|
|
const QString afterFileName = value.toString();
|
|
|
|
|
const QString beforeFilePath = filePath(index);
|
|
|
|
|
const QString parentPath = filePath(parent(index));
|
|
|
|
|
const QString afterFilePath = parentPath + '/' + afterFileName;
|
|
|
|
|
if (beforeFilePath == afterFilePath)
|
|
|
|
|
return false;
|
|
|
|
|
// need to rename through file system model, which takes care of not changing our selection
|
|
|
|
|
const bool success = QFileSystemModel::setData(index, value, role);
|
|
|
|
|
// for files we can do more than just rename on disk, for directories the user is on his/her own
|
|
|
|
|
if (success && fileInfo(index).isFile()) {
|
|
|
|
|
Core::DocumentManager::renamedFile(beforeFilePath, afterFilePath);
|
|
|
|
|
const QVector<FolderNode *> folderNodes
|
|
|
|
|
= renamableFolderNodes(Utils::FileName::fromString(beforeFilePath),
|
|
|
|
|
Utils::FileName::fromString(afterFilePath));
|
|
|
|
|
QVector<FolderNode *> failedNodes;
|
|
|
|
|
for (FolderNode *folder : folderNodes) {
|
|
|
|
|
if (!folder->canRenameFile(beforeFilePath, afterFilePath))
|
|
|
|
|
failedNodes.append(folder);
|
|
|
|
|
}
|
|
|
|
|
if (!failedNodes.isEmpty()) {
|
|
|
|
|
const QString projects
|
|
|
|
|
= Utils::transform<QList>(failedNodes,
|
|
|
|
|
[](FolderNode *n) {
|
|
|
|
|
return n->managingProject()->filePath().fileName();
|
|
|
|
|
})
|
|
|
|
|
.join(", ");
|
|
|
|
|
const QString errorMessage
|
|
|
|
|
= tr("The file \"%1\" was renamed to \"%2\", "
|
|
|
|
|
"but the following projects could not be automatically changed: %3")
|
|
|
|
|
.arg(beforeFilePath, afterFilePath, projects);
|
|
|
|
|
QTimer::singleShot(0, Core::ICore::instance(), [errorMessage] {
|
|
|
|
|
QMessageBox::warning(Core::ICore::dialogParent(),
|
|
|
|
|
ProjectExplorerPlugin::tr("Project Editing Failed"),
|
|
|
|
|
errorMessage);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
static void showOnlyFirstColumn(QTreeView *view)
|
|
|
|
|
{
|
|
|
|
|
const int columnCount = view->header()->count();
|
|
|
|
|
for (int i = 1; i < columnCount; ++i)
|
|
|
|
|
view->setColumnHidden(i, true);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-07 17:50:32 +01:00
|
|
|
static bool isChildOf(const QModelIndex &index, const QModelIndex &parent)
|
|
|
|
|
{
|
|
|
|
|
if (index == parent)
|
|
|
|
|
return true;
|
|
|
|
|
QModelIndex current = index;
|
|
|
|
|
while (current.isValid()) {
|
|
|
|
|
current = current.parent();
|
|
|
|
|
if (current == parent)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2017-09-15 11:03:45 +02:00
|
|
|
\class FolderNavigationWidget
|
|
|
|
|
|
|
|
|
|
Shows a file system tree, with the root directory selectable from a dropdown.
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
\internal
|
|
|
|
|
*/
|
2016-04-13 15:52:14 +02:00
|
|
|
FolderNavigationWidget::FolderNavigationWidget(QWidget *parent) : QWidget(parent),
|
2017-09-15 11:03:45 +02:00
|
|
|
m_listView(new Utils::NavigationTreeView(this)),
|
2016-04-13 15:52:14 +02:00
|
|
|
m_fileSystemModel(new FolderNavigationModel(this)),
|
|
|
|
|
m_filterHiddenFilesAction(new QAction(tr("Show Hidden Files"), this)),
|
2017-09-15 11:03:45 +02:00
|
|
|
m_toggleSync(new QToolButton(this)),
|
2017-11-07 17:50:32 +01:00
|
|
|
m_rootSelector(new QComboBox),
|
2017-11-22 16:34:31 +01:00
|
|
|
m_crumbLabel(new DelayedFileCrumbLabel(this))
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-11-29 16:18:01 +01:00
|
|
|
m_context = new Core::IContext(this);
|
|
|
|
|
m_context->setContext(Core::Context(C_FOLDERNAVIGATIONWIDGET));
|
|
|
|
|
m_context->setWidget(this);
|
|
|
|
|
Core::ICore::addContextObject(m_context);
|
|
|
|
|
|
2017-11-07 18:03:29 +01:00
|
|
|
setBackgroundRole(QPalette::Base);
|
|
|
|
|
setAutoFillBackground(true);
|
2010-01-26 10:33:39 +01:00
|
|
|
m_fileSystemModel->setResolveSymlinks(false);
|
2013-09-12 16:06:33 +02:00
|
|
|
m_fileSystemModel->setIconProvider(Core::FileIconProvider::iconProvider());
|
2017-09-15 11:03:45 +02:00
|
|
|
QDir::Filters filters = QDir::AllEntries | QDir::NoDotAndDotDot;
|
2013-03-14 11:35:27 +01:00
|
|
|
if (Utils::HostOsInfo::isWindowsHost()) // Symlinked directories can cause file watcher warnings on Win32.
|
|
|
|
|
filters |= QDir::NoSymLinks;
|
2010-01-26 10:33:39 +01:00
|
|
|
m_fileSystemModel->setFilter(filters);
|
2017-09-15 11:03:45 +02:00
|
|
|
m_fileSystemModel->setRootPath(QString());
|
2012-12-02 23:16:02 +01:00
|
|
|
m_filterHiddenFilesAction->setCheckable(true);
|
|
|
|
|
setHiddenFilesFilter(false);
|
2010-07-05 20:53:34 +02:00
|
|
|
m_listView->setIconSize(QSize(16,16));
|
2017-09-15 11:03:45 +02:00
|
|
|
m_listView->setModel(m_fileSystemModel);
|
2017-11-29 16:18:01 +01:00
|
|
|
m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
2014-09-08 12:26:12 +02:00
|
|
|
m_listView->setDragEnabled(true);
|
|
|
|
|
m_listView->setDragDropMode(QAbstractItemView::DragOnly);
|
2017-09-15 11:03:45 +02:00
|
|
|
showOnlyFirstColumn(m_listView);
|
2010-01-26 10:33:39 +01:00
|
|
|
setFocusProxy(m_listView);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-11-07 18:03:29 +01:00
|
|
|
auto selectorWidget = new QWidget(this);
|
|
|
|
|
auto selectorLayout = new QVBoxLayout(selectorWidget);
|
|
|
|
|
selectorWidget->setLayout(selectorLayout);
|
|
|
|
|
selectorLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
selectorLayout->addWidget(m_rootSelector);
|
|
|
|
|
|
2017-11-15 09:20:58 +01:00
|
|
|
auto crumbLayout = new QVBoxLayout;
|
|
|
|
|
crumbLayout->setSpacing(0);
|
|
|
|
|
crumbLayout->setContentsMargins(4, 4, 4, 4);
|
|
|
|
|
crumbLayout->addWidget(m_crumbLabel);
|
|
|
|
|
m_crumbLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
auto layout = new QVBoxLayout();
|
2017-11-07 18:03:29 +01:00
|
|
|
layout->addWidget(selectorWidget);
|
2017-11-15 09:20:58 +01:00
|
|
|
layout->addLayout(crumbLayout);
|
|
|
|
|
layout->addWidget(createHLine());
|
2010-01-26 10:33:39 +01:00
|
|
|
layout->addWidget(m_listView);
|
2008-12-02 12:01:29 +01:00
|
|
|
layout->setSpacing(0);
|
|
|
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
setLayout(layout);
|
|
|
|
|
|
2016-08-03 17:55:54 +02:00
|
|
|
m_toggleSync->setIcon(Utils::Icons::LINK.icon());
|
2012-12-02 23:16:02 +01:00
|
|
|
m_toggleSync->setCheckable(true);
|
|
|
|
|
m_toggleSync->setToolTip(tr("Synchronize with Editor"));
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// connections
|
2016-01-29 16:38:37 +02:00
|
|
|
connect(m_listView, &QAbstractItemView::activated,
|
2017-09-15 11:03:45 +02:00
|
|
|
this, [this](const QModelIndex &index) { openItem(index); });
|
2017-11-22 16:34:31 +01:00
|
|
|
// use QueuedConnection for updating crumble path, because that can scroll, which doesn't
|
|
|
|
|
// work well when done directly in currentChanged (the wrong item can get highlighted)
|
2017-11-07 17:50:32 +01:00
|
|
|
connect(m_listView->selectionModel(),
|
|
|
|
|
&QItemSelectionModel::currentChanged,
|
|
|
|
|
this,
|
2017-11-22 16:34:31 +01:00
|
|
|
&FolderNavigationWidget::setCrumblePath,
|
|
|
|
|
Qt::QueuedConnection);
|
2017-11-07 17:50:32 +01:00
|
|
|
connect(m_crumbLabel, &Utils::FileCrumbLabel::pathClicked, [this](const Utils::FileName &path) {
|
|
|
|
|
const QModelIndex rootIndex = m_listView->rootIndex();
|
|
|
|
|
const QModelIndex fileIndex = m_fileSystemModel->index(path.toString());
|
|
|
|
|
if (!isChildOf(fileIndex, rootIndex))
|
|
|
|
|
selectBestRootForFile(path);
|
|
|
|
|
selectFile(path);
|
|
|
|
|
});
|
|
|
|
|
connect(m_filterHiddenFilesAction,
|
|
|
|
|
&QAction::toggled,
|
|
|
|
|
this,
|
|
|
|
|
&FolderNavigationWidget::setHiddenFilesFilter);
|
2016-01-29 16:38:37 +02:00
|
|
|
connect(m_toggleSync, &QAbstractButton::clicked,
|
|
|
|
|
this, &FolderNavigationWidget::toggleAutoSynchronization);
|
2017-09-15 11:03:45 +02:00
|
|
|
connect(m_rootSelector,
|
|
|
|
|
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);
|
2017-11-15 11:24:26 +01:00
|
|
|
const QModelIndex rootIndex = m_listView->rootIndex();
|
|
|
|
|
const QModelIndex fileIndex = m_listView->currentIndex();
|
|
|
|
|
if (!isChildOf(fileIndex, rootIndex))
|
|
|
|
|
selectFile(directory);
|
2017-09-15 11:03:45 +02:00
|
|
|
});
|
2017-11-17 15:25:16 +01:00
|
|
|
|
|
|
|
|
setAutoSynchronization(true);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
FolderNavigationWidget::~FolderNavigationWidget()
|
|
|
|
|
{
|
|
|
|
|
Core::ICore::removeContextObject(m_context);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void FolderNavigationWidget::toggleAutoSynchronization()
|
|
|
|
|
{
|
|
|
|
|
setAutoSynchronization(!m_autoSync);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-26 17:19:00 +02:00
|
|
|
static bool itemLessThan(QComboBox *combo,
|
|
|
|
|
int index,
|
|
|
|
|
const FolderNavigationWidgetFactory::RootDirectory &directory)
|
|
|
|
|
{
|
|
|
|
|
return combo->itemData(index, SORT_ROLE).toInt() < directory.sortValue
|
|
|
|
|
|| (combo->itemData(index, SORT_ROLE).toInt() == directory.sortValue
|
|
|
|
|
&& combo->itemData(index, Qt::DisplayRole).toString() < directory.displayName);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-18 13:39:35 +02:00
|
|
|
void FolderNavigationWidget::insertRootDirectory(
|
2017-09-15 13:30:26 +02:00
|
|
|
const FolderNavigationWidgetFactory::RootDirectory &directory)
|
2017-09-15 11:03:45 +02:00
|
|
|
{
|
2017-09-26 17:19:00 +02:00
|
|
|
// Find existing. Do not remove yet, to not mess up the current selection.
|
|
|
|
|
int previousIndex = 0;
|
|
|
|
|
while (previousIndex < m_rootSelector->count()
|
|
|
|
|
&& m_rootSelector->itemData(previousIndex, ID_ROLE).toString() != directory.id)
|
|
|
|
|
++previousIndex;
|
|
|
|
|
// Insert sorted.
|
2017-09-15 13:30:26 +02:00
|
|
|
int index = 0;
|
2017-09-26 17:19:00 +02:00
|
|
|
while (index < m_rootSelector->count() && itemLessThan(m_rootSelector, index, directory))
|
2017-09-15 13:30:26 +02:00
|
|
|
++index;
|
2017-09-26 17:19:00 +02:00
|
|
|
m_rootSelector->insertItem(index, directory.displayName);
|
|
|
|
|
if (index <= previousIndex) // item was inserted, update previousIndex
|
|
|
|
|
++previousIndex;
|
2017-09-15 13:30:26 +02:00
|
|
|
m_rootSelector->setItemData(index, qVariantFromValue(directory.path), PATH_ROLE);
|
|
|
|
|
m_rootSelector->setItemData(index, directory.id, ID_ROLE);
|
2017-09-26 17:19:00 +02:00
|
|
|
m_rootSelector->setItemData(index, directory.sortValue, SORT_ROLE);
|
2017-09-15 13:30:26 +02:00
|
|
|
m_rootSelector->setItemData(index, directory.path.toUserOutput(), Qt::ToolTipRole);
|
2017-10-09 06:59:54 +02:00
|
|
|
m_rootSelector->setItemIcon(index, directory.icon);
|
2017-09-26 17:19:00 +02:00
|
|
|
if (m_rootSelector->currentIndex() == previousIndex)
|
|
|
|
|
m_rootSelector->setCurrentIndex(index);
|
|
|
|
|
if (previousIndex < m_rootSelector->count())
|
|
|
|
|
m_rootSelector->removeItem(previousIndex);
|
2017-09-15 11:03:45 +02:00
|
|
|
if (m_autoSync) // we might find a better root for current selection now
|
|
|
|
|
setCurrentEditor(Core::EditorManager::currentEditor());
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 13:30:26 +02:00
|
|
|
void FolderNavigationWidget::removeRootDirectory(const QString &id)
|
2017-09-15 11:03:45 +02:00
|
|
|
{
|
|
|
|
|
for (int i = 0; i < m_rootSelector->count(); ++i) {
|
2017-09-15 13:30:26 +02:00
|
|
|
if (m_rootSelector->itemData(i, ID_ROLE).toString() == id) {
|
2017-09-15 11:03:45 +02:00
|
|
|
m_rootSelector->removeItem(i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (m_autoSync) // we might need to find a new root for current selection
|
|
|
|
|
setCurrentEditor(Core::EditorManager::currentEditor());
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
void FolderNavigationWidget::editCurrentItem()
|
|
|
|
|
{
|
|
|
|
|
const QModelIndex current = m_listView->currentIndex();
|
|
|
|
|
if (m_fileSystemModel->flags(current) & Qt::ItemIsEditable)
|
|
|
|
|
m_listView->edit(current);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool FolderNavigationWidget::autoSynchronization() const
|
|
|
|
|
{
|
|
|
|
|
return m_autoSync;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNavigationWidget::setAutoSynchronization(bool sync)
|
|
|
|
|
{
|
2012-12-02 23:16:02 +01:00
|
|
|
m_toggleSync->setChecked(sync);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (sync == m_autoSync)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_autoSync = sync;
|
|
|
|
|
|
|
|
|
|
if (m_autoSync) {
|
2015-01-16 17:45:06 +01:00
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
|
2017-09-15 11:03:45 +02:00
|
|
|
this, &FolderNavigationWidget::setCurrentEditor);
|
|
|
|
|
setCurrentEditor(Core::EditorManager::currentEditor());
|
2008-12-02 12:01:29 +01:00
|
|
|
} else {
|
2015-01-16 17:45:06 +01:00
|
|
|
disconnect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
|
2017-09-15 11:03:45 +02:00
|
|
|
this, &FolderNavigationWidget::setCurrentEditor);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
void FolderNavigationWidget::setCurrentEditor(Core::IEditor *editor)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-10-20 12:51:13 +02:00
|
|
|
if (!editor || editor->document()->filePath().isEmpty() || editor->document()->isTemporary())
|
2015-01-19 14:59:25 +01:00
|
|
|
return;
|
2017-09-15 11:03:45 +02:00
|
|
|
const Utils::FileName filePath = editor->document()->filePath();
|
2017-11-07 17:50:32 +01:00
|
|
|
selectBestRootForFile(filePath);
|
|
|
|
|
selectFile(filePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNavigationWidget::selectBestRootForFile(const Utils::FileName &filePath)
|
|
|
|
|
{
|
2017-09-15 11:03:45 +02:00
|
|
|
const int bestRootIndex = bestRootForFile(filePath);
|
|
|
|
|
m_rootSelector->setCurrentIndex(bestRootIndex);
|
2010-01-26 10:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
void FolderNavigationWidget::selectFile(const Utils::FileName &filePath)
|
2010-01-26 10:33:39 +01:00
|
|
|
{
|
2017-09-15 11:03:45 +02:00
|
|
|
const QModelIndex fileIndex = m_fileSystemModel->index(filePath.toString());
|
2017-11-15 11:24:26 +01:00
|
|
|
if (fileIndex.isValid() || filePath.isEmpty() /* Computer root */) {
|
2017-09-15 11:03:45 +02:00
|
|
|
// TODO This only scrolls to the right position if all directory contents are loaded.
|
|
|
|
|
// Unfortunately listening to directoryLoaded was still not enough (there might also
|
|
|
|
|
// 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());
|
2017-11-07 17:50:32 +01:00
|
|
|
if (fileIndex == m_listView->rootIndex()) {
|
|
|
|
|
m_listView->horizontalScrollBar()->setValue(0);
|
|
|
|
|
m_listView->verticalScrollBar()->setValue(0);
|
|
|
|
|
} else {
|
|
|
|
|
m_listView->scrollTo(fileIndex);
|
|
|
|
|
}
|
2017-09-15 11:03:45 +02:00
|
|
|
});
|
2010-04-21 13:42:36 +02:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
void FolderNavigationWidget::setRootDirectory(const Utils::FileName &directory)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-09-15 11:03:45 +02:00
|
|
|
const QModelIndex index = m_fileSystemModel->setRootPath(directory.toString());
|
|
|
|
|
m_listView->setRootIndex(index);
|
2010-01-26 10:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
int FolderNavigationWidget::bestRootForFile(const Utils::FileName &filePath)
|
2010-01-26 10:33:39 +01:00
|
|
|
{
|
2017-09-15 11:03:45 +02:00
|
|
|
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;
|
2010-01-26 10:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-15 11:03:45 +02:00
|
|
|
void FolderNavigationWidget::openItem(const QModelIndex &index)
|
2010-01-26 10:33:39 +01:00
|
|
|
{
|
2017-10-09 11:11:22 +02:00
|
|
|
QTC_ASSERT(index.isValid(), return);
|
|
|
|
|
// signal "activate" is also sent when double-clicking folders
|
|
|
|
|
// but we don't want to do anything in that case
|
|
|
|
|
if (m_fileSystemModel->isDir(index))
|
2010-01-26 10:33:39 +01:00
|
|
|
return;
|
2017-09-15 11:03:45 +02:00
|
|
|
const QString path = m_fileSystemModel->filePath(index);
|
2017-10-09 11:11:22 +02:00
|
|
|
Core::EditorManager::openEditor(path);
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-20 14:52:16 +02:00
|
|
|
QStringList FolderNavigationWidget::projectsInDirectory(const QModelIndex &index) const
|
2017-10-09 11:11:22 +02:00
|
|
|
{
|
2017-10-20 14:52:16 +02:00
|
|
|
QTC_ASSERT(index.isValid() && m_fileSystemModel->isDir(index), return {});
|
2017-10-09 11:11:22 +02:00
|
|
|
const QFileInfo fi = m_fileSystemModel->fileInfo(index);
|
|
|
|
|
if (!fi.isReadable() || !fi.isExecutable())
|
2017-10-20 14:52:16 +02:00
|
|
|
return {};
|
2017-10-09 11:11:22 +02:00
|
|
|
const QString path = m_fileSystemModel->filePath(index);
|
|
|
|
|
// Try to find project files in directory and open those.
|
2017-10-20 14:52:16 +02:00
|
|
|
return FolderNavigationWidget::projectFilesInDirectory(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNavigationWidget::openProjectsInDirectory(const QModelIndex &index)
|
|
|
|
|
{
|
|
|
|
|
const QStringList projectFiles = projectsInDirectory(index);
|
2017-10-09 11:11:22 +02:00
|
|
|
if (!projectFiles.isEmpty())
|
|
|
|
|
Core::ICore::instance()->openFiles(projectFiles);
|
2010-01-26 10:33:39 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-22 16:34:31 +01:00
|
|
|
void FolderNavigationWidget::setCrumblePath(const QModelIndex &index, const QModelIndex &)
|
|
|
|
|
{
|
|
|
|
|
const int width = m_crumbLabel->width();
|
|
|
|
|
const int previousHeight = m_crumbLabel->immediateHeightForWidth(width);
|
|
|
|
|
m_crumbLabel->setPath(Utils::FileName::fromString(m_fileSystemModel->filePath(index)));
|
|
|
|
|
const int currentHeight = m_crumbLabel->immediateHeightForWidth(width);
|
|
|
|
|
const int diff = currentHeight - previousHeight;
|
|
|
|
|
if (diff != 0 && m_crumbLabel->isVisible()) {
|
|
|
|
|
// try to fix scroll position, otherwise delay layouting
|
|
|
|
|
QScrollBar *bar = m_listView->verticalScrollBar();
|
|
|
|
|
const int newBarValue = bar ? bar->value() + diff : 0;
|
|
|
|
|
if (bar && bar->minimum() <= newBarValue && bar->maximum() >= newBarValue) {
|
|
|
|
|
// we need to set the scroll bar when the layout request from the crumble path is
|
|
|
|
|
// handled, otherwise it will flicker
|
|
|
|
|
m_crumbLabel->setScrollBarOnce(bar, newBarValue);
|
|
|
|
|
} else {
|
|
|
|
|
m_crumbLabel->delayLayoutOnce();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-26 10:33:39 +01:00
|
|
|
void FolderNavigationWidget::contextMenuEvent(QContextMenuEvent *ev)
|
|
|
|
|
{
|
|
|
|
|
QMenu menu;
|
|
|
|
|
// Open current item
|
2017-09-15 11:03:45 +02:00
|
|
|
const QModelIndex current = m_listView->currentIndex();
|
2010-01-26 12:31:58 +01:00
|
|
|
const bool hasCurrentItem = current.isValid();
|
2017-10-09 11:11:22 +02:00
|
|
|
QAction *actionOpenFile = nullptr;
|
|
|
|
|
QAction *actionOpenProjects = nullptr;
|
2017-10-12 12:07:29 +02:00
|
|
|
QAction *actionOpenAsProject = nullptr;
|
2017-11-08 13:15:36 +01:00
|
|
|
const bool isDir = m_fileSystemModel->isDir(current);
|
2017-10-12 12:07:29 +02:00
|
|
|
const Utils::FileName filePath = hasCurrentItem ? Utils::FileName::fromString(
|
|
|
|
|
m_fileSystemModel->filePath(current))
|
|
|
|
|
: Utils::FileName();
|
2017-09-15 11:03:45 +02:00
|
|
|
if (hasCurrentItem) {
|
|
|
|
|
const QString fileName = m_fileSystemModel->fileName(current);
|
2017-11-08 13:15:36 +01:00
|
|
|
if (isDir) {
|
2017-10-09 11:11:22 +02:00
|
|
|
actionOpenProjects = menu.addAction(tr("Open Project in \"%1\"").arg(fileName));
|
2017-10-20 14:52:16 +02:00
|
|
|
if (projectsInDirectory(current).isEmpty())
|
|
|
|
|
actionOpenProjects->setEnabled(false);
|
2017-10-12 12:07:29 +02:00
|
|
|
} else {
|
2017-10-09 11:11:22 +02:00
|
|
|
actionOpenFile = menu.addAction(tr("Open \"%1\"").arg(fileName));
|
2017-10-12 12:07:29 +02:00
|
|
|
if (ProjectExplorerPlugin::isProjectFile(Utils::FileName::fromString(fileName)))
|
|
|
|
|
actionOpenAsProject = menu.addAction(tr("Open Project \"%1\"").arg(fileName));
|
|
|
|
|
}
|
2017-09-15 11:03:45 +02:00
|
|
|
}
|
2015-01-23 13:59:55 +01:00
|
|
|
|
|
|
|
|
// we need dummy DocumentModel::Entry with absolute file path in it
|
|
|
|
|
// to get EditorManager::addNativeDirAndOpenWithActions() working
|
|
|
|
|
Core::DocumentModel::Entry fakeEntry;
|
|
|
|
|
Core::IDocument document;
|
2017-10-12 12:07:29 +02:00
|
|
|
document.setFilePath(filePath);
|
2015-01-23 13:59:55 +01:00
|
|
|
fakeEntry.document = &document;
|
|
|
|
|
Core::EditorManager::addNativeDirAndOpenWithActions(&menu, &fakeEntry);
|
|
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
if (hasCurrentItem) {
|
|
|
|
|
if (m_fileSystemModel->flags(current) & Qt::ItemIsEditable)
|
|
|
|
|
menu.addAction(Core::ActionManager::command(Constants::RENAMEFILE)->action());
|
|
|
|
|
if (!isDir && Core::DiffService::instance()) {
|
2017-11-08 13:15:36 +01:00
|
|
|
menu.addAction(
|
|
|
|
|
TextEditor::TextDocument::createDiffAgainstCurrentFileAction(&menu, [filePath]() {
|
|
|
|
|
return filePath;
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-26 10:33:39 +01:00
|
|
|
QAction *action = menu.exec(ev->globalPos());
|
|
|
|
|
if (!action)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ev->accept();
|
2017-10-09 11:11:22 +02:00
|
|
|
if (action == actionOpenFile)
|
2010-01-26 10:33:39 +01:00
|
|
|
openItem(current);
|
2017-10-12 12:07:29 +02:00
|
|
|
else if (action == actionOpenAsProject)
|
|
|
|
|
ProjectExplorerPlugin::openProject(filePath.toString());
|
2017-10-09 11:11:22 +02:00
|
|
|
else if (action == actionOpenProjects)
|
|
|
|
|
openProjectsInDirectory(current);
|
2010-01-26 12:31:58 +01:00
|
|
|
}
|
|
|
|
|
|
2012-12-02 23:16:02 +01:00
|
|
|
void FolderNavigationWidget::setHiddenFilesFilter(bool filter)
|
|
|
|
|
{
|
|
|
|
|
QDir::Filters filters = m_fileSystemModel->filter();
|
|
|
|
|
if (filter)
|
|
|
|
|
filters |= QDir::Hidden;
|
|
|
|
|
else
|
|
|
|
|
filters &= ~(QDir::Hidden);
|
|
|
|
|
m_fileSystemModel->setFilter(filters);
|
|
|
|
|
m_filterHiddenFilesAction->setChecked(filter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FolderNavigationWidget::hiddenFilesFilter() const
|
|
|
|
|
{
|
|
|
|
|
return m_filterHiddenFilesAction->isChecked();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-26 15:16:55 +01:00
|
|
|
QStringList FolderNavigationWidget::projectFilesInDirectory(const QString &path)
|
|
|
|
|
{
|
|
|
|
|
QDir dir(path);
|
|
|
|
|
QStringList projectFiles;
|
|
|
|
|
foreach (const QFileInfo &i, dir.entryInfoList(ProjectExplorerPlugin::projectFileGlobs(), QDir::Files))
|
|
|
|
|
projectFiles.append(i.absoluteFilePath());
|
|
|
|
|
return projectFiles;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-26 10:33:39 +01:00
|
|
|
// --------------------FolderNavigationWidgetFactory
|
2009-01-20 17:14:00 +01:00
|
|
|
FolderNavigationWidgetFactory::FolderNavigationWidgetFactory()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-09-15 11:03:45 +02:00
|
|
|
m_instance = this;
|
2014-06-24 11:15:32 +02:00
|
|
|
setDisplayName(tr("File System"));
|
|
|
|
|
setPriority(400);
|
|
|
|
|
setId("File System");
|
|
|
|
|
setActivationSequence(QKeySequence(Core::UseMacShortcuts ? tr("Meta+Y") : tr("Alt+Y")));
|
2017-09-26 17:19:00 +02:00
|
|
|
insertRootDirectory({QLatin1String("A.Computer"),
|
|
|
|
|
0 /*sortValue*/,
|
|
|
|
|
FolderNavigationWidget::tr("Computer"),
|
2017-10-09 06:59:54 +02:00
|
|
|
Utils::FileName(),
|
|
|
|
|
Icons::DESKTOP_DEVICE_SMALL.icon()});
|
2017-09-18 13:39:35 +02:00
|
|
|
insertRootDirectory({QLatin1String("A.Home"),
|
2017-09-26 17:19:00 +02:00
|
|
|
10 /*sortValue*/,
|
2017-09-18 13:39:35 +02:00
|
|
|
FolderNavigationWidget::tr("Home"),
|
2017-10-09 06:59:54 +02:00
|
|
|
Utils::FileName::fromString(QDir::homePath()),
|
|
|
|
|
Utils::Icons::HOME.icon()});
|
2017-09-18 13:39:35 +02:00
|
|
|
updateProjectsDirectoryRoot();
|
|
|
|
|
connect(Core::DocumentManager::instance(),
|
|
|
|
|
&Core::DocumentManager::projectsDirectoryChanged,
|
|
|
|
|
this,
|
|
|
|
|
&FolderNavigationWidgetFactory::updateProjectsDirectoryRoot);
|
2017-11-29 16:18:01 +01:00
|
|
|
registerActions();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Core::NavigationView FolderNavigationWidgetFactory::createWidget()
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto fnw = new FolderNavigationWidget;
|
2017-09-15 13:30:26 +02:00
|
|
|
for (const RootDirectory &root : m_rootDirectories)
|
2017-09-18 13:39:35 +02:00
|
|
|
fnw->insertRootDirectory(root);
|
2017-09-15 11:03:45 +02:00
|
|
|
connect(this,
|
|
|
|
|
&FolderNavigationWidgetFactory::rootDirectoryAdded,
|
|
|
|
|
fnw,
|
2017-09-18 13:39:35 +02:00
|
|
|
&FolderNavigationWidget::insertRootDirectory);
|
2017-09-15 11:03:45 +02:00
|
|
|
connect(this,
|
|
|
|
|
&FolderNavigationWidgetFactory::rootDirectoryRemoved,
|
|
|
|
|
fnw,
|
|
|
|
|
&FolderNavigationWidget::removeRootDirectory);
|
|
|
|
|
|
|
|
|
|
Core::NavigationView n;
|
2012-12-02 23:16:02 +01:00
|
|
|
n.widget = fnw;
|
2016-04-13 15:52:14 +02:00
|
|
|
auto filter = new QToolButton;
|
2016-08-03 17:55:54 +02:00
|
|
|
filter->setIcon(Utils::Icons::FILTER.icon());
|
2012-12-02 23:16:02 +01:00
|
|
|
filter->setToolTip(tr("Filter Files"));
|
|
|
|
|
filter->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
|
filter->setProperty("noArrow", true);
|
2016-04-13 15:52:14 +02:00
|
|
|
auto filterMenu = new QMenu(filter);
|
2012-12-02 23:16:02 +01:00
|
|
|
filterMenu->addAction(fnw->m_filterHiddenFilesAction);
|
|
|
|
|
filter->setMenu(filterMenu);
|
|
|
|
|
n.dockToolBarWidgets << filter << fnw->m_toggleSync;
|
2008-12-02 12:01:29 +01:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-17 18:31:56 +03:00
|
|
|
void FolderNavigationWidgetFactory::saveSettings(QSettings *settings, int position, QWidget *widget)
|
2012-12-02 23:16:02 +01:00
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto fnw = qobject_cast<FolderNavigationWidget *>(widget);
|
2012-12-02 23:16:02 +01:00
|
|
|
QTC_ASSERT(fnw, return);
|
|
|
|
|
const QString baseKey = QLatin1String("FolderNavigationWidget.") + QString::number(position);
|
|
|
|
|
settings->setValue(baseKey + QLatin1String(".HiddenFilesFilter"), fnw->hiddenFilesFilter());
|
|
|
|
|
settings->setValue(baseKey + QLatin1String(".SyncWithEditor"), fnw->autoSynchronization());
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-17 18:31:56 +03:00
|
|
|
void FolderNavigationWidgetFactory::restoreSettings(QSettings *settings, int position, QWidget *widget)
|
2012-12-02 23:16:02 +01:00
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto fnw = qobject_cast<FolderNavigationWidget *>(widget);
|
2012-12-02 23:16:02 +01:00
|
|
|
QTC_ASSERT(fnw, return);
|
|
|
|
|
const QString baseKey = QLatin1String("FolderNavigationWidget.") + QString::number(position);
|
|
|
|
|
fnw->setHiddenFilesFilter(settings->value(baseKey + QLatin1String(".HiddenFilesFilter"), false).toBool());
|
|
|
|
|
fnw->setAutoSynchronization(settings->value(baseKey + QLatin1String(".SyncWithEditor"), true).toBool());
|
|
|
|
|
}
|
2017-09-15 11:03:45 +02:00
|
|
|
|
2017-09-18 13:39:35 +02:00
|
|
|
void FolderNavigationWidgetFactory::insertRootDirectory(const RootDirectory &directory)
|
2017-09-15 11:03:45 +02:00
|
|
|
{
|
2017-09-18 13:39:35 +02:00
|
|
|
const int index = rootIndex(directory.id);
|
|
|
|
|
if (index < 0)
|
|
|
|
|
m_rootDirectories.append(directory);
|
2017-09-29 12:54:28 +02:00
|
|
|
else
|
|
|
|
|
m_rootDirectories[index] = directory;
|
2017-09-15 13:30:26 +02:00
|
|
|
emit m_instance->rootDirectoryAdded(directory);
|
2017-09-15 11:03:45 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-15 13:30:26 +02:00
|
|
|
void FolderNavigationWidgetFactory::removeRootDirectory(const QString &id)
|
2017-09-15 11:03:45 +02:00
|
|
|
{
|
2017-09-18 13:39:35 +02:00
|
|
|
const int index = rootIndex(id);
|
2017-09-15 13:30:26 +02:00
|
|
|
QTC_ASSERT(index >= 0, return );
|
2017-09-15 11:03:45 +02:00
|
|
|
m_rootDirectories.removeAt(index);
|
2017-09-15 13:30:26 +02:00
|
|
|
emit m_instance->rootDirectoryRemoved(id);
|
2017-09-15 11:03:45 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-18 13:39:35 +02:00
|
|
|
int FolderNavigationWidgetFactory::rootIndex(const QString &id)
|
|
|
|
|
{
|
|
|
|
|
return Utils::indexOf(m_rootDirectories,
|
|
|
|
|
[id](const RootDirectory &entry) { return entry.id == id; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FolderNavigationWidgetFactory::updateProjectsDirectoryRoot()
|
|
|
|
|
{
|
|
|
|
|
insertRootDirectory({QLatin1String(PROJECTSDIRECTORYROOT_ID),
|
2017-09-26 17:19:00 +02:00
|
|
|
20 /*sortValue*/,
|
2017-09-18 13:39:35 +02:00
|
|
|
FolderNavigationWidget::tr("Projects"),
|
2017-10-09 06:59:54 +02:00
|
|
|
Core::DocumentManager::projectsDirectory(),
|
|
|
|
|
Utils::Icons::PROJECT.icon()});
|
2017-09-18 13:39:35 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-29 16:18:01 +01:00
|
|
|
void FolderNavigationWidgetFactory::registerActions()
|
|
|
|
|
{
|
|
|
|
|
Core::Context context(C_FOLDERNAVIGATIONWIDGET);
|
|
|
|
|
auto rename = new QAction(this);
|
|
|
|
|
Core::ActionManager::registerAction(rename, Constants::RENAMEFILE, context);
|
|
|
|
|
connect(rename, &QAction::triggered, Core::ICore::instance(), [] {
|
|
|
|
|
Core::IContext *context = Core::ICore::currentContextObject();
|
|
|
|
|
QWidget *widget = context ? context->widget() : nullptr;
|
|
|
|
|
if (auto navWidget = qobject_cast<FolderNavigationWidget *>(widget))
|
|
|
|
|
navWidget->editCurrentItem();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 16:34:31 +01:00
|
|
|
int DelayedFileCrumbLabel::immediateHeightForWidth(int w) const
|
|
|
|
|
{
|
|
|
|
|
return Utils::FileCrumbLabel::heightForWidth(w);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int DelayedFileCrumbLabel::heightForWidth(int w) const
|
|
|
|
|
{
|
|
|
|
|
static QHash<int, int> oldHeight;
|
|
|
|
|
setScrollBarOnce();
|
|
|
|
|
int newHeight = Utils::FileCrumbLabel::heightForWidth(w);
|
|
|
|
|
if (!m_delaying || !oldHeight.contains(w)) {
|
|
|
|
|
oldHeight.insert(w, newHeight);
|
|
|
|
|
} else if (oldHeight.value(w) != newHeight){
|
|
|
|
|
auto that = const_cast<DelayedFileCrumbLabel *>(this);
|
|
|
|
|
QTimer::singleShot(QApplication::doubleClickInterval(), that, [that, w, newHeight] {
|
|
|
|
|
oldHeight.insert(w, newHeight);
|
|
|
|
|
that->m_delaying = false;
|
|
|
|
|
that->updateGeometry();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return oldHeight.value(w);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DelayedFileCrumbLabel::delayLayoutOnce()
|
|
|
|
|
{
|
|
|
|
|
m_delaying = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DelayedFileCrumbLabel::setScrollBarOnce(QScrollBar *bar, int value)
|
|
|
|
|
{
|
|
|
|
|
m_bar = bar;
|
|
|
|
|
m_barValue = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DelayedFileCrumbLabel::setScrollBarOnce() const
|
|
|
|
|
{
|
|
|
|
|
if (!m_bar)
|
|
|
|
|
return;
|
|
|
|
|
auto that = const_cast<DelayedFileCrumbLabel *>(this);
|
|
|
|
|
that->m_bar->setValue(m_barValue);
|
|
|
|
|
that->m_bar.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-25 15:09:16 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace ProjectExplorer
|