forked from qt-creator/qt-creator
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 <hjk@qt.io>
This commit is contained in:
@@ -1521,31 +1521,26 @@ void DebuggerPluginPrivate::attachCore()
|
|||||||
if (!lastExternalKit.isEmpty())
|
if (!lastExternalKit.isEmpty())
|
||||||
dlg.setKitId(Id::fromString(lastExternalKit));
|
dlg.setKitId(Id::fromString(lastExternalKit));
|
||||||
dlg.setSymbolFile(FilePath::fromSettings(configValue("LastExternalExecutableFile")));
|
dlg.setSymbolFile(FilePath::fromSettings(configValue("LastExternalExecutableFile")));
|
||||||
dlg.setLocalCoreFile(FilePath::fromSettings(configValue("LastLocalCoreFile")));
|
dlg.setCoreFile(FilePath::fromSettings(configValue("LastLocalCoreFile")));
|
||||||
dlg.setRemoteCoreFile(FilePath::fromSettings(configValue("LastRemoteCoreFile")));
|
|
||||||
dlg.setOverrideStartScript(FilePath::fromSettings(configValue("LastExternalStartScript")));
|
dlg.setOverrideStartScript(FilePath::fromSettings(configValue("LastExternalStartScript")));
|
||||||
dlg.setSysRoot(FilePath::fromSettings(configValue("LastSysRoot")));
|
dlg.setSysRoot(FilePath::fromSettings(configValue("LastSysRoot")));
|
||||||
dlg.setForceLocalCoreFile(configValue("LastForceLocalCoreFile").toBool());
|
|
||||||
|
|
||||||
if (dlg.exec() != QDialog::Accepted)
|
if (dlg.exec() != QDialog::Accepted)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setConfigValue("LastExternalExecutableFile", dlg.symbolFile().toSettings());
|
setConfigValue("LastExternalExecutableFile", dlg.symbolFile().toSettings());
|
||||||
setConfigValue("LastLocalCoreFile", dlg.localCoreFile().toSettings());
|
setConfigValue("LastLocalCoreFile", dlg.coreFile().toSettings());
|
||||||
setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile().toSettings());
|
|
||||||
setConfigValue("LastExternalKit", dlg.kit()->id().toSetting());
|
setConfigValue("LastExternalKit", dlg.kit()->id().toSetting());
|
||||||
setConfigValue("LastExternalStartScript", dlg.overrideStartScript().toSettings());
|
setConfigValue("LastExternalStartScript", dlg.overrideStartScript().toSettings());
|
||||||
setConfigValue("LastSysRoot", dlg.sysRoot().toSettings());
|
setConfigValue("LastSysRoot", dlg.sysRoot().toSettings());
|
||||||
setConfigValue("LastForceLocalCoreFile", dlg.forcesLocalCoreFile());
|
|
||||||
|
|
||||||
auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
auto runControl = new RunControl(ProjectExplorer::Constants::DEBUG_RUN_MODE);
|
||||||
runControl->setKit(dlg.kit());
|
runControl->setKit(dlg.kit());
|
||||||
runControl->setDisplayName(Tr::tr("Core file \"%1\"")
|
runControl->setDisplayName(Tr::tr("Core file \"%1\"").arg(dlg.coreFile().toUserOutput()));
|
||||||
.arg(dlg.useLocalCoreFile() ? dlg.localCoreFile().toUserOutput()
|
|
||||||
: dlg.remoteCoreFile().toUserOutput()));
|
|
||||||
auto debugger = new DebuggerRunTool(runControl);
|
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->setStartMode(AttachToCore);
|
||||||
debugger->setCloseMode(DetachAtClose);
|
debugger->setCloseMode(DetachAtClose);
|
||||||
debugger->setOverrideStartScript(dlg.overrideStartScript());
|
debugger->setOverrideStartScript(dlg.overrideStartScript());
|
||||||
|
@@ -7,16 +7,17 @@
|
|||||||
#include "debuggertr.h"
|
#include "debuggertr.h"
|
||||||
#include "gdb/gdbengine.h"
|
#include "gdb/gdbengine.h"
|
||||||
|
|
||||||
#include <projectexplorer/devicesupport/devicefilesystemmodel.h>
|
|
||||||
#include <projectexplorer/devicesupport/filetransfer.h>
|
|
||||||
#include <projectexplorer/devicesupport/idevice.h>
|
#include <projectexplorer/devicesupport/idevice.h>
|
||||||
#include <projectexplorer/kitchooser.h>
|
#include <projectexplorer/kitchooser.h>
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
|
#include <utils/asynctask.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/processinterface.h>
|
#include <utils/processinterface.h>
|
||||||
|
#include <utils/progressindicator.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/tasktree.h>
|
||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QTextBrowser>
|
#include <QTextBrowser>
|
||||||
@@ -36,112 +38,6 @@ using namespace Utils;
|
|||||||
|
|
||||||
namespace Debugger::Internal {
|
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
|
// AttachCoreDialog
|
||||||
@@ -153,17 +49,20 @@ class AttachCoreDialogPrivate
|
|||||||
public:
|
public:
|
||||||
KitChooser *kitChooser;
|
KitChooser *kitChooser;
|
||||||
|
|
||||||
QCheckBox *forceLocalCheckBox;
|
|
||||||
QLabel *forceLocalLabel;
|
|
||||||
PathChooser *symbolFileName;
|
PathChooser *symbolFileName;
|
||||||
PathChooser *localCoreFileName;
|
PathChooser *coreFileName;
|
||||||
PathChooser *remoteCoreFileName;
|
|
||||||
QPushButton *selectRemoteCoreButton;
|
|
||||||
|
|
||||||
PathChooser *overrideStartScriptFileName;
|
PathChooser *overrideStartScriptFileName;
|
||||||
PathChooser *sysRootDirectory;
|
PathChooser *sysRootDirectory;
|
||||||
|
|
||||||
|
FilePath debuggerPath;
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox;
|
QDialogButtonBox *buttonBox;
|
||||||
|
ProgressIndicator *progressIndicator;
|
||||||
|
QLabel *progressLabel;
|
||||||
|
|
||||||
|
TaskTree taskTree;
|
||||||
|
expected_str<FilePath> coreFileResult;
|
||||||
|
expected_str<FilePath> symbolFileResult;
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
@@ -175,23 +74,14 @@ public:
|
|||||||
bool validKit;
|
bool validKit;
|
||||||
bool validSymbolFilename;
|
bool validSymbolFilename;
|
||||||
bool validCoreFilename;
|
bool validCoreFilename;
|
||||||
bool localCoreFile;
|
|
||||||
bool localKit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
State getDialogState(const AttachCoreDialog &p) const
|
State getDialogState() const
|
||||||
{
|
{
|
||||||
State st;
|
State st;
|
||||||
st.localCoreFile = p.useLocalCoreFile();
|
|
||||||
st.validKit = (kitChooser->currentKit() != nullptr);
|
st.validKit = (kitChooser->currentKit() != nullptr);
|
||||||
st.validSymbolFilename = symbolFileName->isValid();
|
st.validSymbolFilename = symbolFileName->isValid();
|
||||||
|
st.validCoreFilename = coreFileName->isValid();
|
||||||
if (st.localCoreFile)
|
|
||||||
st.validCoreFilename = localCoreFileName->isValid();
|
|
||||||
else
|
|
||||||
st.validCoreFilename = !p.remoteCoreFile().isEmpty();
|
|
||||||
|
|
||||||
st.localKit = p.isLocalKit();
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -210,23 +100,17 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
|
|||||||
d->kitChooser->setShowIcons(true);
|
d->kitChooser->setShowIcons(true);
|
||||||
d->kitChooser->populate();
|
d->kitChooser->populate();
|
||||||
|
|
||||||
d->forceLocalCheckBox = new QCheckBox(this);
|
d->coreFileName = new PathChooser(this);
|
||||||
d->forceLocalLabel = new QLabel(this);
|
d->coreFileName->setHistoryCompleter("Debugger.CoreFile.History");
|
||||||
d->forceLocalLabel->setText(Tr::tr("Use local core file:"));
|
d->coreFileName->setExpectedKind(PathChooser::File);
|
||||||
d->forceLocalLabel->setBuddy(d->forceLocalCheckBox);
|
d->coreFileName->setPromptDialogTitle(Tr::tr("Select Core File"));
|
||||||
|
d->coreFileName->setAllowPathFromDevice(true);
|
||||||
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->symbolFileName = new PathChooser(this);
|
d->symbolFileName = new PathChooser(this);
|
||||||
d->symbolFileName->setHistoryCompleter("LocalExecutable");
|
d->symbolFileName->setHistoryCompleter("Executable");
|
||||||
d->symbolFileName->setExpectedKind(PathChooser::File);
|
d->symbolFileName->setExpectedKind(PathChooser::File);
|
||||||
d->symbolFileName->setPromptDialogTitle(Tr::tr("Select Executable or Symbol File"));
|
d->symbolFileName->setPromptDialogTitle(Tr::tr("Select Executable or Symbol File"));
|
||||||
|
d->symbolFileName->setAllowPathFromDevice(true);
|
||||||
d->symbolFileName->setToolTip(
|
d->symbolFileName->setToolTip(
|
||||||
Tr::tr("Select a file containing debug information corresponding to the core file. "
|
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 "
|
"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(
|
d->sysRootDirectory->setToolTip(Tr::tr(
|
||||||
"This option can be used to override the kit's SysRoot setting"));
|
"This option can be used to override the kit's SysRoot setting"));
|
||||||
|
|
||||||
auto coreLayout = new QHBoxLayout;
|
d->progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Small, this);
|
||||||
coreLayout->addWidget(d->localCoreFileName);
|
d->progressIndicator->setVisible(false);
|
||||||
coreLayout->addWidget(d->remoteCoreFileName);
|
|
||||||
coreLayout->addWidget(d->selectRemoteCoreButton);
|
|
||||||
|
|
||||||
auto formLayout = new QFormLayout;
|
d->progressLabel = new QLabel();
|
||||||
formLayout->setContentsMargins(0, 0, 0, 0);
|
d->progressLabel->setVisible(false);
|
||||||
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);
|
|
||||||
|
|
||||||
auto vboxLayout = new QVBoxLayout(this);
|
// clang-format off
|
||||||
vboxLayout->addLayout(formLayout);
|
using namespace Layouting;
|
||||||
vboxLayout->addStretch();
|
|
||||||
vboxLayout->addWidget(Layouting::createHr());
|
Column {
|
||||||
vboxLayout->addWidget(d->buttonBox);
|
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()
|
AttachCoreDialog::~AttachCoreDialog()
|
||||||
@@ -275,28 +161,50 @@ AttachCoreDialog::~AttachCoreDialog()
|
|||||||
|
|
||||||
int AttachCoreDialog::exec()
|
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->symbolFileName, &PathChooser::textChanged, this, &AttachCoreDialog::changed);
|
||||||
connect(d->localCoreFileName, &PathChooser::textChanged, this, [this] {
|
connect(d->coreFileName, &PathChooser::textChanged, this, [this] {
|
||||||
coreFileChanged(d->localCoreFileName->rawFilePath());
|
coreFileChanged(d->coreFileName->rawFilePath());
|
||||||
});
|
});
|
||||||
connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed);
|
|
||||||
connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed);
|
connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed);
|
||||||
connect(d->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
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();
|
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) {
|
if (!st.validKit) {
|
||||||
d->kitChooser->setFocus();
|
d->kitChooser->setFocus();
|
||||||
} else if (!st.validCoreFilename) {
|
} else if (!st.validCoreFilename) {
|
||||||
if (st.localCoreFile)
|
d->coreFileName->setFocus();
|
||||||
d->localCoreFileName->setFocus();
|
|
||||||
else
|
|
||||||
d->remoteCoreFileName->setFocus();
|
|
||||||
} else if (!st.validSymbolFilename) {
|
} else if (!st.validSymbolFilename) {
|
||||||
d->symbolFileName->setFocus();
|
d->symbolFileName->setFocus();
|
||||||
}
|
}
|
||||||
@@ -304,18 +212,61 @@ int AttachCoreDialog::exec()
|
|||||||
return QDialog::exec();
|
return QDialog::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttachCoreDialog::isLocalKit() const
|
void AttachCoreDialog::accepted()
|
||||||
{
|
{
|
||||||
Kit *k = d->kitChooser->currentKit();
|
const DebuggerItem *debuggerItem = Debugger::DebuggerKitAspect::debugger(kit());
|
||||||
QTC_ASSERT(k, return false);
|
const FilePath debuggerCommand = debuggerItem->command();
|
||||||
IDevice::ConstPtr device = DeviceKitAspect::device(k);
|
|
||||||
QTC_ASSERT(device, return false);
|
using namespace Tasking;
|
||||||
return device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
|
|
||||||
|
const auto copyFile = [debuggerCommand](const FilePath &srcPath) -> expected_str<FilePath> {
|
||||||
|
if (!srcPath.isSameDevice(debuggerCommand)) {
|
||||||
|
const expected_str<FilePath> tmpPath = debuggerCommand.tmpDir();
|
||||||
|
if (!tmpPath)
|
||||||
|
return make_unexpected(tmpPath.error());
|
||||||
|
|
||||||
|
const FilePath pattern = (tmpPath.value()
|
||||||
|
/ (srcPath.fileName() + ".XXXXXXXXXXX"));
|
||||||
|
|
||||||
|
const expected_str<FilePath> resultPath = pattern.createTempFile();
|
||||||
|
if (!resultPath)
|
||||||
|
return make_unexpected(resultPath.error());
|
||||||
|
const expected_str<void> result = srcPath.copyFile(resultPath.value());
|
||||||
|
if (!result)
|
||||||
|
return make_unexpected(result.error());
|
||||||
|
|
||||||
|
return resultPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttachCoreDialog::useLocalCoreFile() const
|
return srcPath;
|
||||||
{
|
};
|
||||||
return isLocalKit() || d->forceLocalCheckBox->isChecked();
|
|
||||||
|
using ResultType = expected_str<FilePath>;
|
||||||
|
|
||||||
|
const auto copyFileAsync = [=](QFutureInterface<ResultType> &fi, const FilePath &srcPath) {
|
||||||
|
fi.reportResult(copyFile(srcPath));
|
||||||
|
};
|
||||||
|
|
||||||
|
const Group root = {
|
||||||
|
parallel,
|
||||||
|
Async<ResultType>{[=](auto &task) {
|
||||||
|
task.setAsyncCallData(copyFileAsync, this->coreFile());
|
||||||
|
},
|
||||||
|
[=](const auto &task) { d->coreFileResult = task.result(); }},
|
||||||
|
Async<ResultType>{[=](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)
|
void AttachCoreDialog::coreFileChanged(const FilePath &coreFile)
|
||||||
@@ -335,40 +286,13 @@ void AttachCoreDialog::coreFileChanged(const FilePath &coreFile)
|
|||||||
|
|
||||||
void AttachCoreDialog::changed()
|
void AttachCoreDialog::changed()
|
||||||
{
|
{
|
||||||
AttachCoreDialogPrivate::State st = d->getDialogState(*this);
|
AttachCoreDialogPrivate::State st = d->getDialogState();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(st.isValid());
|
d->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(st.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachCoreDialog::selectRemoteCoreFile()
|
FilePath AttachCoreDialog::coreFile() const
|
||||||
{
|
{
|
||||||
changed();
|
return d->coreFileName->filePath();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath AttachCoreDialog::symbolFile() const
|
FilePath AttachCoreDialog::symbolFile() const
|
||||||
@@ -376,24 +300,24 @@ FilePath AttachCoreDialog::symbolFile() const
|
|||||||
return d->symbolFileName->filePath();
|
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)
|
void AttachCoreDialog::setSymbolFile(const FilePath &symbolFilePath)
|
||||||
{
|
{
|
||||||
d->symbolFileName->setFilePath(symbolFilePath);
|
d->symbolFileName->setFilePath(symbolFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachCoreDialog::setLocalCoreFile(const FilePath &coreFilePath)
|
void AttachCoreDialog::setCoreFile(const FilePath &coreFilePath)
|
||||||
{
|
{
|
||||||
d->localCoreFileName->setFilePath(coreFilePath);
|
d->coreFileName->setFilePath(coreFilePath);
|
||||||
}
|
|
||||||
|
|
||||||
void AttachCoreDialog::setRemoteCoreFile(const FilePath &coreFilePath)
|
|
||||||
{
|
|
||||||
d->remoteCoreFileName->setFilePath(coreFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath AttachCoreDialog::remoteCoreFile() const
|
|
||||||
{
|
|
||||||
return d->remoteCoreFileName->filePath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttachCoreDialog::setKitId(Id id)
|
void AttachCoreDialog::setKitId(Id id)
|
||||||
@@ -401,16 +325,6 @@ void AttachCoreDialog::setKitId(Id id)
|
|||||||
d->kitChooser->setCurrentKitId(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
|
Kit *AttachCoreDialog::kit() const
|
||||||
{
|
{
|
||||||
return d->kitChooser->currentKit();
|
return d->kitChooser->currentKit();
|
||||||
|
@@ -21,28 +21,26 @@ public:
|
|||||||
int exec() override;
|
int exec() override;
|
||||||
|
|
||||||
Utils::FilePath symbolFile() const;
|
Utils::FilePath symbolFile() const;
|
||||||
Utils::FilePath localCoreFile() const;
|
Utils::FilePath coreFile() const;
|
||||||
Utils::FilePath remoteCoreFile() const;
|
|
||||||
Utils::FilePath overrideStartScript() const;
|
Utils::FilePath overrideStartScript() const;
|
||||||
Utils::FilePath sysRoot() const;
|
Utils::FilePath sysRoot() const;
|
||||||
bool useLocalCoreFile() const;
|
|
||||||
bool forcesLocalCoreFile() const;
|
|
||||||
bool isLocalKit() const;
|
|
||||||
|
|
||||||
// For persistance.
|
// For persistance.
|
||||||
ProjectExplorer::Kit *kit() const;
|
ProjectExplorer::Kit *kit() const;
|
||||||
void setSymbolFile(const Utils::FilePath &symbolFilePath);
|
void setSymbolFile(const Utils::FilePath &symbolFilePath);
|
||||||
void setLocalCoreFile(const Utils::FilePath &coreFilePath);
|
void setCoreFile(const Utils::FilePath &coreFilePath);
|
||||||
void setRemoteCoreFile(const Utils::FilePath &coreFilePath);
|
|
||||||
void setOverrideStartScript(const Utils::FilePath &scriptName);
|
void setOverrideStartScript(const Utils::FilePath &scriptName);
|
||||||
void setSysRoot(const Utils::FilePath &sysRoot);
|
void setSysRoot(const Utils::FilePath &sysRoot);
|
||||||
void setKitId(Utils::Id id);
|
void setKitId(Utils::Id id);
|
||||||
void setForceLocalCoreFile(bool on);
|
|
||||||
|
Utils::FilePath coreFileCopy() const;
|
||||||
|
Utils::FilePath symbolFileCopy() const;
|
||||||
|
|
||||||
|
void accepted();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void changed();
|
void changed();
|
||||||
void coreFileChanged(const Utils::FilePath &core);
|
void coreFileChanged(const Utils::FilePath &core);
|
||||||
void selectRemoteCoreFile();
|
|
||||||
|
|
||||||
class AttachCoreDialogPrivate *d;
|
class AttachCoreDialogPrivate *d;
|
||||||
};
|
};
|
||||||
|
@@ -51,7 +51,6 @@ add_qtc_plugin(ProjectExplorer
|
|||||||
devicesupport/desktopprocesssignaloperation.cpp devicesupport/desktopprocesssignaloperation.h
|
devicesupport/desktopprocesssignaloperation.cpp devicesupport/desktopprocesssignaloperation.h
|
||||||
devicesupport/devicecheckbuildstep.cpp devicesupport/devicecheckbuildstep.h
|
devicesupport/devicecheckbuildstep.cpp devicesupport/devicecheckbuildstep.h
|
||||||
devicesupport/devicefactoryselectiondialog.cpp devicesupport/devicefactoryselectiondialog.h
|
devicesupport/devicefactoryselectiondialog.cpp devicesupport/devicefactoryselectiondialog.h
|
||||||
devicesupport/devicefilesystemmodel.cpp devicesupport/devicefilesystemmodel.h
|
|
||||||
devicesupport/devicemanager.cpp devicesupport/devicemanager.h
|
devicesupport/devicemanager.cpp devicesupport/devicemanager.h
|
||||||
devicesupport/devicemanagermodel.cpp devicesupport/devicemanagermodel.h
|
devicesupport/devicemanagermodel.cpp devicesupport/devicemanagermodel.h
|
||||||
devicesupport/deviceprocessesdialog.cpp devicesupport/deviceprocessesdialog.h
|
devicesupport/deviceprocessesdialog.cpp devicesupport/deviceprocessesdialog.h
|
||||||
|
@@ -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 <utils/futuresynchronizer.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
#include <utils/runextensions.h>
|
|
||||||
#include <utils/utilsicons.h>
|
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
#include <QList>
|
|
||||||
#include <QScopeGuard>
|
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
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<RemoteFileNode *> m_children;
|
|
||||||
};
|
|
||||||
|
|
||||||
static RemoteFileNode *indexToFileNode(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
return static_cast<RemoteFileNode *>(index.internalPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
static RemoteDirNode *indexToDirNode(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
RemoteFileNode * const fileNode = indexToFileNode(index);
|
|
||||||
QTC_CHECK(fileNode);
|
|
||||||
return dynamic_cast<RemoteDirNode *>(fileNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
using ResultType = QList<QPair<FilePath, FileType>>;
|
|
||||||
|
|
||||||
class DeviceFileSystemModelPrivate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IDevice::ConstPtr m_device;
|
|
||||||
std::unique_ptr<RemoteDirNode> m_rootNode;
|
|
||||||
QSet<QFutureWatcher<ResultType> *> 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<ResultType> &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<ResultType> *watcher = new QFutureWatcher<ResultType>(this);
|
|
||||||
auto future = runAsync(dirEntries, filePath);
|
|
||||||
d->m_futureSynchronizer.addFuture(future);
|
|
||||||
connect(watcher, &QFutureWatcher<ResultType>::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<FilePath, FileType> &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
|
|
@@ -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 <QAbstractItemModel>
|
|
||||||
|
|
||||||
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;
|
|
@@ -211,7 +211,6 @@ Project {
|
|||||||
"desktopdevicefactory.cpp", "desktopdevicefactory.h",
|
"desktopdevicefactory.cpp", "desktopdevicefactory.h",
|
||||||
"devicecheckbuildstep.cpp", "devicecheckbuildstep.h",
|
"devicecheckbuildstep.cpp", "devicecheckbuildstep.h",
|
||||||
"devicefactoryselectiondialog.cpp", "devicefactoryselectiondialog.h",
|
"devicefactoryselectiondialog.cpp", "devicefactoryselectiondialog.h",
|
||||||
"devicefilesystemmodel.cpp", "devicefilesystemmodel.h",
|
|
||||||
"devicemanager.cpp", "devicemanager.h",
|
"devicemanager.cpp", "devicemanager.h",
|
||||||
"devicemanagermodel.cpp", "devicemanagermodel.h",
|
"devicemanagermodel.cpp", "devicemanagermodel.h",
|
||||||
"deviceprocessesdialog.cpp", "deviceprocessesdialog.h",
|
"deviceprocessesdialog.cpp", "deviceprocessesdialog.h",
|
||||||
|
Reference in New Issue
Block a user