From 96ebe93ecb529cc8d31cb743f6c3970fc55ae07b Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 2 Feb 2023 14:27:50 +0100 Subject: [PATCH] Debugger: Rebuild AttachCoreDialog The old dialog was based on local vs. remote file paths. These days we can simply treat them the same. If the selected files are not on the same device as the debuggger they will be copied first. Change-Id: If5ec93d1e1e49c51b3032fec8384682d2a5e35b4 Reviewed-by: hjk --- src/plugins/debugger/debuggerplugin.cpp | 17 +- src/plugins/debugger/loadcoredialog.cpp | 380 +++++++----------- src/plugins/debugger/loadcoredialog.h | 16 +- src/plugins/projectexplorer/CMakeLists.txt | 1 - .../devicesupport/devicefilesystemmodel.cpp | 300 -------------- .../devicesupport/devicefilesystemmodel.h | 50 --- .../projectexplorer/projectexplorer.qbs | 1 - 7 files changed, 160 insertions(+), 605 deletions(-) delete mode 100644 src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.cpp delete mode 100644 src/plugins/projectexplorer/devicesupport/devicefilesystemmodel.h 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",