diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ae4532b2bd5..4e3d00298bf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1521,31 +1521,26 @@ void DebuggerPluginPrivate::attachCore() if (!lastExternalKit.isEmpty()) dlg.setKitId(Id::fromString(lastExternalKit)); dlg.setSymbolFile(FilePath::fromSettings(configValue("LastExternalExecutableFile"))); - dlg.setLocalCoreFile(FilePath::fromSettings(configValue("LastLocalCoreFile"))); - dlg.setRemoteCoreFile(FilePath::fromSettings(configValue("LastRemoteCoreFile"))); + dlg.setCoreFile(FilePath::fromSettings(configValue("LastLocalCoreFile"))); dlg.setOverrideStartScript(FilePath::fromSettings(configValue("LastExternalStartScript"))); dlg.setSysRoot(FilePath::fromSettings(configValue("LastSysRoot"))); - dlg.setForceLocalCoreFile(configValue("LastForceLocalCoreFile").toBool()); if (dlg.exec() != QDialog::Accepted) return; setConfigValue("LastExternalExecutableFile", dlg.symbolFile().toSettings()); - setConfigValue("LastLocalCoreFile", dlg.localCoreFile().toSettings()); - setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile().toSettings()); + setConfigValue("LastLocalCoreFile", dlg.coreFile().toSettings()); setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); setConfigValue("LastExternalStartScript", dlg.overrideStartScript().toSettings()); setConfigValue("LastSysRoot", dlg.sysRoot().toSettings()); - setConfigValue("LastForceLocalCoreFile", dlg.forcesLocalCoreFile()); auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE); runControl->setKit(dlg.kit()); - runControl->setDisplayName(Tr::tr("Core file \"%1\"") - .arg(dlg.useLocalCoreFile() ? dlg.localCoreFile().toUserOutput() - : dlg.remoteCoreFile().toUserOutput())); + runControl->setDisplayName(Tr::tr("Core file \"%1\"").arg(dlg.coreFile().toUserOutput())); auto debugger = new DebuggerRunTool(runControl); - debugger->setInferiorExecutable(dlg.symbolFile()); - debugger->setCoreFilePath(dlg.localCoreFile()); + + debugger->setInferiorExecutable(dlg.symbolFileCopy()); + debugger->setCoreFilePath(dlg.coreFileCopy()); debugger->setStartMode(AttachToCore); debugger->setCloseMode(DetachAtClose); debugger->setOverrideStartScript(dlg.overrideStartScript()); diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index b360f937018..86c9c738dc3 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -7,16 +7,17 @@ #include "debuggertr.h" #include "gdb/gdbengine.h" -#include -#include #include #include #include +#include #include #include #include +#include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,112 +38,6 @@ using namespace Utils; namespace Debugger::Internal { -/////////////////////////////////////////////////////////////////////// -// -// SelectRemoteFileDialog -// -/////////////////////////////////////////////////////////////////////// - -class SelectRemoteFileDialog : public QDialog -{ -public: - explicit SelectRemoteFileDialog(QWidget *parent); - - void attachToDevice(Kit *k); - FilePath localFile() const { return m_localFile; } - FilePath remoteFile() const { return m_remoteFile; } - -private: - void selectFile(); - - QSortFilterProxyModel m_model; - DeviceFileSystemModel m_fileSystemModel; - QTreeView *m_fileSystemView; - QTextBrowser *m_textBrowser; - QDialogButtonBox *m_buttonBox; - FilePath m_localFile; - FilePath m_remoteFile; - FileTransfer m_fileTransfer; -}; - -SelectRemoteFileDialog::SelectRemoteFileDialog(QWidget *parent) - : QDialog(parent) -{ - m_model.setSourceModel(&m_fileSystemModel); - - m_fileSystemView = new QTreeView(this); - m_fileSystemView->setModel(&m_model); - m_fileSystemView->setSortingEnabled(true); - m_fileSystemView->sortByColumn(1, Qt::AscendingOrder); - m_fileSystemView->setUniformRowHeights(true); - m_fileSystemView->setSelectionMode(QAbstractItemView::SingleSelection); - m_fileSystemView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_fileSystemView->header()->setDefaultSectionSize(100); - m_fileSystemView->header()->setStretchLastSection(true); - - m_textBrowser = new QTextBrowser(this); - m_textBrowser->setReadOnly(true); - - m_buttonBox = new QDialogButtonBox(this); - m_buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); - m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - - auto layout = new QVBoxLayout(this); - layout->addWidget(m_fileSystemView); - layout->addWidget(m_textBrowser); - layout->addWidget(m_buttonBox); - - connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(m_buttonBox, &QDialogButtonBox::accepted, this, &SelectRemoteFileDialog::selectFile); - - connect(&m_fileTransfer, &FileTransfer::done, this, [this](const ProcessResultData &result) { - const bool success = result.m_error == QProcess::UnknownError - && result.m_exitStatus == QProcess::NormalExit - && result.m_exitCode == 0; - if (success) { - m_textBrowser->append(Tr::tr("Download of remote file succeeded.")); - accept(); - } else { - m_textBrowser->append(Tr::tr("Download of remote file failed: %1") - .arg(result.m_errorString)); - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - m_fileSystemView->setEnabled(true); - } - }); -} - -void SelectRemoteFileDialog::attachToDevice(Kit *k) -{ - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - QTC_ASSERT(k, return); - IDevice::ConstPtr device = DeviceKitAspect::device(k); - QTC_ASSERT(device, return); - m_fileSystemModel.setDevice(device); -} - -void SelectRemoteFileDialog::selectFile() -{ - QModelIndex idx = m_model.mapToSource(m_fileSystemView->currentIndex()); - if (!idx.isValid()) - return; - - m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - m_fileSystemView->setEnabled(false); - - { - TemporaryFile localFile("remotecore-XXXXXX"); - localFile.open(); - m_localFile = FilePath::fromString(localFile.fileName()); - } - - idx = idx.sibling(idx.row(), 1); - m_remoteFile = FilePath::fromVariant(m_fileSystemModel.data(idx, DeviceFileSystemModel::PathRole)); - - m_fileTransfer.setFilesToTransfer({{m_remoteFile, m_localFile}}); - m_fileTransfer.start(); -} - /////////////////////////////////////////////////////////////////////// // // AttachCoreDialog @@ -153,17 +49,20 @@ class AttachCoreDialogPrivate public: KitChooser *kitChooser; - QCheckBox *forceLocalCheckBox; - QLabel *forceLocalLabel; PathChooser *symbolFileName; - PathChooser *localCoreFileName; - PathChooser *remoteCoreFileName; - QPushButton *selectRemoteCoreButton; - + PathChooser *coreFileName; PathChooser *overrideStartScriptFileName; PathChooser *sysRootDirectory; + FilePath debuggerPath; + QDialogButtonBox *buttonBox; + ProgressIndicator *progressIndicator; + QLabel *progressLabel; + + TaskTree taskTree; + expected_str coreFileResult; + expected_str symbolFileResult; struct State { @@ -175,23 +74,14 @@ public: bool validKit; bool validSymbolFilename; bool validCoreFilename; - bool localCoreFile; - bool localKit; }; - State getDialogState(const AttachCoreDialog &p) const + State getDialogState() const { State st; - st.localCoreFile = p.useLocalCoreFile(); st.validKit = (kitChooser->currentKit() != nullptr); st.validSymbolFilename = symbolFileName->isValid(); - - if (st.localCoreFile) - st.validCoreFilename = localCoreFileName->isValid(); - else - st.validCoreFilename = !p.remoteCoreFile().isEmpty(); - - st.localKit = p.isLocalKit(); + st.validCoreFilename = coreFileName->isValid(); return st; } }; @@ -210,23 +100,17 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent) d->kitChooser->setShowIcons(true); d->kitChooser->populate(); - d->forceLocalCheckBox = new QCheckBox(this); - d->forceLocalLabel = new QLabel(this); - d->forceLocalLabel->setText(Tr::tr("Use local core file:")); - d->forceLocalLabel->setBuddy(d->forceLocalCheckBox); - - d->remoteCoreFileName = new PathChooser(this); - d->selectRemoteCoreButton = new QPushButton(PathChooser::browseButtonLabel(), this); - - d->localCoreFileName = new PathChooser(this); - d->localCoreFileName->setHistoryCompleter("Debugger.CoreFile.History"); - d->localCoreFileName->setExpectedKind(PathChooser::File); - d->localCoreFileName->setPromptDialogTitle(Tr::tr("Select Core File")); + d->coreFileName = new PathChooser(this); + d->coreFileName->setHistoryCompleter("Debugger.CoreFile.History"); + d->coreFileName->setExpectedKind(PathChooser::File); + d->coreFileName->setPromptDialogTitle(Tr::tr("Select Core File")); + d->coreFileName->setAllowPathFromDevice(true); d->symbolFileName = new PathChooser(this); - d->symbolFileName->setHistoryCompleter("LocalExecutable"); + d->symbolFileName->setHistoryCompleter("Executable"); d->symbolFileName->setExpectedKind(PathChooser::File); d->symbolFileName->setPromptDialogTitle(Tr::tr("Select Executable or Symbol File")); + d->symbolFileName->setAllowPathFromDevice(true); d->symbolFileName->setToolTip( Tr::tr("Select a file containing debug information corresponding to the core file. " "Typically, this is the executable or a *.debug file if the debug " @@ -244,28 +128,30 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent) d->sysRootDirectory->setToolTip(Tr::tr( "This option can be used to override the kit's SysRoot setting")); - auto coreLayout = new QHBoxLayout; - coreLayout->addWidget(d->localCoreFileName); - coreLayout->addWidget(d->remoteCoreFileName); - coreLayout->addWidget(d->selectRemoteCoreButton); + d->progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small, this); + d->progressIndicator->setVisible(false); - auto formLayout = new QFormLayout; - formLayout->setContentsMargins(0, 0, 0, 0); - formLayout->setHorizontalSpacing(6); - formLayout->setVerticalSpacing(6); - formLayout->addRow(Tr::tr("Kit:"), d->kitChooser); - formLayout->addRow(d->forceLocalLabel, d->forceLocalCheckBox); - formLayout->addRow(Tr::tr("Core file:"), coreLayout); - formLayout->addRow(Tr::tr("&Executable or symbol file:"), d->symbolFileName); - formLayout->addRow(Tr::tr("Override &start script:"), d->overrideStartScriptFileName); - formLayout->addRow(Tr::tr("Override S&ysRoot:"), d->sysRootDirectory); - formLayout->addRow(d->buttonBox); + d->progressLabel = new QLabel(); + d->progressLabel->setVisible(false); - auto vboxLayout = new QVBoxLayout(this); - vboxLayout->addLayout(formLayout); - vboxLayout->addStretch(); - vboxLayout->addWidget(Layouting::createHr()); - vboxLayout->addWidget(d->buttonBox); + // clang-format off + using namespace Layouting; + + Column { + Form { + Tr::tr("Kit:"), d->kitChooser, br, + Tr::tr("Core file:"), d->coreFileName, br, + Tr::tr("&Executable or symbol file:"), d->symbolFileName, br, + Tr::tr("Override &start script:"), d->overrideStartScriptFileName, br, + Tr::tr("Override S&ysRoot:"), d->sysRootDirectory, br, + }, + st, + hr, + Row { + d->progressIndicator, d->progressLabel, d->buttonBox + } + }.attachTo(this); + // clang-format on } AttachCoreDialog::~AttachCoreDialog() @@ -275,28 +161,50 @@ AttachCoreDialog::~AttachCoreDialog() int AttachCoreDialog::exec() { - connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile); - connect(d->remoteCoreFileName, &PathChooser::textChanged, this, [this] { - coreFileChanged(d->remoteCoreFileName->rawFilePath()); - }); connect(d->symbolFileName, &PathChooser::textChanged, this, &AttachCoreDialog::changed); - connect(d->localCoreFileName, &PathChooser::textChanged, this, [this] { - coreFileChanged(d->localCoreFileName->rawFilePath()); + connect(d->coreFileName, &PathChooser::textChanged, this, [this] { + coreFileChanged(d->coreFileName->rawFilePath()); }); - connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed); connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(d->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(d->buttonBox, &QDialogButtonBox::accepted, this, &AttachCoreDialog::accepted); changed(); - AttachCoreDialogPrivate::State st = d->getDialogState(*this); + connect(&d->taskTree, &TaskTree::done, this, [&]() { + setEnabled(true); + d->progressIndicator->setVisible(false); + d->progressLabel->setVisible(false); + + if (!d->coreFileResult) { + QMessageBox::critical(this, + Tr::tr("Error"), + Tr::tr("Failed to copy core file to device: %1") + .arg(d->coreFileResult.error())); + return; + } + + if (!d->symbolFileResult) { + QMessageBox::critical(this, + Tr::tr("Error"), + Tr::tr("Failed to copy symbol file to device: %1") + .arg(d->coreFileResult.error())); + return; + } + + accept(); + }); + connect(&d->taskTree, &TaskTree::progressValueChanged, this, [this](int value) { + const QString text = Tr::tr("Copying files to device... %1/%2") + .arg(value) + .arg(d->taskTree.progressMaximum()); + d->progressLabel->setText(text); + }); + + AttachCoreDialogPrivate::State st = d->getDialogState(); if (!st.validKit) { d->kitChooser->setFocus(); } else if (!st.validCoreFilename) { - if (st.localCoreFile) - d->localCoreFileName->setFocus(); - else - d->remoteCoreFileName->setFocus(); + d->coreFileName->setFocus(); } else if (!st.validSymbolFilename) { d->symbolFileName->setFocus(); } @@ -304,18 +212,61 @@ int AttachCoreDialog::exec() return QDialog::exec(); } -bool AttachCoreDialog::isLocalKit() const +void AttachCoreDialog::accepted() { - Kit *k = d->kitChooser->currentKit(); - QTC_ASSERT(k, return false); - IDevice::ConstPtr device = DeviceKitAspect::device(k); - QTC_ASSERT(device, return false); - return device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; -} + const DebuggerItem *debuggerItem = Debugger::DebuggerKitAspect::debugger(kit()); + const FilePath debuggerCommand = debuggerItem->command(); -bool AttachCoreDialog::useLocalCoreFile() const -{ - return isLocalKit() || d->forceLocalCheckBox->isChecked(); + using namespace Tasking; + + const auto copyFile = [debuggerCommand](const FilePath &srcPath) -> expected_str { + if (!srcPath.isSameDevice(debuggerCommand)) { + const expected_str tmpPath = debuggerCommand.tmpDir(); + if (!tmpPath) + return make_unexpected(tmpPath.error()); + + const FilePath pattern = (tmpPath.value() + / (srcPath.fileName() + ".XXXXXXXXXXX")); + + const expected_str resultPath = pattern.createTempFile(); + if (!resultPath) + return make_unexpected(resultPath.error()); + const expected_str result = srcPath.copyFile(resultPath.value()); + if (!result) + return make_unexpected(result.error()); + + return resultPath; + } + + return srcPath; + }; + + using ResultType = expected_str; + + const auto copyFileAsync = [=](QFutureInterface &fi, const FilePath &srcPath) { + fi.reportResult(copyFile(srcPath)); + }; + + const Group root = { + parallel, + Async{[=](auto &task) { + task.setAsyncCallData(copyFileAsync, this->coreFile()); + }, + [=](const auto &task) { d->coreFileResult = task.result(); }}, + Async{[=](auto &task) { + task.setAsyncCallData(copyFileAsync, this->symbolFile()); + }, + [=](const auto &task) { d->symbolFileResult = task.result(); }}, + }; + + d->taskTree.setupRoot(root); + d->taskTree.start(); + + d->progressLabel->setText(Tr::tr("Copying files to device...")); + + setEnabled(false); + d->progressIndicator->setVisible(true); + d->progressLabel->setVisible(true); } void AttachCoreDialog::coreFileChanged(const FilePath &coreFile) @@ -335,40 +286,13 @@ void AttachCoreDialog::coreFileChanged(const FilePath &coreFile) void AttachCoreDialog::changed() { - AttachCoreDialogPrivate::State st = d->getDialogState(*this); - - d->forceLocalLabel->setVisible(!st.localKit); - d->forceLocalCheckBox->setVisible(!st.localKit); - if (st.localCoreFile) { - d->localCoreFileName->setVisible(true); - d->remoteCoreFileName->setVisible(false); - d->selectRemoteCoreButton->setVisible(false); - } else { - d->localCoreFileName->setVisible(false); - d->remoteCoreFileName->setVisible(true); - d->selectRemoteCoreButton->setVisible(true); - } - + AttachCoreDialogPrivate::State st = d->getDialogState(); d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(st.isValid()); } -void AttachCoreDialog::selectRemoteCoreFile() +FilePath AttachCoreDialog::coreFile() const { - changed(); - QTC_ASSERT(!isLocalKit(), return); - SelectRemoteFileDialog dlg(this); - dlg.setWindowTitle(Tr::tr("Select Remote Core File")); - dlg.attachToDevice(d->kitChooser->currentKit()); - if (dlg.exec() == QDialog::Rejected) - return; - d->localCoreFileName->setFilePath(dlg.localFile()); - d->remoteCoreFileName->setFilePath(dlg.remoteFile()); - changed(); -} - -FilePath AttachCoreDialog::localCoreFile() const -{ - return d->localCoreFileName->filePath(); + return d->coreFileName->filePath(); } FilePath AttachCoreDialog::symbolFile() const @@ -376,24 +300,24 @@ FilePath AttachCoreDialog::symbolFile() const return d->symbolFileName->filePath(); } +FilePath AttachCoreDialog::coreFileCopy() const +{ + return d->coreFileResult.value_or(d->symbolFileName->filePath()); +} + +FilePath AttachCoreDialog::symbolFileCopy() const +{ + return d->symbolFileResult.value_or(d->symbolFileName->filePath()); +} + void AttachCoreDialog::setSymbolFile(const FilePath &symbolFilePath) { d->symbolFileName->setFilePath(symbolFilePath); } -void AttachCoreDialog::setLocalCoreFile(const FilePath &coreFilePath) +void AttachCoreDialog::setCoreFile(const FilePath &coreFilePath) { - d->localCoreFileName->setFilePath(coreFilePath); -} - -void AttachCoreDialog::setRemoteCoreFile(const FilePath &coreFilePath) -{ - d->remoteCoreFileName->setFilePath(coreFilePath); -} - -FilePath AttachCoreDialog::remoteCoreFile() const -{ - return d->remoteCoreFileName->filePath(); + d->coreFileName->setFilePath(coreFilePath); } void AttachCoreDialog::setKitId(Id id) @@ -401,16 +325,6 @@ void AttachCoreDialog::setKitId(Id id) d->kitChooser->setCurrentKitId(id); } -void AttachCoreDialog::setForceLocalCoreFile(bool on) -{ - d->forceLocalCheckBox->setChecked(on); -} - -bool AttachCoreDialog::forcesLocalCoreFile() const -{ - return d->forceLocalCheckBox->isChecked(); -} - Kit *AttachCoreDialog::kit() const { return d->kitChooser->currentKit(); diff --git a/src/plugins/debugger/loadcoredialog.h b/src/plugins/debugger/loadcoredialog.h index 4c07cf6cfa6..ee1d065f92d 100644 --- a/src/plugins/debugger/loadcoredialog.h +++ b/src/plugins/debugger/loadcoredialog.h @@ -21,28 +21,26 @@ public: int exec() override; Utils::FilePath symbolFile() const; - Utils::FilePath localCoreFile() const; - Utils::FilePath remoteCoreFile() const; + Utils::FilePath coreFile() const; Utils::FilePath overrideStartScript() const; Utils::FilePath sysRoot() const; - bool useLocalCoreFile() const; - bool forcesLocalCoreFile() const; - bool isLocalKit() const; // For persistance. ProjectExplorer::Kit *kit() const; void setSymbolFile(const Utils::FilePath &symbolFilePath); - void setLocalCoreFile(const Utils::FilePath &coreFilePath); - void setRemoteCoreFile(const Utils::FilePath &coreFilePath); + void setCoreFile(const Utils::FilePath &coreFilePath); void setOverrideStartScript(const Utils::FilePath &scriptName); void setSysRoot(const Utils::FilePath &sysRoot); void setKitId(Utils::Id id); - void setForceLocalCoreFile(bool on); + + Utils::FilePath coreFileCopy() const; + Utils::FilePath symbolFileCopy() const; + + void accepted(); private: void changed(); void coreFileChanged(const Utils::FilePath &core); - void selectRemoteCoreFile(); class AttachCoreDialogPrivate *d; }; diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 0cb06abaee3..518d2842c8b 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -51,7 +51,6 @@ add_qtc_plugin(ProjectExplorer devicesupport/desktopprocesssignaloperation.cpp devicesupport/desktopprocesssignaloperation.h devicesupport/devicecheckbuildstep.cpp devicesupport/devicecheckbuildstep.h devicesupport/devicefactoryselectiondialog.cpp devicesupport/devicefactoryselectiondialog.h - devicesupport/devicefilesystemmodel.cpp devicesupport/devicefilesystemmodel.h devicesupport/devicemanager.cpp devicesupport/devicemanager.h devicesupport/devicemanagermodel.cpp devicesupport/devicemanagermodel.h devicesupport/deviceprocessesdialog.cpp devicesupport/deviceprocessesdialog.h diff --git a/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.cpp b/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.cpp deleted file mode 100644 index abf52223b14..00000000000 --- a/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.cpp +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "devicefilesystemmodel.h" - -#include "idevice.h" -#include "../projectexplorertr.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Utils; - -namespace ProjectExplorer { -namespace Internal { - -enum class FileType { - File, - Dir, -// Link, - Other -}; - - -class RemoteDirNode; -class RemoteFileNode -{ -public: - virtual ~RemoteFileNode() = default; - - FilePath m_filePath; - FileType m_fileType = FileType::File; - RemoteDirNode *m_parent = nullptr; -}; - -class RemoteDirNode : public RemoteFileNode -{ -public: - RemoteDirNode() { m_fileType = FileType::Dir; } - ~RemoteDirNode() { qDeleteAll(m_children); } - - enum { Initial, Fetching, Finished } m_state = Initial; - QList m_children; -}; - -static RemoteFileNode *indexToFileNode(const QModelIndex &index) -{ - return static_cast(index.internalPointer()); -} - -static RemoteDirNode *indexToDirNode(const QModelIndex &index) -{ - RemoteFileNode * const fileNode = indexToFileNode(index); - QTC_CHECK(fileNode); - return dynamic_cast(fileNode); -} - -using ResultType = QList>; - -class DeviceFileSystemModelPrivate -{ -public: - IDevice::ConstPtr m_device; - std::unique_ptr m_rootNode; - QSet *> m_watchers; - FutureSynchronizer m_futureSynchronizer; -}; - -} // namespace Internal - -using namespace Internal; - -DeviceFileSystemModel::DeviceFileSystemModel(QObject *parent) - : QAbstractItemModel(parent), d(new DeviceFileSystemModelPrivate) -{ - d->m_futureSynchronizer.setCancelOnWait(true); -} - -DeviceFileSystemModel::~DeviceFileSystemModel() -{ - qDeleteAll(d->m_watchers); - delete d; -} - -void DeviceFileSystemModel::setDevice(const IDevice::ConstPtr &device) -{ - d->m_device = device; -} - -bool DeviceFileSystemModel::canFetchMore(const QModelIndex &parent) const -{ - if (!parent.isValid()) { - return !d->m_rootNode.get(); - } - - RemoteDirNode * const dirNode = indexToDirNode(parent); - if (!dirNode) - return false; - if (dirNode->m_state == RemoteDirNode::Initial) - return true; - return false; -} - -void DeviceFileSystemModel::fetchMore(const QModelIndex &parent) -{ - if (!parent.isValid()) { - beginInsertRows(QModelIndex(), 0, 0); - QTC_CHECK(!d->m_rootNode); - d->m_rootNode.reset(new RemoteDirNode); - d->m_rootNode->m_filePath = d->m_device->rootPath(); - endInsertRows(); - return; - } - RemoteDirNode * const dirNode = indexToDirNode(parent); - if (!dirNode) - return; - if (dirNode->m_state != RemoteDirNode::Initial) - return; - collectEntries(dirNode->m_filePath, dirNode); - dirNode->m_state = RemoteDirNode::Fetching; -} - -bool DeviceFileSystemModel::hasChildren(const QModelIndex &parent) const -{ - if (!parent.isValid()) - return true; - - RemoteDirNode * const dirNode = indexToDirNode(parent); - if (!dirNode) - return false; - if (dirNode->m_state == RemoteDirNode::Initial) - return true; - return dirNode->m_children.size(); -} - -int DeviceFileSystemModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return 2; // type + name -} - -QVariant DeviceFileSystemModel::data(const QModelIndex &index, int role) const -{ - const RemoteFileNode * const node = indexToFileNode(index); - QTC_ASSERT(node, return QVariant()); - if (index.column() == 0 && role == Qt::DecorationRole) { - if (node->m_fileType == FileType::File) - return Utils::Icons::UNKNOWN_FILE.icon(); - if (node->m_fileType == FileType::Dir) - return Utils::Icons::DIR.icon(); - return Utils::Icons::HELP.icon(); // Shows a question mark. - } - if (index.column() == 1) { - if (role == Qt::DisplayRole) { - if (node->m_filePath == d->m_device->rootPath()) - return QString("/"); - return node->m_filePath.fileName(); - } - if (role == PathRole) - return node->m_filePath.toVariant(); - } - return QVariant(); -} - -Qt::ItemFlags DeviceFileSystemModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; -} - -QVariant DeviceFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation != Qt::Horizontal) - return QVariant(); - if (role != Qt::DisplayRole) - return QVariant(); - if (section == 0) - return Tr::tr("File Type"); - if (section == 1) - return Tr::tr("File Name"); - return QVariant(); -} - -QModelIndex DeviceFileSystemModel::index(int row, int column, const QModelIndex &parent) const -{ - if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) - return QModelIndex(); - if (!d->m_rootNode) - return QModelIndex(); - if (!parent.isValid()) - return createIndex(row, column, d->m_rootNode.get()); - const RemoteDirNode * const parentNode = indexToDirNode(parent); - QTC_ASSERT(parentNode, return QModelIndex()); - QTC_ASSERT(row < parentNode->m_children.count(), return QModelIndex()); - RemoteFileNode * const childNode = parentNode->m_children.at(row); - return createIndex(row, column, childNode); -} - -QModelIndex DeviceFileSystemModel::parent(const QModelIndex &child) const -{ - if (!child.isValid()) // Don't assert on this, since the model tester tries it. - return QModelIndex(); - - const RemoteFileNode * const childNode = indexToFileNode(child); - QTC_ASSERT(childNode, return QModelIndex()); - if (childNode == d->m_rootNode.get()) - return QModelIndex(); - RemoteDirNode * const parentNode = childNode->m_parent; - if (parentNode == d->m_rootNode.get()) - return createIndex(0, 0, d->m_rootNode.get()); - const RemoteDirNode * const grandParentNode = parentNode->m_parent; - QTC_ASSERT(grandParentNode, return QModelIndex()); - return createIndex(grandParentNode->m_children.indexOf(parentNode), 0, parentNode); -} - -static FileType fileType(const FilePath &path) -{ - if (path.isDir()) - return FileType::Dir; - if (path.isFile()) - return FileType::File; - return FileType::Other; -} - -static void dirEntries(QFutureInterface &futureInterface, const FilePath &dir) -{ - const FilePaths entries = dir.dirEntries(QDir::NoFilter); - ResultType result; - for (const FilePath &entry : entries) { - if (futureInterface.isCanceled()) - return; - result.push_back({entry, fileType(entry)}); - } - futureInterface.reportResult(result); -} - -int DeviceFileSystemModel::rowCount(const QModelIndex &parent) const -{ - if (!d->m_rootNode) - return 0; - if (!parent.isValid()) - return 1; - if (parent.column() != 0) - return 0; - RemoteDirNode * const dirNode = indexToDirNode(parent); - if (!dirNode) - return 0; - return dirNode->m_children.count(); -} - -void DeviceFileSystemModel::collectEntries(const FilePath &filePath, RemoteDirNode *parentNode) -{ - // Destructor of this will delete working watchers, as they are children of this. - QFutureWatcher *watcher = new QFutureWatcher(this); - auto future = runAsync(dirEntries, filePath); - d->m_futureSynchronizer.addFuture(future); - connect(watcher, &QFutureWatcher::finished, this, [this, watcher, parentNode] { - auto cleanup = qScopeGuard([watcher, this] { - d->m_watchers.remove(watcher); - watcher->deleteLater(); - }); - - QTC_ASSERT(parentNode->m_state == RemoteDirNode::Fetching, return); - parentNode->m_state = RemoteDirNode::Finished; - - const ResultType entries = watcher->result(); - if (entries.isEmpty()) - return; - - const int row = parentNode->m_parent - ? parentNode->m_parent->m_children.indexOf(parentNode) : 0; - const QModelIndex parentIndex = createIndex(row, 0, parentNode); - beginInsertRows(parentIndex, 0, entries.count() - 1); - - for (const QPair &entry : entries) { - RemoteFileNode *childNode = nullptr; - if (entry.second == FileType::Dir) - childNode = new RemoteDirNode; - else - childNode = new RemoteFileNode; - childNode->m_filePath = entry.first; - childNode->m_fileType = entry.second; - childNode->m_parent = parentNode; - parentNode->m_children.append(childNode); - } - endInsertRows(); - }); - d->m_watchers.insert(watcher); - watcher->setFuture(future); -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.h b/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.h deleted file mode 100644 index a972aa971f5..00000000000 --- a/src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (C) 2016 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "../projectexplorer_export.h" -#include "idevicefwd.h" - -#include - -namespace Utils { class FilePath; } - -namespace ProjectExplorer { - -namespace Internal { -class DeviceFileSystemModelPrivate; -class RemoteDirNode; -} - -// Very simple read-only model. Symbolic links are not followed. -class PROJECTEXPLORER_EXPORT DeviceFileSystemModel : public QAbstractItemModel -{ - Q_OBJECT -public: - explicit DeviceFileSystemModel(QObject *parent = nullptr); - ~DeviceFileSystemModel(); - - void setDevice(const IDeviceConstPtr &device); - - // Use this to get the full path of a file or directory. - static const int PathRole = Qt::UserRole; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - -private: - bool canFetchMore(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - void fetchMore(const QModelIndex &parent) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; - QModelIndex parent(const QModelIndex &child) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - - void collectEntries(const Utils::FilePath &filePath, Internal::RemoteDirNode *parentNode); - - Internal::DeviceFileSystemModelPrivate * const d; -}; - -} // namespace ProjectExplorer; diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 0afa0b399bb..1cba645f41f 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -211,7 +211,6 @@ Project { "desktopdevicefactory.cpp", "desktopdevicefactory.h", "devicecheckbuildstep.cpp", "devicecheckbuildstep.h", "devicefactoryselectiondialog.cpp", "devicefactoryselectiondialog.h", - "devicefilesystemmodel.cpp", "devicefilesystemmodel.h", "devicemanager.cpp", "devicemanager.h", "devicemanagermodel.cpp", "devicemanagermodel.h", "deviceprocessesdialog.cpp", "deviceprocessesdialog.h",