VariableInspectorWidget.cpp
240 lines
| 9.3 KiB
| text/x-c
|
CppLexer
Alexandre Leroux
|
r685 | #include <Variable/RenameVariableDialog.h> | ||
#include <Variable/Variable.h> | ||||
Alexandre Leroux
|
r152 | #include <Variable/VariableController.h> | ||
Alexandre Leroux
|
r110 | #include <Variable/VariableInspectorWidget.h> | ||
Alexandre Leroux
|
r290 | #include <Variable/VariableMenuHeaderWidget.h> | ||
Alexandre Leroux
|
r152 | #include <Variable/VariableModel.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 | |||
r884 | #include <DragAndDrop/DragDropHelper.h> | |||
Alexandre Leroux
|
r152 | #include <SqpApplication.h> | ||
Alexandre Leroux
|
r251 | Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget") | ||
r401 | ||||
class QProgressBarItemDelegate : public QStyledItemDelegate { | ||||
public: | ||||
r402 | QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {} | |||
r401 | ||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, | ||||
const QModelIndex &index) const | ||||
{ | ||||
auto data = index.data(Qt::DisplayRole); | ||||
r402 | auto progressData = index.data(VariableRoles::ProgressRole); | |||
r401 | if (data.isValid() && progressData.isValid()) { | |||
auto name = data.value<QString>(); | ||||
auto progress = progressData.value<double>(); | ||||
r422 | if (progress > 0) { | |||
auto cancelButtonWidth = 20; | ||||
r401 | 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 | ||||
r401 | QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, | |||
painter); | ||||
r422 | ||||
// Cancel button | ||||
auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | ||||
option.rect.height()); | ||||
auto buttonOption = QStyleOptionButton{}; | ||||
buttonOption.rect = buttonRect; | ||||
buttonOption.text = "X"; | ||||
QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter); | ||||
} | ||||
else { | ||||
QStyledItemDelegate::paint(painter, option, index); | ||||
r401 | } | |||
} | ||||
else { | ||||
QStyledItemDelegate::paint(painter, option, index); | ||||
} | ||||
} | ||||
r422 | ||||
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, | ||||
const QModelIndex &index) | ||||
{ | ||||
if (event->type() == QEvent::MouseButtonRelease) { | ||||
auto data = index.data(Qt::DisplayRole); | ||||
auto progressData = index.data(VariableRoles::ProgressRole); | ||||
if (data.isValid() && progressData.isValid()) { | ||||
auto cancelButtonWidth = 20; | ||||
auto progressRect = option.rect; | ||||
progressRect.setWidth(progressRect.width() - cancelButtonWidth); | ||||
// Cancel button | ||||
auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | ||||
option.rect.height()); | ||||
r447 | auto e = (QMouseEvent *)event; | |||
auto clickX = e->x(); | ||||
auto clickY = e->y(); | ||||
r422 | ||||
auto x = buttonRect.left(); // the X coordinate | ||||
auto y = buttonRect.top(); // the Y coordinate | ||||
auto w = buttonRect.width(); // button width | ||||
auto h = buttonRect.height(); // button height | ||||
if (clickX > x && clickX < x + w) { | ||||
if (clickY > y && clickY < y + h) { | ||||
auto variableModel = sqpApp->variableController().variableModel(); | ||||
variableModel->abortProgress(index); | ||||
} | ||||
r763 | return true; | |||
r422 | } | |||
else { | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
} | ||||
else { | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
} | ||||
else { | ||||
r763 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |||
r422 | } | |||
r763 | ||||
return QStyledItemDelegate::editorEvent(event, model, option, index); | ||||
r422 | } | |||
r401 | }; | |||
Alexandre Leroux
|
r110 | VariableInspectorWidget::VariableInspectorWidget(QWidget *parent) | ||
r401 | : QWidget{parent}, | |||
ui{new Ui::VariableInspectorWidget}, | ||||
r402 | 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 | |||
Alexandre Leroux
|
r368 | auto variableModel = sqpApp->variableController().variableModel(); | ||
ui->tableView->setModel(variableModel); | ||||
// 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 | ||||
connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, | ||||
SLOT(refresh())); | ||||
r304 | 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(); | ||||
for (auto i = 0; i < count; ++i) { | ||||
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, | ||||
&VariableInspectorWidget::onTableMenuRequested); | ||||
Alexandre Leroux
|
r110 | } | ||
VariableInspectorWidget::~VariableInspectorWidget() | ||||
{ | ||||
delete ui; | ||||
} | ||||
Alexandre Leroux
|
r245 | |||
void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept | ||||
{ | ||||
Alexandre Leroux
|
r287 | auto selectedRows = ui->tableView->selectionModel()->selectedRows(); | ||
// Gets the model to retrieve the underlying selected variables | ||||
auto model = sqpApp->variableController().variableModel(); | ||||
auto selectedVariables = QVector<std::shared_ptr<Variable> >{}; | ||||
for (const auto &selectedRow : qAsConst(selectedRows)) { | ||||
if (auto selectedVariable = model->variable(selectedRow.row())) { | ||||
selectedVariables.push_back(selectedVariable); | ||||
Alexandre Leroux
|
r246 | } | ||
} | ||||
Alexandre Leroux
|
r287 | |||
QMenu tableMenu{}; | ||||
// 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 | ||
if (!selectedVariables.isEmpty()) { | ||||
Alexandre Leroux
|
r683 | tableMenu.addSeparator(); | ||
Alexandre Leroux
|
r706 | // 'Rename' and 'Duplicate' actions (only if one variable selected) | ||
Alexandre Leroux
|
r683 | if (selectedVariables.size() == 1) { | ||
auto selectedVariable = selectedVariables.front(); | ||||
Alexandre Leroux
|
r770 | auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]() | ||
{ | ||||
if (auto var = varW.lock()) { | ||||
sqpApp->variableController().cloneVariable(var); | ||||
} | ||||
Alexandre Leroux
|
r706 | }; | ||
tableMenu.addAction(tr("Duplicate"), duplicateFun); | ||||
Alexandre Leroux
|
r770 | auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]() | ||
{ | ||||
if (auto var = varW.lock()) { | ||||
// Generates forbidden names (names associated to existing variables) | ||||
auto allVariables = model->variables(); | ||||
auto forbiddenNames = QVector<QString>(allVariables.size()); | ||||
std::transform(allVariables.cbegin(), allVariables.cend(), | ||||
forbiddenNames.begin(), | ||||
[](const auto &variable) { return variable->name(); }); | ||||
RenameVariableDialog dialog{var->name(), forbiddenNames, this}; | ||||
if (dialog.exec() == QDialog::Accepted) { | ||||
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]() { | ||
sqpApp->variableController().deleteVariables(selectedVariables); | ||||
Alexandre Leroux
|
r291 | }; | ||
tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun); | ||||
} | ||||
Alexandre Leroux
|
r287 | if (!tableMenu.isEmpty()) { | ||
Alexandre Leroux
|
r290 | // Generates menu header (inserted before first action) | ||
auto firstAction = tableMenu.actions().first(); | ||||
auto headerAction = new QWidgetAction{&tableMenu}; | ||||
headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu}); | ||||
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(); | ||||
} | ||||