summaryrefslogtreecommitdiff
path: root/src/plugins/baremetal/debugserverproviderssettingspage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/baremetal/debugserverproviderssettingspage.cpp')
-rw-r--r--src/plugins/baremetal/debugserverproviderssettingspage.cpp440
1 files changed, 440 insertions, 0 deletions
diff --git a/src/plugins/baremetal/debugserverproviderssettingspage.cpp b/src/plugins/baremetal/debugserverproviderssettingspage.cpp
new file mode 100644
index 0000000000..a1d2980f8c
--- /dev/null
+++ b/src/plugins/baremetal/debugserverproviderssettingspage.cpp
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "baremetalconstants.h"
+
+#include "debugserverprovidermanager.h"
+#include "debugserverproviderssettingspage.h"
+#include "idebugserverprovider.h"
+
+#include <coreplugin/icore.h>
+#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+
+#include <utils/algorithm.h>
+#include <utils/detailswidget.h>
+#include <utils/qtcassert.h>
+
+#include <QAction>
+#include <QApplication>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QItemSelectionModel>
+#include <QMenu>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSpacerItem>
+#include <QTextStream>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+using namespace Utils;
+
+namespace BareMetal {
+namespace Internal {
+
+// DebugServerProviderNode
+
+class DebugServerProviderNode final : public TreeItem
+{
+public:
+ explicit DebugServerProviderNode(IDebugServerProvider *provider, bool changed = false)
+ : provider(provider), changed(changed)
+ {
+ }
+
+ QVariant data(int column, int role) const final
+ {
+ if (role == Qt::FontRole) {
+ QFont f = QApplication::font();
+ if (changed)
+ f.setBold(true);
+ return f;
+ }
+
+ if (role == Qt::DisplayRole) {
+ return column == 0 ? provider->displayName() : provider->typeDisplayName();
+ }
+
+ // FIXME: Need to handle ToolTipRole role?
+ return {};
+ }
+
+ IDebugServerProvider *provider = nullptr;
+ IDebugServerProviderConfigWidget *widget = nullptr;
+ bool changed = false;
+};
+
+// DebugServerProviderModel
+
+DebugServerProviderModel::DebugServerProviderModel()
+{
+ setHeader({tr("Name"), tr("Type")});
+
+ const DebugServerProviderManager *manager = DebugServerProviderManager::instance();
+
+ connect(manager, &DebugServerProviderManager::providerAdded,
+ this, &DebugServerProviderModel::addProvider);
+ connect(manager, &DebugServerProviderManager::providerRemoved,
+ this, &DebugServerProviderModel::removeProvider);
+
+ for (IDebugServerProvider *p : DebugServerProviderManager::providers())
+ addProvider(p);
+}
+
+IDebugServerProvider *DebugServerProviderModel::provider(const QModelIndex &index) const
+{
+ if (const DebugServerProviderNode *node = nodeForIndex(index))
+ return node->provider;
+
+ return nullptr;
+}
+
+DebugServerProviderNode *DebugServerProviderModel::nodeForIndex(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return nullptr;
+
+ return static_cast<DebugServerProviderNode *>(itemForIndex(index));
+}
+
+void DebugServerProviderModel::apply()
+{
+ // Remove unused providers
+ for (IDebugServerProvider *provider : qAsConst(m_providersToRemove))
+ DebugServerProviderManager::deregisterProvider(provider);
+ QTC_ASSERT(m_providersToRemove.isEmpty(), m_providersToRemove.clear());
+
+ // Update providers
+ for (TreeItem *item : *rootItem()) {
+ const auto n = static_cast<DebugServerProviderNode *>(item);
+ if (!n->changed)
+ continue;
+
+ QTC_CHECK(n->provider);
+ if (n->widget)
+ n->widget->apply();
+
+ n->changed = false;
+ n->update();
+ }
+
+ // Add new (and already updated) providers
+ QStringList skippedProviders;
+ for (IDebugServerProvider *provider: qAsConst(m_providersToAdd)) {
+ if (!DebugServerProviderManager::registerProvider(provider))
+ skippedProviders << provider->displayName();
+ }
+
+ m_providersToAdd.clear();
+
+ if (!skippedProviders.isEmpty()) {
+ QMessageBox::warning(Core::ICore::dialogParent(),
+ tr("Duplicate Providers Detected"),
+ tr("The following providers were already configured:<br>"
+ "&nbsp;%1<br>"
+ "They were not configured again.")
+ .arg(skippedProviders.join(QLatin1String(",<br>&nbsp;"))));
+ }
+}
+
+DebugServerProviderNode *DebugServerProviderModel::findNode(const IDebugServerProvider *provider) const
+{
+ auto test = [provider](TreeItem *item) {
+ return static_cast<DebugServerProviderNode *>(item)->provider == provider;
+ };
+
+ return static_cast<DebugServerProviderNode *>(Utils::findOrDefault(*rootItem(), test));
+}
+
+QModelIndex DebugServerProviderModel::indexForProvider(IDebugServerProvider *provider) const
+{
+ const DebugServerProviderNode *n = findNode(provider);
+ return n ? indexForItem(n) : QModelIndex();
+}
+
+void DebugServerProviderModel::markForRemoval(IDebugServerProvider *provider)
+{
+ DebugServerProviderNode *n = findNode(provider);
+ QTC_ASSERT(n, return);
+ destroyItem(n);
+
+ if (m_providersToAdd.contains(provider)) {
+ m_providersToAdd.removeOne(provider);
+ delete provider;
+ } else {
+ m_providersToRemove.append(provider);
+ }
+}
+
+void DebugServerProviderModel::markForAddition(IDebugServerProvider *provider)
+{
+ DebugServerProviderNode *n = createNode(provider, true);
+ rootItem()->appendChild(n);
+ m_providersToAdd.append(provider);
+}
+
+DebugServerProviderNode *DebugServerProviderModel::createNode(
+ IDebugServerProvider *provider, bool changed)
+{
+ const auto node = new DebugServerProviderNode(provider, changed);
+ node->widget = provider->configurationWidget();
+ connect(node->widget, &IDebugServerProviderConfigWidget::dirty, this, [node] {
+ node->changed = true;
+ node->update();
+ });
+ return node;
+}
+
+void DebugServerProviderModel::addProvider(IDebugServerProvider *provider)
+{
+ if (findNode(provider))
+ m_providersToAdd.removeOne(provider);
+ else
+ rootItem()->appendChild(createNode(provider, false));
+
+ emit providerStateChanged();
+}
+
+void DebugServerProviderModel::removeProvider(IDebugServerProvider *provider)
+{
+ m_providersToRemove.removeAll(provider);
+ if (DebugServerProviderNode *n = findNode(provider))
+ destroyItem(n);
+
+ emit providerStateChanged();
+}
+
+// DebugServerProvidersSettingsWidget
+
+class DebugServerProvidersSettingsWidget final : public QWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(BareMetal::Internal::DebugServerProvidersSettingsPage)
+
+public:
+ explicit DebugServerProvidersSettingsWidget(DebugServerProvidersSettingsPage *page);
+
+ void providerSelectionChanged();
+ void removeProvider();
+ void updateState();
+
+ void createProvider(IDebugServerProviderFactory *f);
+ QModelIndex currentIndex() const;
+
+public:
+ DebugServerProvidersSettingsPage *m_page = nullptr;
+ DebugServerProviderModel m_model;
+ QItemSelectionModel *m_selectionModel = nullptr;
+ QTreeView *m_providerView = nullptr;
+ Utils::DetailsWidget *m_container = nullptr;
+ QPushButton *m_addButton = nullptr;
+ QPushButton *m_cloneButton = nullptr;
+ QPushButton *m_delButton = nullptr;
+};
+
+DebugServerProvidersSettingsWidget::DebugServerProvidersSettingsWidget
+ (DebugServerProvidersSettingsPage *page)
+ : m_page(page)
+{
+ m_providerView = new QTreeView(this);
+ m_providerView->setUniformRowHeights(true);
+ m_providerView->header()->setStretchLastSection(false);
+
+ m_addButton = new QPushButton(tr("Add"), this);
+ m_cloneButton = new QPushButton(tr("Clone"), this);
+ m_delButton = new QPushButton(tr("Remove"), this);
+
+ m_container = new Utils::DetailsWidget(this);
+ m_container->setState(Utils::DetailsWidget::NoSummary);
+ m_container->setMinimumWidth(500);
+ m_container->setVisible(false);
+
+ const auto buttonLayout = new QHBoxLayout;
+ buttonLayout->setSpacing(6);
+ buttonLayout->setContentsMargins(0, 0, 0, 0);
+ buttonLayout->addWidget(m_addButton);
+ buttonLayout->addWidget(m_cloneButton);
+ buttonLayout->addWidget(m_delButton);
+ const auto spacerItem = new QSpacerItem(40, 10, QSizePolicy::Expanding, QSizePolicy::Minimum);
+ buttonLayout->addItem(spacerItem);
+
+ const auto verticalLayout = new QVBoxLayout;
+ verticalLayout->addWidget(m_providerView);
+ verticalLayout->addLayout(buttonLayout);
+
+ const auto horizontalLayout = new QHBoxLayout;
+ horizontalLayout->addLayout(verticalLayout);
+ horizontalLayout->addWidget(m_container);
+
+ const auto groupBox = new QGroupBox(tr("Debug Server Providers"), this);
+ groupBox->setLayout(horizontalLayout);
+
+ const auto topLayout = new QVBoxLayout(this);
+ topLayout->addWidget(groupBox);
+
+ connect(&m_model, &DebugServerProviderModel::providerStateChanged,
+ this, &DebugServerProvidersSettingsWidget::updateState);
+
+ m_providerView->setModel(&m_model);
+
+ const auto headerView = m_providerView->header();
+ headerView->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ headerView->setSectionResizeMode(1, QHeaderView::Stretch);
+ m_providerView->expandAll();
+
+ m_selectionModel = m_providerView->selectionModel();
+
+ connect(m_selectionModel, &QItemSelectionModel::selectionChanged,
+ this, &DebugServerProvidersSettingsWidget::providerSelectionChanged);
+
+ connect(DebugServerProviderManager::instance(), &DebugServerProviderManager::providersChanged,
+ this, &DebugServerProvidersSettingsWidget::providerSelectionChanged);
+
+ // Set up add menu:
+ const auto addMenu = new QMenu(m_addButton);
+
+ for (const auto f : DebugServerProviderManager::factories()) {
+ const auto action = new QAction(addMenu);
+ action->setText(f->displayName());
+ connect(action, &QAction::triggered, this, [this, f] { createProvider(f); });
+ addMenu->addAction(action);
+ }
+
+ connect(m_cloneButton, &QAbstractButton::clicked, this, [this] { createProvider(nullptr); });
+
+ m_addButton->setMenu(addMenu);
+
+ connect(m_delButton, &QPushButton::clicked,
+ this, &DebugServerProvidersSettingsWidget::removeProvider);
+
+ updateState();
+}
+
+void DebugServerProvidersSettingsWidget::providerSelectionChanged()
+{
+ if (!m_container)
+ return;
+ const QModelIndex current = currentIndex();
+ QWidget *w = m_container->takeWidget(); // Prevent deletion.
+ if (w)
+ w->setVisible(false);
+
+ const DebugServerProviderNode *node = m_model.nodeForIndex(current);
+ w = node ? node->widget : nullptr;
+ m_container->setWidget(w);
+ m_container->setVisible(w != nullptr);
+ updateState();
+}
+
+void DebugServerProvidersSettingsWidget::createProvider(IDebugServerProviderFactory *f)
+{
+ IDebugServerProvider *provider = nullptr;
+ if (!f) {
+ const IDebugServerProvider *old = m_model.provider(currentIndex());
+ if (!old)
+ return;
+ provider = old->clone();
+ } else {
+ provider = f->create();
+ }
+
+ if (!provider)
+ return;
+
+ m_model.markForAddition(provider);
+
+ m_selectionModel->select(m_model.indexForProvider(provider),
+ QItemSelectionModel::Clear
+ | QItemSelectionModel::SelectCurrent
+ | QItemSelectionModel::Rows);
+}
+
+void DebugServerProvidersSettingsWidget::removeProvider()
+{
+ if (IDebugServerProvider *p = m_model.provider(currentIndex()))
+ m_model.markForRemoval(p);
+}
+
+void DebugServerProvidersSettingsWidget::updateState()
+{
+ if (!m_cloneButton)
+ return;
+
+ bool canCopy = false;
+ bool canDelete = false;
+ if (const IDebugServerProvider *p = m_model.provider(currentIndex())) {
+ canCopy = p->isValid();
+ canDelete = true;
+ }
+
+ m_cloneButton->setEnabled(canCopy);
+ m_delButton->setEnabled(canDelete);
+}
+
+QModelIndex DebugServerProvidersSettingsWidget::currentIndex() const
+{
+ if (!m_selectionModel)
+ return {};
+
+ const QModelIndexList rows = m_selectionModel->selectedRows();
+ if (rows.count() != 1)
+ return {};
+ return rows.at(0);
+}
+
+
+DebugServerProvidersSettingsPage::DebugServerProvidersSettingsPage()
+{
+ setId(Constants::GDB_PROVIDERS_SETTINGS_ID);
+ setDisplayName(tr("Bare Metal"));
+ setCategory(ProjectExplorer::Constants::DEVICE_SETTINGS_CATEGORY);
+}
+
+QWidget *DebugServerProvidersSettingsPage::widget()
+{
+ if (!m_configWidget)
+ m_configWidget = new DebugServerProvidersSettingsWidget(this);
+ return m_configWidget;
+}
+
+void DebugServerProvidersSettingsPage::apply()
+{
+ if (m_configWidget)
+ m_configWidget->m_model.apply();
+}
+
+void DebugServerProvidersSettingsPage::finish()
+{
+ if (m_configWidget)
+ disconnect(DebugServerProviderManager::instance(), &DebugServerProviderManager::providersChanged,
+ m_configWidget, &DebugServerProvidersSettingsWidget::providerSelectionChanged);
+
+ delete m_configWidget;
+ m_configWidget = nullptr;
+}
+
+} // namespace Internal
+} // namespace BareMetal