VariableInspectorWidget.cpp
265 lines
| 9.8 KiB
| text/x-c
|
CppLexer
r1420 | #include <DataSource/DataSourceController.h> | |||
Alexandre Leroux
|
r685 | #include <Variable/RenameVariableDialog.h> | ||
r1348 | #include <Variable/VariableController2.h> | |||
Alexandre Leroux
|
r110 | #include <Variable/VariableInspectorWidget.h> | ||
Alexandre Leroux
|
r290 | #include <Variable/VariableMenuHeaderWidget.h> | ||
r1348 | #include <Variable/VariableModel2.h> | |||
Alexandre Leroux
|
r110 | |||
#include <ui_VariableInspectorWidget.h> | ||||
r422 | #include <QMouseEvent> | |||
Alexandre Leroux
|
r152 | #include <QSortFilterProxyModel> | ||
r401 | #include <QStyledItemDelegate> | |||
Alexandre Leroux
|
r290 | #include <QWidgetAction> | ||
Alexandre Leroux
|
r152 | |||
r1075 | #include <DragAndDrop/DragDropGuiController.h> | |||
Alexandre Leroux
|
r152 | #include <SqpApplication.h> | ||
Alexandre Leroux
|
r251 | Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget") | ||
r401 | ||||
r1420 | class QProgressBarItemDelegate : public QStyledItemDelegate | |||
{ | ||||
r401 | ||||
public: | ||||
r1420 | QProgressBarItemDelegate(QObject* parent) : QStyledItemDelegate { parent } {} | |||
r401 | ||||
r1420 | void paint( | |||
QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const | ||||
r401 | { | |||
auto data = index.data(Qt::DisplayRole); | ||||
r402 | auto progressData = index.data(VariableRoles::ProgressRole); | |||
r1420 | if (data.isValid() && progressData.isValid()) | |||
{ | ||||
r401 | auto name = data.value<QString>(); | |||
auto progress = progressData.value<double>(); | ||||
r1420 | if (progress > 0) | |||
{ | ||||
r422 | auto cancelButtonWidth = 20; | |||
r1420 | auto progressBarOption = QStyleOptionProgressBar {}; | |||
r422 | auto progressRect = option.rect; | |||
progressRect.setWidth(progressRect.width() - cancelButtonWidth); | ||||
progressBarOption.rect = progressRect; | ||||
r401 | progressBarOption.minimum = 0; | |||
progressBarOption.maximum = 100; | ||||
progressBarOption.progress = progress; | ||||
progressBarOption.text | ||||
= QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%"); | ||||
progressBarOption.textVisible = true; | ||||
progressBarOption.textAlignment = Qt::AlignCenter; | ||||
r422 | ||||
r1420 | QApplication::style()->drawControl( | |||
QStyle::CE_ProgressBar, &progressBarOption, painter); | ||||
r422 | ||||
// Cancel button | ||||
auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | ||||
r1420 | option.rect.height()); | |||
auto buttonOption = QStyleOptionButton {}; | ||||
r422 | buttonOption.rect = buttonRect; | |||
buttonOption.text = "X"; | ||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter); | ||||
} | ||||
r1420 | else | |||
{ | ||||
r422 | QStyledItemDelegate::paint(painter, option, index); | |||
r401 | } | |||
} | ||||
r1420 | else | |||
{ | ||||
r401 | QStyledItemDelegate::paint(painter, option, index); | |||
} | ||||
} | ||||
r422 | ||||
r1420 | bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, | |||
const QModelIndex& index) | ||||
r422 | { | |||
r1420 | if (event->type() == QEvent::MouseButtonRelease) | |||
{ | ||||
r422 | auto data = index.data(Qt::DisplayRole); | |||
auto progressData = index.data(VariableRoles::ProgressRole); | ||||
r1420 | if (data.isValid() && progressData.isValid()) | |||
{ | ||||
r422 | auto cancelButtonWidth = 20; | |||
auto progressRect = option.rect; | ||||
progressRect.setWidth(progressRect.width() - cancelButtonWidth); | ||||
// Cancel button | ||||
auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | ||||
r1420 | option.rect.height()); | |||
r422 | ||||
r1420 | auto e = (QMouseEvent*)event; | |||
r447 | auto clickX = e->x(); | |||
auto clickY = e->y(); | ||||
r422 | ||||
r1420 | auto x = buttonRect.left(); // the X coordinate | |||
auto y = buttonRect.top(); // the Y coordinate | ||||
auto w = buttonRect.width(); // button width | ||||
r422 | auto h = buttonRect.height(); // button height | |||
r1420 | if (clickX > x && clickX < x + w) | |||
{ | ||||
if (clickY > y && clickY < y + h) | ||||
{ | ||||
// auto& variableModel = sqpApp->variableModel(); | ||||
// variableModel->abortProgress(index); | ||||
r422 | } | |||
r763 | return true; | |||
r422 | } | |||
r1420 | else | |||
{ | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
} | ||||
r1420 | else | |||
{ | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
} | ||||
r1420 | else | |||
{ | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
r763 | ||||
return QStyledItemDelegate::editorEvent(event, model, option, index); | ||||
r422 | } | |||
r401 | }; | |||
r1420 | VariableInspectorWidget::VariableInspectorWidget(QWidget* parent) | |||
: QWidget { parent } | ||||
, ui { new Ui::VariableInspectorWidget } | ||||
, m_ProgressBarItemDelegate { new QProgressBarItemDelegate { this } } | ||||
Alexandre Leroux
|
r110 | { | ||
ui->setupUi(this); | ||||
Alexandre Leroux
|
r152 | |||
// Sets model for table | ||||
r304 | // auto sortFilterModel = new QSortFilterProxyModel{this}; | |||
// sortFilterModel->setSourceModel(sqpApp->variableController().variableModel()); | ||||
Alexandre Leroux
|
r152 | |||
r1350 | m_model = new VariableModel2(); | |||
r1348 | ui->tableView->setModel(m_model); | |||
r1420 | connect(m_model, &VariableModel2::createVariable, [](const QVariantHash& productData) { | |||
r1350 | sqpApp->dataSourceController().requestVariable(productData); | |||
}); | ||||
auto vc = &(sqpApp->variableController()); | ||||
connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded); | ||||
connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted); | ||||
connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange); | ||||
Alexandre Leroux
|
r368 | |||
// Adds extra signal/slot between view and model, so the view can be updated instantly when | ||||
// there is a change of data in the model | ||||
r1420 | // connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, | |||
r1350 | // SLOT(refresh())); | |||
Alexandre Leroux
|
r368 | |||
r1420 | // ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel()); | |||
r401 | ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate); | |||
Alexandre Leroux
|
r245 | |||
Alexandre Leroux
|
r278 | // Fixes column sizes | ||
auto model = ui->tableView->model(); | ||||
const auto count = model->columnCount(); | ||||
r1420 | for (auto i = 0; i < count; ++i) | |||
{ | ||||
Alexandre Leroux
|
r278 | ui->tableView->setColumnWidth( | ||
i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width()); | ||||
} | ||||
Alexandre Leroux
|
r286 | // Sets selection options | ||
ui->tableView->setSelectionBehavior(QTableView::SelectRows); | ||||
ui->tableView->setSelectionMode(QTableView::ExtendedSelection); | ||||
Alexandre Leroux
|
r245 | // Connection to show a menu when right clicking on the tree | ||
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); | ||||
connect(ui->tableView, &QTableView::customContextMenuRequested, this, | ||||
r1420 | &VariableInspectorWidget::onTableMenuRequested); | |||
Alexandre Leroux
|
r110 | } | ||
VariableInspectorWidget::~VariableInspectorWidget() | ||||
{ | ||||
delete ui; | ||||
} | ||||
Alexandre Leroux
|
r245 | |||
r1420 | void VariableInspectorWidget::onTableMenuRequested(const QPoint& pos) noexcept | |||
Alexandre Leroux
|
r245 | { | ||
Alexandre Leroux
|
r287 | auto selectedRows = ui->tableView->selectionModel()->selectedRows(); | ||
r1420 | auto selectedVariables = QVector<std::shared_ptr<Variable2>> {}; | |||
for (const auto& selectedRow : qAsConst(selectedRows)) | ||||
{ | ||||
if (auto selectedVariable = this->m_model->variables()[selectedRow.row()]) | ||||
{ | ||||
Alexandre Leroux
|
r287 | selectedVariables.push_back(selectedVariable); | ||
Alexandre Leroux
|
r246 | } | ||
} | ||||
Alexandre Leroux
|
r287 | |||
r1420 | QMenu tableMenu {}; | |||
Alexandre Leroux
|
r287 | |||
// Emits a signal so that potential receivers can populate the menu before displaying it | ||||
emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables); | ||||
Alexandre Leroux
|
r291 | // Adds menu-specific actions | ||
r1420 | if (!selectedVariables.isEmpty()) | |||
{ | ||||
Alexandre Leroux
|
r683 | tableMenu.addSeparator(); | ||
Alexandre Leroux
|
r706 | // 'Rename' and 'Duplicate' actions (only if one variable selected) | ||
r1420 | if (selectedVariables.size() == 1) | |||
{ | ||||
Alexandre Leroux
|
r683 | auto selectedVariable = selectedVariables.front(); | ||
r1420 | auto duplicateFun = [varW = std::weak_ptr<Variable2>(selectedVariable)]() { | |||
if (auto var = varW.lock()) | ||||
{ | ||||
Alexandre Leroux
|
r770 | sqpApp->variableController().cloneVariable(var); | ||
} | ||||
Alexandre Leroux
|
r706 | }; | ||
tableMenu.addAction(tr("Duplicate"), duplicateFun); | ||||
r1420 | auto renameFun = [varW = std::weak_ptr<Variable2>(selectedVariable), this]() { | |||
if (auto var = varW.lock()) | ||||
{ | ||||
Alexandre Leroux
|
r770 | // Generates forbidden names (names associated to existing variables) | ||
r1348 | auto allVariables = sqpApp->variableController().variables(); | |||
Alexandre Leroux
|
r770 | auto forbiddenNames = QVector<QString>(allVariables.size()); | ||
std::transform(allVariables.cbegin(), allVariables.cend(), | ||||
r1420 | forbiddenNames.begin(), | |||
[](const auto& variable) { return variable->name(); }); | ||||
Alexandre Leroux
|
r770 | |||
r1420 | RenameVariableDialog dialog { var->name(), forbiddenNames, this }; | |||
if (dialog.exec() == QDialog::Accepted) | ||||
{ | ||||
Alexandre Leroux
|
r770 | var->setName(dialog.name()); | ||
} | ||||
Alexandre Leroux
|
r685 | } | ||
Alexandre Leroux
|
r683 | }; | ||
tableMenu.addAction(tr("Rename..."), renameFun); | ||||
} | ||||
Alexandre Leroux
|
r291 | // 'Delete' action | ||
Alexandre Leroux
|
r336 | auto deleteFun = [&selectedVariables]() { | ||
r1420 | for (const auto& var : selectedVariables) | |||
r1348 | sqpApp->variableController().deleteVariable(var); | |||
Alexandre Leroux
|
r291 | }; | ||
r1420 | tableMenu.addAction(QIcon { ":/icones/delete.png" }, tr("Delete"), deleteFun); | |||
Alexandre Leroux
|
r291 | } | ||
r1420 | if (!tableMenu.isEmpty()) | |||
{ | ||||
Alexandre Leroux
|
r290 | // Generates menu header (inserted before first action) | ||
auto firstAction = tableMenu.actions().first(); | ||||
r1420 | auto headerAction = new QWidgetAction { &tableMenu }; | |||
headerAction->setDefaultWidget( | ||||
new VariableMenuHeaderWidget { selectedVariables, &tableMenu }); | ||||
Alexandre Leroux
|
r290 | tableMenu.insertAction(firstAction, headerAction); | ||
Alexandre Leroux
|
r287 | // Displays menu | ||
Alexandre Leroux
|
r655 | tableMenu.exec(QCursor::pos()); | ||
Alexandre Leroux
|
r251 | } | ||
Alexandre Leroux
|
r245 | } | ||
Alexandre Leroux
|
r368 | |||
void VariableInspectorWidget::refresh() noexcept | ||||
{ | ||||
ui->tableView->viewport()->update(); | ||||
} | ||||